sri4node
v1.2.36
Published
An implementation of SRI (Standard ROA Interface) on Node.js.
Downloads
24
Readme
About
An implementation of SRI (Standard ROA Interface). SRI is a set of standards to make RESTful interfaces. It specifies how resources are accesses, queried, updated, deleted. The specification can be found here.
The implementation supports storage on a postgres database.
Installing
Installation is simple using npm :
$ cd [your_project]
$ npm install --save sri4node
You will also want to install Express.js and node-postgres :
$ npm install --save express
$ npm install --save pg
Express.js and node-postgress are technically not dependencies (as in npm dependencies) of sri4node. But you need to pass them in when configuring. This allows you to keep full control over the order of registering express middleware, and allows you to share and configure the node-postgres library.
Usage
Start by requiring the module in your code. Then we'll create some convenient aliasses for the utility functions bundled with sri4node as well.
var express = require('express');
var app = express();
var pg = require('pg');
var sri4node = require('sri4node');
var $u = sri4node.utils;
var $m = sri4node.mapUtils;
var $s = sri4node.schemaUtils;
var $q = sri4node.queryUtils;
Finally we configure handlers for 1 example resource.
This example shows a resource for storing content as html
with meta-data like authors
, themes
and editor
.
The declaration of the editor is a reference to a second resource (/person), which itself is not shown here.
var promise = sri4node.configure(app,pg,
{
// Log and time HTTP requests ?
logrequests : true,
// Log SQL ?
logsql: false,
// Log debugging information ?
logdebug: false,
// Log middleware timing ?
logmiddleware: true,
// The URL of the postgres database
defaultdatabaseurl : "postgres://user:pwd@localhost:5432/postgres",
authenticate: $u.basicAuthentication(myAuthenticator),
identify : functionToConstructSecurityContext,
// All URLs force SSL and allow cross origin access.
forceSecureSockets: true,
description: 'A description about the collection of resources',
resources : [
{
// Base url, maps 1:1 with a table in postgres
// Can be defined as /x or /x/y/..
// Table name will be the last part of the path
type: '/content',
// Is this resource public ?
// Can it be read / updated / inserted publicly ?
public: false,
// Multiple function that check access control
// They receive a database object and the security context
// as determined by the 'identify' function above.
secure : [
checkAccessOnResource,
checkSomeMoreRules
],
// Enable cache (default false)
cache: {
ttl: 60, // in seconds, the time the objects live (0 means forever)
type: 'local' // will store in an in-memory local cache
},
// custom routes can be defined. See #custom-routes
customroutes: [
{route: '/content/:key/:attachment', handler: getAttachment}
],
// Standard JSON Schema definition.
// It uses utility functions, for compactness.
schema: {
$schema: "http://json-schema.org/schema#",
title: "An article on the websites/mailinglists.",
type: "object",
properties : {
authors: $s.string("Comma-separated list of authors."),
themes: $s.string("Comma-separated list of themes."),
html: $s.string("HTML content of the article.")
},
required: ["authors","themes","html"]
},
// Functions that validate the incoming resource
// when a PUT operation is executed.
validate: [
validateAuthorVersusThemes
],
// Supported URL parameters are configured
// for list resources. $q is an alias for
// sri4node.queryUtils.
// This is a collection of predefined functions.
// You can build your own (see below).
// These functions can execute an arbitrary set
// of preparatory queries on the database,
// You can execute stored procedures and create
// temporary tables to allow you to add things like :
// ' AND key IN (SELECT key FROM mytemptable) '
// to the query being executed.
// Allowig any kind of filtering on
// the resulting list resource.
query: {
editor: $q.filterReferencedType('/persons','editor'),
defaultFilter: $q.defaultFilter
},
// The limit for queries. If not provided a default will be used
defaultlimit: 5,
// The maximum allowed limit for queries. If not provided a default will be used
maxlimit: 50,
// All columns in the table that appear in the
// resource should be declared in the 'map' object.
// Optionally mapping functions can be given.
// Mapping functions can be registered
// for onread, onwrite and onupdate.
//
// For GET operations the key in the 'map' object
// is the name of the key as it will appear in the JSON output.
//
// For PUT operations it is the key that appears
// on the input resource. The end result after mapping
// is created / updated in the database table.
map: {
authors: {},
themes: {},
html: {},
// Reference to another resource of type /persons.
// (mapping of 'persons' is not shown in this example)
// Can also be referenced as /x/y/.. if another resources is defined like this
editor: {references : '/persons'}
},
// After read, update, insert or delete
// you can perform extra actions.
afterread: [
addAdditionalInfoToOutputJSON
],
afterupdate: [],
afterinsert: [],
afterdelete: [
cleanupFunction
]
}
]
});
Configure returns a Q promise. Now we can start Express.js to start serving up our SRI REST interface :
promise.then(function () {
app.listen(5000, function() {
console.log("Node app is running at localhost:" + app.get('port'))
});
});
Reserved and required fields (mandatory)
There are 3 columns that every resource table must have (it's mandatory).
Those are:
- "$$meta.deleted" boolean not null default false,
- "$$meta.modified" timestamp with time zone not null default current_timestamp,
- "$$meta.created" timestamp with time zone not null default current_timestamp
For performance reasons it's highly suggested that an index is created for each column:
- CREATE INDEX table_created ON table ("$$meta.created");
- CREATE INDEX table_modified ON table ("$$meta.modified");
- CREATE INDEX table_deleted ON table ("$$meta.deleted");
The following index is for the default order by:
- CREATE INDEX table_created_key ON table ("$$meta.created", "key");
The application will fail to register a resource that lacks these fields (and show a message to the user)
Processing Pipeline
sri4node has a very simple processing pipeline for mapping SRI resources onto a database. We explain the possible HTTP operations below :
- reading regular resources (GET)
- updating/creating regular resources (PUT)
- deleting regular resources (DELETE)
- reading list resources (queries) (GET)
In essence we map 1 regular resource to a database row. A list resource corresponds to a query on a database table.
Expansion on list resource can be specified as expand=results
, this will include all regular resources in your list resource.
A shorthand version of this is expand=full
.
Expansion on list resource can also be specified as expand=results.x.y,results.u.v.w
, where x.y
and u.v.w
can be any path in the expanded regular resource.
This will include related regular resources.
Expansion on regular resource can be specified as expand=u.v,x.y.z
, where u.v
and x.y.z
can be any reference to related regular resources.
This will include related regular resources.
When reading a regular resource a database row is transformed into an SRI resource by doing this :
- Check if you have permission by executing all registered
secure
functions in the configuration. If any of these functions rejects its promise, the client will receive 403 Forbidden. - Retrieve the row and convert all columns into a JSON key-value pair (keys map directly to the database column name).
All standard postgreSQL datatypes are converted automatically to JSON.
Values can be transformed by an onread function (if configured).
By default references to other resources (GUIDs in the database) are expanded to form a relative URL.
As they are mapped with
{ references: '/type' }
. - Add a
$$meta
section to the response document. - Execute any
afterread
functions to allow you to manipulate the result JSON.
When creating or updating a regular resource, a database row is updated/inserted by doing this :
- Check if you have permission by executing all registered
secure
functions. If any of these functions rejects its promise, the client will receive 403 Forbidden. - Perform schema validation on the incoming resource. If the schema is violated, the client will receive a 409 Conflict.
- Execute
validate
functions. If any of of thevalidate
functions rejects its promise, the client receives a 409 Conflict. - Convert the JSON document into a simple key-value object.
Keys map 1:1 with database columns.
All incoming values are passed through the
onwrite
/oninsert
function for conversion (if configured). By default references to other resources (relative links in the JSON document) are reduced to foreign keys values (GUIDs) in the database. - insert or update the database row.
- Execute
afterupdate
orafterinsert
functions.
When deleting a regular resource :
- Check if you have permission by executing all registered
secure
functions in the mapping. If any of these functions rejects its promise, the client will receive 403 Forbidden. - Delete the row from the database.
- Execute any
afterdelete
functions.
When reading a list resource :
- Check if you have read permission by executing all registered
secure
functions in the mapping. If any of these functions rejects its promise, the client will receive 403 Forbidden. - Generate a
SELECT COUNT
statement and execute all registeredquery
functions to annotate theWHERE
clause of the query. - Execute a
SELECT
statement and execute all registeredquery
functions to annotate theWHERE
clause of the query. Thequery
functions are executed if they appear in the request URL as parameters. Thequery
section can also define adefaultFilter
function. It is this default function that will be called if no other query function was registered. - Retrieve the results, and expand if necessary (i.e. generate a JSON document for the result row - and add it as
$$expanded
). See the SRI specification for more details. - Build a list resource with a
$$meta
section + aresults
section. - Execute any
afterread
functions to allow you to manipulate the result JSON.
That's it ! :-).
Timing
If logmiddleware
is true in the configuration the application will display a log of the timing of each
middleware.
Function Definitions
Below is a description of the different types of functions that you can use in the configuration of sri4node.
It describes the inputs and outputs of the different functions.
Most of these function return a Q promise.
Some of the function are called with a database context, allowing you to execute SQL inside your function.
Such a database object can be used together with sri4node.utils.prepareSQL()
and sri4node.utils.executeSQL()
.
Transaction demarcation is handled by sri4node, on a per-request-basis.
That implies that /batch
operations are all handled in a single transaction.
For more details on batch operations see the SRI specification.
onread
Database columns are mapped 1:1 to keys in the output JSON object.
The onread
function receives these arguments :
key
is the key the function was registered on.element
is the the result of the query that was executed.
Functions are executed in order of listing in the map
section of the configuration.
No return value is expected, this function manipulates the element in-place.
These functions allow you to do al sorts of things,
like remove the key if it is NULL
in the database,
always remove a certain key, rename a key, etc..
A selection of predefined functions is available in sri4node.mapUtils
(usually assigned to $m
).
See below for details.
oninsert / onupdate
JSON properties are mapped 1:1 to columns in the postgres table.
The onupdate
and oninsert
functions recieves these parameters :
key
is the key they were registered on.element
is the JSON object being PUT.
All functions are executed in order of listing in the map
section of the configuration.
All are allowed to manipulate the element, before it is inserted/updated in the table.
No return value is expected, the functions manipulate the element in-place.
A selection of predefined functions is available in sri4node.mapUtils
(usually assign to $m
).
See below for details.
secure
A secure
function receives these parameters :
request
is the Express.js request object for this operation.response
is the Express.js response object for this operation.database
is a database object (see above) that you can use for querying the database.me
is the security context of the user performing the current HTTP operation. This is the result of theidentify
function.batch
an array of the operations requested. Each element has attributeshref
andverb
.
The function must return a Q promise.
It should resolve()
the promise if the function allows the HTTP operation.
It should reject()
the promise if the function disallows the HTTP operation.
In the later case the client will receive a 403 Forbidden as response to his operation.
validate
Validation functions are executed before update/insert. All validation functions are executed for every PUT operation.
A validate
function receives these arguments :
body
is the full JSON document being PUT.database
is a database object (see above) that you can use for querying the database.
The function must return a Q promise.
It should reject()
the returned promise if the validation fails, with one or more objects that correspond to the SRI definition of an error.
The implementation can return an array, or a single object.
If any of the validate
functions reject their promise, the client receives 409 Conflict.
In the response body the client will then find all responses generated by all rejecting validate
functions combined.
query
All queries are URLs.
Any allowed URL parameter is interpreted by these functions.
The functions can annotate the WHERE
clause of the query executed.
The functions receive these parameters :
value
is the value of the request parameter (string).select
is a query object (as returned bysri4node.prepareSQL()
) for adding SQL to theWHERE
clause. See below for more details.parameter
is the name of the URL parameter.database
is a database object that you can use to execute extra SQL statements.count
is a boolean telling you if you are currently decorating theSELECT COUNT
query, or the finalSELECT
query. Useful for making sure some statements are not executed twice (when using the database object)mapping
is the mapping in the configuration of sri4node.
All the configured query
functions should extend the SQL statement with an AND
clause.
The function must return a Q promise.
When the URL parameter was applied to the query object, then the promise should resolve()
.
If one query function rejects its promise, the client received 404 Not Found and all error objects by all rejecting query
functions in the body.
It should reject with one or an array of error objects that correspond to the SRI definition.
Mind you that path does not makes sense for errors on URL parameters, so it is ommited.
If a query parameter is supplied that is not supported, the client also receives a 404 Not Found and a listing of supported query parameters.
handlelistqueryresult
An optional function to override the default code for building the JSON result based on the database query result.
This function receives these parameters :
req
the express.js request object.result
is an object containing the query result.
The function must return a Q promise JSON output object.
afterread
Hook for post-processing a GET operation (both regular and list resources).
It applies to both regular resources, and list resources (with at least expand=results
).
The function receives these parameters :
database
is a database object, allowing you to execute extra SQL statements.elements
is an array of one or more resources that you can manipulate.me
the return of the identify functionroute
the url route that originated the responseheadersFn
A function of the form (field [, value]): Sets the response’s HTTP header field to value. To set multiple fields at once, pass an object as the parameter.
The function must return a Q promise.
If one of the afterread
methods rejects its promise, all error objects are returned to the client, who receives a 500 Internal Error response by default. It should reject()
with an object that correspond to the SRI definition of an error.
When rejecting, an object can be provided to produce a different output. The object must have the following properties:
statusCode
is the http status code to be returned in the response.body
is the body of the http response Mind you that path does not makes sense for errors in afterread methods, so you should omit it.
afterupdate / afterinsert
Hooks for post-processing a PUT operation can be registered to perform desired things, like clear a cache, do further processing, update other tables, etc.. The function receives these parameters :
database
is a database object, allowing you to execute extra SQL statements.elements
is an array of one or more objects. Each object contains two attributes:path
is the route of the requestbody
is the JSON element (as it was PUT, so without mapping/processing) that was just updated / created.
me
the return of the identify function
The function must return a Q promise.
In case the returned promise is rejected, all executed SQL (including the INSERT/UPDATE of the resource) is rolled back.
The function should reject()
its promise with an object that correspond to the SRI definition of an error.
If any of the functions rejects its promise the client receives 409 Conflict by default, an a combination of all error objects in the response body.
When rejecting, an object can be provided to produce a different output. The object must have the following properties:
statusCode
is the http status code to be returned in the response.body
is the body of the http response
afterdelete
Hook for post-processing when a record is deleted. The function receives these parameters :
database
is a database object, allowing you to execute extra SQL statements.elements
is an array of one or more objects. Each object contains two attributes:path
is the route of the requestbody
is the permalink of the object that was deleted.
me
the return of the identify function
The function must return a Q promise.
In case the returned promise is rejected, the database transaction (including the DELETE of the resource) is rolled back.
The function should reject()
its promise with an object that correspond to the SRI definition of an error.
If any of the functions rejects its promise the client receives 409 Conflict by default, an a combination of all error objects in the response body.
When rejecting, an object can be provided to produce a different output. The object must have the following properties:
statusCode
is the http status code to be returned in the response.body
is the body of the http response
authenticate
This function handles authentication of the current user. This function receives these parameters :
req
the express.js request object.res
the express.js response object.next
a function that can be called to delegate response handling to the next handler in the chain.
checkAuthentication
If this function is configured it takes precedence over #authenticate for read (GET) operations. This must be accompanied by the #postAuthenticationFailed function.
The difference with authenticate is that this function tries to authenticate the user but continues regardless of whether there's a valid user or not. If there's a valid user it puts it in the req object for subsequent checks.
req
the express.js request object.res
the express.js response object.next
a function that can be called to delegate response handling to the next handler in the chain.
postAuthenticationFailed
This function is called if the read (GET) operation didn't succeed because of permission issues.
If there's a valid user, then the user is not authorized. If there's no user, then it's not authenticated.
The error can be used to send a specific error.
req
the express.js request object.res
the express.js response object.user
a function that can be called to delegate response handling to the next handler in the chain.error
a function that can be called to delegate response handling to the next handler in the chain.
identify
This function determines the /me resource. The same information is also passed into query
functions as an argument.
It receives these parameter :
req
the express.js request object, allowing you to analyze any headers on the request.database
a database obejct, allowing you to perform queries.
The function must return a Q promise, with the me
object.
This will be returned in the body of a request to /me, and it will also be passed into your secure
functions.
resource specific configuration variables
methods
Can be used to restrict the methods which are allowed on a resource. If not specified the default is [ 'GET','PUT','POST','DELETE' ]
table
Can be used to override the tablename in case it does not match the resource name.
Caching
By default resources are not cached. By defining a cache
section we can store results in a cache not to hit the database.
The key of the cache is the requested url.
There are currently two supported types of caches: local and redis.
local
stores the output in a local in-memory cache.redis
connects to a Redis store and stores objects there. This allows for horizontal scalability since multiple application instances can share the cache.
Examples
cache: { ttl: 0, type: 'local' }
Will store objects in a local cache without an expiration time. The object will live in the cache until replaced by a new version
cache: { ttl: 60, // store objects for 60 seconds. After 60 seconds the objects are purged. type: 'redis', redis: 'redis://[email protected]:9000' }
If type is redis the URL to a Redis server must be provided.
Custom Routes
Allows you to set extra routes besides the defaults GET, PUT, DELETE for the resource. Each element of the customroutes array contains:
route
uri to be added [required].method
the route method, possible values GET, PUT. Default GET.handler
function called when the route is accessed [required].middleware
optional Express.js middleware function or array of such functions to be called before the handler.description
a description of the custom route.
A handler function receives this arguments:
req
the express.js request object.res
the express.js response object.database
is a database object (see above) that you can use for querying the database.me
the return of the identify function
Limiting results
The following attributes dictate how the lists are paginated:
defaultlimit
: the number of resources per page. If empty, a default of 30 is used.maxlimit
: The maximum limit allowed. If empty, a default of 500 is used.
The limit query parameter can be used to specify the amount of retrieved results. A special case is allowed where the limit value is '*' and the expand parameter is 'NONE', this means unlimited results.
Bundled Utility Functions
These utilities live independently of the basic processing described above. In other words, they provide no magic for the developer. They are provided for convenience. If you understand the above processing pipeline, reading the source for one of these functions should contain no surprises.
General Utilities
The utilities are found in sri4node.utils
.
getConnection(pg, configuration)
Used for obtaining a new connection to the database. It must be properly closed after done using it. Failure to do so will create connection leaks in the pool. Arguments:
pg
: a postgres object (https://www.npmjs.com/package/pg)config
: a configuration object with the attributes:{defaultdatabaseurl: databaseUrl, logsql: verbose}
Example usage:
var db;
getConnection(pg, config)
.then(function (database) {
db = database;
// do something with the database
})
.finally(function () {
db.done();
});
prepareSQL()
Used for preparing SQL. Supply a name
to keep the query in the database as a prepared statement.
It returns a query object with these functions :
sql()
is a method for appending sql.param(value)
is a method for appending a parameter to the SQL statement.array(value)
is a method for appending an array of parameters to the SQL statement (comma-separated). Useful for generating things likeIN
clauses.keys(value)
adds all keys in an object comma-separated to the SQL statement.values(value)
is a method for appending all values of an object as parameters to the SQL statement.keys
andvalues
have the same iteration order.with(query, virtualtablename)
is a method for adding a different query object asWITH
statement to this query. Allows you to use postgres Common Table Expressions (CTE) in your request parameters. You can refer in the query to the virtual table you named withvirtualtablename
. Use$u.prepareSQL()
to build the SQL statement for your CTE.
All the methods on the query object can be chained. It forms a simple fluent interface.
Example of using a common table expression :
var query = $u.prepareSQL();
query.sql('SELECT * FROM xyz WHERE c1 IN (SELECT * FROM virtualtable)');
var cte = $u.prepareSQL();
cte.sql(...);
query.with(cte,'virtualtable');
executeSQL(database, query)
Used for executing SQL.
Call with the a database
object you received, and a query
object (as returned by prepareSQL()
, or as received for query
functions).
The function returns a Q promise.
It's not a responsible of this function to close the connection on error since it's an argument, hence the caller must properly
make sure that the connection is disposed regardless of the result.
addReferencingResources(type, foreignkey, targetkey)
Afterread utility function. Adds, for convenience, an array of referencing resource to the currently retrieved resource(s).
It will add an array of references to resource of type
to the currently retrieved resource.
Specify the foreign key column (in the table of those referencing resource) via foreignkey
.
Specify the desired key (should be $$somekey
, as it is not actually a part of the resource, but provided for convenience) to add to the currently retrieved resource(s) via targetkey
.
convertListResourceURLToSQL(req, mapping, count, database, query)
Receives a query object and constructs the SQL for a list query.
Arguments:
req
is the request object.mapping
is the mapping in the configuration of sri4node.count
a boolean to indicate if the query wanted is a count query or not.database
a database obejct, allowing you to perform queries.query
a query obtain viaprepareSQL
This returns a promise that it's fulfilled when the query
object contains the constructed SQL.
basicAuthentication(authenticator)
Used for protecting a resource with BASIC authentication.
It accepts a single parameter, that is in turn a function that is responsible for checking username/password.
The function authenticator
, receives these parameters :
database
is a database connection, that may be used to perform queries.username
the username, that sent on the HTTPAuthentication
header.password
the password, that was sent on the HTTPAuthentication
header.
The authenticator
function should return a Q promise that is resolved with a boolean true
or false
to indicate that username and password match, or do not match.
It should reject the promise in any other case.
Mapping Utilities
Provides various utilities for mapping between postgres and JSON.
These functions can be found in sri4node.mapUtils
.
removeifnull
Remove key from object if value was null/undefined.
sri4node = require('sri4node');
$m = sri4node.mapUtils;
...
{
type: '/content',
...
map: {
...
title: { onread: $m.removeifnull }
...
},
...
}
remove
Always remove this key.
sri4node = require('sri4node');
$m = sri4node.mapUtils;
...
{
type: '/content',
...
map: {
...
title: { onread: $m.remove }
...
},
...
}
now
Override with current server timestamp.
sri4node = require('sri4node');
$m = sri4node.mapUtils;
...
{
type: '/content',
...
map: {
...
publicationdate: { onupdate: $m.now, oninsert: $m.now }
...
},
...
}
value()
Override with a fixed value.
sri4node = require('sri4node');
$m = sri4node.mapUtils;
...
{
type: '/content',
...
map: {
...
status: { oninsert: $m.value('active') }
...
},
...
}
parse
Convert string into JSON.
sri4node = require('sri4node');
$m = sri4node.mapUtils;
...
{
type: '/content',
...
map: {
...
details: {
onread: $m.parse,
oninsert: $m.stringify,
onupdate: $m.stringify
}
...
},
...
}
stringify
Convert JSON into string.
sri4node = require('sri4node');
$m = sri4node.mapUtils;
...
{
type: '/content',
...
map: {
...
details: {
onread: $m.parse,
oninsert: $m.stringify,
onupdate: $m.stringify
}
...
},
...
}
JSON Schema Utilities
These functions are found in sri4node.schemaUtils
.
Provides various utilities for keeping your JSON schema definition compact and readable.
description
is always used to document your resources.
General usage:
sri4node = require('sri4node');
$s = sri4node.schemaUtils;
...
{
type: '/content',
...
schema: {
$schema: "http://json-schema.org/schema#",
title: "An article on the websites/mailinglists.",
type: "object",
properties : {
title: $s.string('Title of the article.',1);
},
...
},
...
}
We describe the generated JSON schema fragment below.
You can use these functions, but when they are insufficient you can insert any valid JSON schema manually in the schema
property of a resource configuration.
They are only provided for convenience.
permalink(type, description)
Used for declaring permalinks.
Example : $s.permalink('/persons','The creator of the article.')
.
Generated schema fragment :
{
type: "object",
properties: {
href: {
type: "string",
pattern: "^\/" + name + "\/[-0-9a-f].*$",
minLength: name.length + 38,
maxLength: name.length + 38,
description: description
}
},
required: ["href"]
}
string(description, min, max)
As you should define your postgres columns as type text
setting minimum and maximum length is usually omitted.
Example: $s.string('Title of the article.',5)
.
Generated schema fragment :
{
type: "string",
description: description,
minLength: min, // if supplied.
maxLength: max, // if supplied.
}
numeric(description)
Defines a property as numeric.
Example: $s.numeric('The amount of ...')
.
Generated schema fragment :
{
type: "numeric",
multipleOf: "1.0",
description: description
}
email(description)
Defines an email.
Example: $s.email('Personal email of the customer.')
.
Generated schema fragment :
{
type: "string",
format: "email",
minLength: 1,
maxLength: 254,
description: description
}
url(description)
Defines a URL.
Example: $s.url('The homepage of the organisational unit.')
.
Generated schema fragment :
{
type: "string",
minLength: 1,
maxLength: 2000,
format: "uri",
description: description
}
belgianzipcode(description)
Defines a Belgian zipcode.
Example: $s.zipcode('The zipcode of the address')
.
Generated schema fragment :
{
type: "string",
pattern: "^[0-9][0-9][0-9][0-9]$",
description: description
}
phone(description)
Defines a telephone number.
Example: $s.phone('The telephone of the customer')
.
Generated schema fragment :
{
type: "string",
pattern: "^[0-9]*$",
minLength: 9,
maxLength: 10,
description: description
}
timestamp(description)
Defines a JSON timestamp.
Example: $s.timestamp('The creation date/time of this resource')
.
Generated schema fragment :
{
type: "string",
format: "date-time",
description: description
}
boolean(description)
Defines a JSON boolean.
Example: $s.boolean('Does she love me or does she not ?')
Generated schema fragment :
{
type: "boolean",
description: description
}
guid(description)
Defines a column as GUID.
Example: $s.guid('API-key for a plugin')
Generated schema fragment :
{
type: 'string',
description: description,
pattern: '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$'
}
Query functions
The functions are found in sri4node.queryUtils
.
Provides pre-packaged filters for use as query
function in a resource configuration.
The example assume you have stored sri4node.queryUtils
in $q as a shortcut.
var sri4node = require('sri4node');
...
var $q = sri4node.queryUtils;
filterReferencedType(type, columnname)
Can be used to filter on referenced resources.
Example: /content resources have a key creator
that references /persons.
A list resource /content?creator=/persons/{guid}
can be created by adding this query function :
{
type: '/content',
map: {
...
creator: { references: '/persons' },
...
},
...
query: [
creator: $q.filterReferencedType('/persons','creator')
],
...
}
Do a query to retrieve all content, created by person X :
GET /content?creator=/persons/{guid-X}
The value being passed in as a URL parameter can be a single href, or a comma-separated list of hrefs. The filter will match on any of the given permalinks.
defaultFilter
An implementation of sri-query. SRI-query defines default, basic filtering on list resources. The function is a default, shared implementation of that.
{
type: '/schools',
map: {
...
},
...
query: [
...
defaultFilter: $q.defaultFilter
]
}
Read the specification for details. Example queries are :
GET /schools?institutionNumberGreater=100000
GET /schools?nameContains=vbs
GET /schools?nameCaseInsensitive=Minnestraal
GET /schools?seatAddresses.key=a39c809e-a3a4-11e3-ace8-005056872b95
Relations query filters
When a resource is detected as a relation (has from and to properties) some query filters are added for the list resources.
{
type: '/relations',
map: {
from: {references: '/messages'},
to: {references: '/messages'}
},
...
query: {
...
}
}
fromTypes
Can be used to filter those relations where the 'from' resource is some of the given types.
toTypes
Can be used to filter those relations where the 'to' resource is some of the given types.
froms
Filter those relations where the 'from' resources is one of the given ones.
tos
Filter those relations where the 'to' resources is one of the given ones.
Example queries are :
GET /relations?fromTypes=request,offer
GET /relations?toTypes=response
GET /relations?froms=/messages/{guid}
GET /relations?tos=/messages/{guid}
Generated API Documentation
Documentation will be generated based on the configuration.
On the /docs
endpoint you can access general documentation about all the resources that are available.
When you want more information about a resource you can access /resource/docs
validateDocs
To document validate functions you need to add validateDocs to the resource configuration. validateDocs has to include a description and possible error codes of the validate function.
validate: [
validateAuthorVersusThemes
],
validateDocs: {
validateAuthorVersusThemes: {
description: "Validate if author or theme exists",
errors: [{
code: 'not.a.desert',
description: 'This is not a desert.'
}]
}
}
queryDocs
To document a custom query function you need to add queryDocs to the resource configuration. queryDocs has to include the description of the query function.
query: {
editor: $q.filterReferencedType('/persons','editor'),
defaultFilter: $q.defaultFilter
},
queryDocs: {
editor: 'Allow to filer on an editor.'
}
##Description
####Interface You can describe your sri interface by using the description variable in the root for your configuration
description: 'A description about the collection of resources'
####Resource You can describe a resource by using the to use schema > title
title: 'An article on the websites/mailinglists'
####Property If you want to describe a property of a resource you need to use schema > properties > property > description :
properties : {
authors: {
type: 'string'
description: 'Comma-separated list of authors.'
}
}
Or use the schemaUtils function:
properties : {
authors: $s.string('Comma-separated list of authors.')
}
Contributions
Contributions are welcome. Contact me on dimitry-underscore-dhondt-at-yahoo-dot-com.
License
The software is licensed under LGPL license.