Constructs a new collection instance that is tied to a particular parent collection entry.
Accesses a single collection entry.
Model two nested collections using path based indexes
1 // 2 // API definition 3 // 4 interface SubItemAPI { 5 // Define the index path that leads to a sub item 6 struct CollectionIndices { 7 // The ID of the base item. This must match the definition in 8 // ItemAPI.CollectionIndices 9 string _item; 10 // The index if the sub item 11 int _index; 12 } 13 14 // GET /items/:item/subItems/length 15 @property int length(string _item); 16 17 // GET /items/:item/subItems/:index/squared_position 18 int getSquaredPosition(string _item, int _index); 19 } 20 21 interface ItemAPI { 22 // Define the index that identifies an item 23 struct CollectionIndices { 24 string _item; 25 } 26 27 // base path /items/:item/subItems 28 Collection!SubItemAPI subItems(string _item); 29 30 // GET /items/:item/name 31 @property string name(string _item); 32 } 33 34 interface API { 35 // a collection of items at the base path /items/ 36 Collection!ItemAPI items(); 37 } 38 39 // 40 // Local API implementation 41 // 42 class SubItemAPIImpl : SubItemAPI { 43 @property int length(string _item) { return 10; } 44 45 int getSquaredPosition(string _item, int _index) { return _index ^^ 2; } 46 } 47 48 class ItemAPIImpl : ItemAPI { 49 private SubItemAPIImpl m_subItems; 50 51 this() { m_subItems = new SubItemAPIImpl; } 52 53 Collection!SubItemAPI subItems(string _item) { return Collection!SubItemAPI(m_subItems, _item); } 54 55 string name(string _item) { return _item; } 56 } 57 58 class APIImpl : API { 59 private ItemAPIImpl m_items; 60 61 this() { m_items = new ItemAPIImpl; } 62 63 Collection!ItemAPI items() { return Collection!ItemAPI(m_items); } 64 } 65 66 // 67 // Resulting API usage 68 // 69 API api = new APIImpl; // A RestInterfaceClient!API would work just as well 70 71 // GET /items/foo/name 72 assert(api.items["foo"].name == "foo"); 73 // GET /items/foo/sub_items/length 74 assert(api.items["foo"].subItems.length == 10); 75 // GET /items/foo/sub_items/2/squared_position 76 assert(api.items["foo"].subItems[2].getSquaredPosition() == 4);
Model two nested collections using normal query parameters as indexes
1 // 2 // API definition 3 // 4 interface SubItemAPI { 5 // Define the index path that leads to a sub item 6 struct CollectionIndices { 7 // The ID of the base item. This must match the definition in 8 // ItemAPI.CollectionIndices 9 string item; 10 // The index if the sub item 11 int index; 12 } 13 14 // GET /items/subItems/length?item=... 15 @property int length(string item); 16 17 // GET /items/subItems/squared_position?item=...&index=... 18 int getSquaredPosition(string item, int index); 19 } 20 21 interface ItemAPI { 22 // Define the index that identifies an item 23 struct CollectionIndices { 24 string item; 25 } 26 27 // base path /items/subItems?item=... 28 Collection!SubItemAPI subItems(string item); 29 30 // GET /items/name?item=... 31 @property string name(string item); 32 } 33 34 interface API { 35 // a collection of items at the base path /items/ 36 Collection!ItemAPI items(); 37 } 38 39 // 40 // Local API implementation 41 // 42 class SubItemAPIImpl : SubItemAPI { 43 @property int length(string item) { return 10; } 44 45 int getSquaredPosition(string item, int index) { return index ^^ 2; } 46 } 47 48 class ItemAPIImpl : ItemAPI { 49 private SubItemAPIImpl m_subItems; 50 51 this() { m_subItems = new SubItemAPIImpl; } 52 53 Collection!SubItemAPI subItems(string item) { return Collection!SubItemAPI(m_subItems, item); } 54 55 string name(string item) { return item; } 56 } 57 58 class APIImpl : API { 59 private ItemAPIImpl m_items; 60 61 this() { m_items = new ItemAPIImpl; } 62 63 Collection!ItemAPI items() { return Collection!ItemAPI(m_items); } 64 } 65 66 // 67 // Resulting API usage 68 // 69 API api = new APIImpl; // A RestInterfaceClient!API would work just as well 70 71 // GET /items/name?item=foo 72 assert(api.items["foo"].name == "foo"); 73 // GET /items/subitems/length?item=foo 74 assert(api.items["foo"].subItems.length == 10); 75 // GET /items/subitems/squared_position?item=foo&index=2 76 assert(api.items["foo"].subItems[2].getSquaredPosition() == 4);
Models REST collection interfaces using natural D syntax.
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].method()), wheres all other methods will be considered methods of the collection itself (collection.method()).
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".