Collection

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".

Constructors

this
this(I api, ParentIDs pids)

Constructs a new collection instance that is tied to a particular parent collection entry.

Members

Aliases

AllIDNames
alias AllIDNames = FieldNameTuple!(I.CollectionIndices)
Undocumented in source.
AllIDs
alias AllIDs = TypeTuple!(typeof(I.CollectionIndices.tupleof))
Undocumented in source.
Interface
alias Interface = I
Undocumented in source.
ItemID
alias ItemID = AllIDs[$ - 1]
Undocumented in source.
ParentIDNames
alias ParentIDNames = AllIDNames[0..$ - 1]
Undocumented in source.
ParentIDs
alias ParentIDs = AllIDs[0..$ - 1]
Undocumented in source.

Functions

opIndex
Item opIndex(ItemID id)

Accesses a single collection entry.

Structs

Item
struct Item
Undocumented in source.

Examples

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 assert(api.items["foo"].name == "foo");
71 assert(api.items["foo"].subItems.length == 10);
72 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 assert(api.items["foo"].name == "foo");
71 assert(api.items["foo"].subItems.length == 10);
72 assert(api.items["foo"].subItems[2].getSquaredPosition() == 4);

Meta