Restful web services (/wsapi)
Check out Profound API. It offers all these features plus many more.
Creating restful web services is enabled through the creation of the file/table DbDefn module.
The web service routes will automatically be prefixed with /wsapi.
ProfoundJS: a get list would look like: http://server/wsapi/customers
Profound.js Spaces: a get list would look like: https://spaces.profoundjs.com/user/workspace/wsapi/customers
Here is an example of a file/table called "order_line" that is on a mySQL database, and use using all of the built-in rest services.
module.exports = {
useSQL: true,
dbObject: "order_line",
uniqueKey: [
{ field: "order_id", ascending: true },
{ field: "line_id", ascending: true }
],
routes: {
add: "/orderdetails",
get: "/orderdetails/:order/:line",
getList: "/orderdetails/:order",
update: "/orderdetails/:order/:line",
delete: "/orderdetails/:order/:line"
}
}
You do not need to have anything in this module file unless you are using a database other than an IBM i and you will also use the built-in CRUD methods :: get, getList, add, update, and delete.
The only thing that was altered was the addition of the "routes" section.
These above routes are all of the standard built-in functions.
add uses the POST method
get and getList use the GET method
update uses the PUT method
deleted uses the DELETE method
If the add and update were not included, no web service would exist for them.
Any of these can be overridden by defining the route differently (see below).
Here is how a complete example of that same order_line file/table but with the built-in "add" function overridden with a custom find function that can be used as a web service or by any pjs module because the function is exported.
function customAdd(request, response) {
pjs.defineTable("orderline", { keyed: true, add: true });
var qty = parseInt(request.body.qty) || 1;
// Make sure the QTY is >= 1
request.body.qty = qty < 1 ? 1 : qty;
var result = orderline.write(null, request.body);
response.send(result);
}
function findOne(request, response) {
pjs.defineTable("orderline", { keyed: true, read: true });
var order = request.order || request.query.order || request.param.order;
var line = request.line || request.query.line || request.param.line;
var data = orderline.getRecord(order, line);
if (response)
response.send(data);
else
return data;
}
module.exports = {
useSQL: true,
dbObject: "order_line",
uniqueKey: [
{ field: "order_id", ascending: true },
{ field: "line_id", ascending: true }
],
findOne: findOne,
routes: {
add: { path:"/orderdetails", handler: customAdd }, // notice the handler property is set to this "customAdd" function.
get: "/orderdetails/:order/:line",
findOne: { method: "get", path:"/orderdetails/find"}, // notice that handler property is not set, but the name "findOne" is an exported function, so it will auto connect them.
getList: "/orderdetails/:order",
update: "/orderdetails/:order/:line",
delete: {path: "/orderdetails/:order/:line", authorize:"apiAuthenticate.js"}, // notice the authorize property is set to a javascript file. This file is yours to create and maintain. It will be called before this action.
}
}
All functions that use any of the PJS APIs should be declared outside of the of the exports section.
Make sure your function names do not match the existing RLA functions, because the RLA functions will take precedence.
You can define the routes in a few different manners.
name: "url path"
The route method will default to POST (unless it is one of the built-in functions - see above)
The name is also the name of the function to be called
Here is an example of creating your own web services. The function named is changeQuantity, so the the name of the route should be the same.
function changeQuantity(request, response) {
var result = null;
pjs.defineTable("orderline", { keyed: true, read: true, update: true, delete: true });
var newQty = parseInt(request.body.qty) || 0;
// If QTY is <= 0 then delete it, else update it
if (newQty <= 0)
result = orderline.delete([request.params.order, request.params.line]);
else {
var item = orderline.getRecord([request.params.order, request.params.line]);
item.qty = newQty;
result = orderline.update(null, item);
}
response.send(result);
}
module.exports = {
...
changeQuantity: changeQuantity, // This will allow this function to be available to other modules
routes: {
...
changeQuantity: "/orderdetails/:order/:line"
}
}
name: {method: "route method", path: "url path" }
Same as above with the option to override the routing methods
name: {method: "route method", path: "url path", handler: "the function" }
Same as above with the option to override the function to be called
The function value should be the actual function object
Because this definition has both the function and path, the name is only needed to be unique to pass javascript rules.