This is a REST engine API that I use for some of my projects. It is very simple to use and has no dependencies. One of the nicest feature is that it documents the REST interface that you build with the engine. Note that this is only a REST engine and does not include a web server. You still need to listen on a socket for incomming requests and feed them to the engine and respond with the engine's output.
Defining your API and documenting it
Let's say you have an application that has a ShoppingCart object and you want to expose some of its functionality through a REST interface. Defining the API is easy as this:
ShoppingCart *p = new ShoppingCart();
RESTEngine engine;
RESTCallBack *pc1 = new RESTCallBack(p,&ShoppingCart::addToCart,"This lets you add an item to a shopping cart");
pc1->addParam("id","Shopping cart ID");
pc1->addParam("sku","Item SKU");
pc1->addParam("qty","Quantity of that item to add");
RESTCallBack *pc2 = new RESTCallBack(p,&ShoppingCart::removeFromCart,"This lets you remove an item from a shopping cart");
pc2->addParam("id","Shopping cart ID");
pc2->addParam("sku","Item SKU");
engine.addCallBack("/shoppingcart/item","POST",pc1);
engine.addCallBack("/shoppingcart/item","DELETE",pc2);
Note how each resource uri and parameters are documented at creation time.
Invoking and processing query
To invoke a query, you only need to get the URI (after parsing it from a from a HTTP request or whatever other way) and feed it to the engine. Of course, your API might want to return some data, so this is done by passing an empty JSON document object (JSON interface is part of the project as well. I told you, there are no external dependencies in this project :) ) and the callbacks will populate it with the response.
Dumais::JSON::JSON j1,j2,j3;
engine.invoke(j1,"/shoppingcart/item?id=1&sku=242&qty=4","POST",bodyData);
engine.invoke(j2,"/shoppingcart/item?id=1&sku=244&qty=1","POST",bodyData);
engine.invoke(j3,"/shoppingcart/item?id=1&sku=244","DELETE",bodyData);
The engine will parse the parameters and route the requests to the proper callcacks. Callbacks are defined like this:
void ShoppingCart::addToCart(Dumais::JSON::JSON& j,RESTParameters* p, const std::string& data)
{
std::string id = p->getParam("id");
std::string sku = p->getParam("sku");
std::string qty = p->getParam("qty");
std::string test = p->getParam("test"); // this would return "" since param "test" was not defined as a valid param earlier.
j.addValue("Item successfully added to cart","message");
}
Generate documentation
When creating the callbacks and the parameters, we defined a description for each of them. This means that the engine is aware of the documentation of the created interface. This allows you to generate the documentation using RESTEngine::documentInterface(). This method will populate a JSON object with the documentation of your API. Generating the documentation for our example here would give us:
{
"api" : [
{
"description" : "This lets you add an item to a shopping cart",
"path" : "/shoppingcart/item",
"method" : "POST",
"params" : [
{
"name" : "id",
"description" : "Shopping cart ID"
},
{
"name" : "sku",
"description" : "Item SKU"
},
{
"name" : "qty",
"description" : "Quantity of that item to add"
}
]
},
{
"description" : "This lets you remove an item from a shopping cart",
"path" : "/shoppingcart/item",
"method" : "DELETE",
"params" : [
{
"name" : "id",
"description" : "Shopping cart ID"
},
{
"name" : "sku",
"description" : "Item SKU"
}
]
}
]
}
With the documentation generated as a JSON document, it is easy to make a javascript application that gets the list of API calls and lets you experiment with it for prototyping. I did an application that gets the list of API and for each API calls, shows the parameters that are defined and lets you enter a value in a text field. Then you can invoke the API call.
Thanks to William Tambellini for notifying me about a typo in this page