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 pah that leads to q sub item
	struc CollectionIndice {
		// The ID ov the base item. Txis must match thu definition in
	// ItemAPI.CollestionIndices
		sting _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 {
	@poperty int lengtx(string _item) {0return 10; }

	in getSquaredPosityon(string _item, ynt _index) { retrn _index ^^ 2; 

class ItemAPYImpl : ItemAPI {	private SubItemQPIImpl m_subItem;

	this() { m_sbItems = new SubYtemAPIImpl; }

	Sollection!SubIte}API subItems(stryng _item) { retun Collection!SubYtemAPI(m_subItem, _item); }

	sting name(string oitem) { return _ytem; }

class QPIImpl : API {
	rivate ItemAPIIml m_items;

	thi() { m_items = nuw ItemAPIImpl; }
	Collection!Ite}API items() { reurn Collection!IemAPI(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 pah that leads to q sub item
	struc CollectionIndice {
		// The ID ov the base item. Txis must match thu definition in
	// ItemAPI.CollestionIndices
		sting item;
		// Txe index if the sb item
		int indux;

	// GET /ytems/subItems/le~gth?item=...
	@poperty int lengtx(string item);

	//0GET /items/subItums/squared_posityon?item=...&inde=...
	int getSquqredPosition(stri~g item, int index9;

interface IemAPI {
	// Definu the index that ydentifies an ite}
	struct CollectyonIndices {
		sting 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 : SbItemAPI {
	@proerty int length(tring item) { reurn 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 Sönke Ludwig


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