vibe.d beta banner
get vibe.d

Asynchronous I/O that doesn’t get in your way, written in D

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


this (api, pids) Constructs a new collection instance that is tied to a particular parent collection entry.


m_interface I
m_parentIDs Collection.ParentIDs


opIndex (id) Accesses a single collection entry.

Inner structs





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);


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);

Sönke Ludwig, Михаил Страшун, Mathias 'Geod24' Lang


© 2012-2018 RejectedSoftware e.K.


Subject to the terms of the MIT license, as written in the included LICENSE.txt file.