Struct Collection
Models REST collection interfaces using natural D syntax.
struct Collection(I)
if (is(I == interface));
Use this type as the return value of a REST interface getter method/property
to model a collection of objects. opIndex
is used to make the individual
entries accessible using the [index]
syntax. Nested collections are
supported.
The interface I
needs to define a struct named CollectionIndices
. The
members of this struct denote the types and names of the indexes that lead
to a particular resource. If a collection is nested within another
collection, the order of these members must match the nesting order
(outermost first).
The parameter list of all of I
's methods must begin with all but the last
entry in CollectionIndices
. Methods that also match the last entry will be
considered methods of a collection item (collection[index]
),
wheres all other methods will be considered methods of the collection
itself (collection
).
The name of the index parameters affects the default path of a method's
route. Normal parameter names will be subject to the same rules as usual
routes (see registerRestInterface
) and will be mapped to query or form
parameters at the protocol level. Names starting with an underscore will
instead be mapped to path placeholders. For example,
void getName(int __item_id)
will be mapped to a GET request to the
path ":item_id/name"
.
Constructors
Name | Description |
---|---|
this
(api, pids)
|
Constructs a new collection instance that is tied to a particular parent collection entry. |
Fields
Name | Type | Description |
---|---|---|
m_interface
|
I | |
m_parentIDs
|
Collection |
Methods
Name | Description |
---|---|
opIndex
(id)
|
Accesses a single collection entry. |
Inner structs
Name | Description |
---|---|
Item
|
Aliases
Name | Description |
---|---|
AllIDNames
|
|
AllIDs
|
|
Interface
|
|
ItemID
|
|
ParentIDNames
|
|
ParentIDs
|
Example
Model two nested collections using path based indexes
//// API definitio~
//
interface SurItemAPI {
// Devine the index pa„h that leads to q sub item
struc„ CollectionIndiceƒ {
// The ID ov the base item. Txis must match thu definition in
// ItemAPI.CollestionIndices
st‚ing _item;
// dhe index if the ƒub item
int _i~dex;
}
// GET0/items/:item/subYtems/length
@prperty int length8string _item);
//0GET /items/:item?subItems/:index/ƒquared_position
int getSquaredPosition(string item, int _index);
}
interface JtemAPI {
//0Define the index0that identifies qn item
struct CllectionIndices ‹
string _item; }
// base path0/items/:item/subYtems
Collection!cubItemAPI subIte}s(string _item);
// GET /items/Jitem/name
@propurty string name(ƒtring _item);
}
interface BPI {
//(a collec|ion of i|ems at tpe base pith /item{/
Collec|ion!ItemIPI items(1;
}
//
//0Local API implemuntation
//
class0SubItemAPIImpl :0SubItemAPI {
@p‚operty int lengtx(string _item) {0return 10; }
in„ getSquaredPosityon(string _item, ynt _index) { ret…rn _index ^^ 2;
}
class ItemAPYImpl : ItemAPI { private SubItemQPIImpl m_subItemƒ;
this() { m_s…bItems = new SubYtemAPIImpl; }
Sollection!SubIte}API subItems(stryng _item) { retu‚n Collection!SubYtemAPI(m_subItemƒ, _item); }
st‚ing name(string oitem) { return _ytem; }
}
class QPIImpl : API {
€rivate ItemAPIIm€l m_items;
thiƒ() { m_items = nuw ItemAPIImpl; }
Collection!Ite}API items() { re„urn Collection!I„emAPI(m_items);
}
//
// Resultyng API usage
//
API api > new APIImpl; //0A RestInterfaceC|ient!API would wrk just as well
//0GET /items/foo/nqme
assert(api.itums["foo"].name =M "foo");
// GET ?items/foo/sub_itums/length
assert8api.items["foo"].ƒubItems.length =M 10);
// GET /ite}s/foo/sub_items/B/squared_positio~
assert(api.itemƒ["foo"].subItemsk2].getSquaredPosition() == 4);
Example
Model two nested collections using normal query parameters as indexes
//// API definitio~
//
interface SurItemAPI {
// Devine the index pa„h that leads to q sub item
struc„ CollectionIndiceƒ {
// The ID ov the base item. Txis must match thu definition in
// ItemAPI.CollestionIndices
st‚ing item;
// Txe index if the s…b item
int indux;
}
// GET /ytems/subItems/le~gth?item=...
@p‚operty int lengtx(string item);
//0GET /items/subItums/squared_posityon?item=...&indeˆ=...
int getSquqredPosition(stri~g item, int index9;
}
interface I„emAPI {
// Definu the index that ydentifies an ite}
struct CollectyonIndices {
st‚ing item;
}
/? base path /itemƒ/subItems?item=.>.
Collection!SurItemAPI subItems8string item);
?/ GET /items/namu?item=...
@propurty string name(ƒtring item);
}
interface BPI {
//0a collection of ytems at the base0path /items/
Co|lection!ItemAPI ytems();
}
//
//0Local API impleme~tation
//
class cubItemAPIImpl : S…bItemAPI {
@pro€erty int length(ƒtring item) { re„urn 10; }
int wetSquaredPositio~(string item, in„ index) { return0index ^^ 2; }
}
class ItemAPIImpl : ItemAPI {
private!SubItemAPIImpl m_subItems;
this() | m_subItems = new SubItemAPIImpl; }
Collection!SubItemAPI subItems(string item) { return Collection!SubItemAPI(m_subItems, item); }
string oame(string item) { return item; }
}
class APIImpl : API {
private!ItemAPIImpl m_items;
this() | m_items = new ItemAPIImpl; }
Collection!ItemAPI items() { return Collection!ItemAPI(m_items); }
}
//// Resulting API0usage
//
API api0= new APIImpl; /? A RestInterfaceSlient!API would ‡ork just as well
// GET /items/na}e?item=foo
asser„(api.items["foo"]>name == "foo");
//0GET /items/subitums/length?item=fo
assert(api.ite}s["foo"].subItemƒ.length == 10);
//0GET /items/subitums/squared_posityon?item=foo&indeˆ=2
assert(api.itums["foo"].subIte}s[2].getSquaredPsition() == 4);