The usage of REST based services is a great possibilty to integrate other
systems and applications with the Lotus Domino Server.
This blog entry outlines the meaning
and advantages of REST and shows you the basics of using the REST controls
shipped with the XPages Extension Library.
REST based (or RESTful) web serivces
are useful for integration scenarios as well as providing data to external
applications.
I used the REST services for example
recently to provide a data interface for a mobile application.
RESTful web services (if you don't know about them, yet)
Representational State Transfer (REST)
is an software architecture style described by Roy Thomas Fielding in his
dissertation.
It conforms to the architecture of the Internet with its HTTP protocol.
More precisely, one could say that the
HTTP protocol which is used in the Internet and in RESTful web services
is an implementation of the REST architecture style.
So if you know the principles of the
HTTP protocol you also know much about REST. To sum up the most important
points:
- Information is provided by resources. Every resource is accessible via an unique ID (the URL)
- "Respresentational" means, that the information is transfered in certain representions in technical meaning (e.g. JSON, XML) as well as with regard to contents (e.g. text, images).
- Stateless. The server keeps no session status over a series of requests.
- Resources can contain links to other resources, enabling navigation.
- Operation on a rescource is possible
by the use of a defined set of generic methods, typically
- GET - read access to a resource, no side effects
- POST - create a new resource
- PUT - create or update a certain resource (certain ID)
- DELETE - delete a resource
RESTful web services provide a HTTP
based service that follows the mentioned properties.
Some of the gerenal advantages of RESTful
services are:
- Loose coupling of applications and systems (leads to high interoperability)
- Easy resource oriented concept with few genereic methods
- Good scalability
- Easy caching
These are essentially also the advantages
of the HTTP potocol in general
REST based services for accessing Domino data
A good overview of the REST functionality
can be found in the video "REST
Services for Domino and XPages" on the extension library
homepage.
Here I will explain in particular the
way of using the XPages controls for REST. There are also two other ways
that don't require a XPages context (using directly the built-in Domino
Data Service and creating a custom servlet).
There are several XPages controls that
you can utilize to access Domino data, for example:
- Database Collection Service (xe:databaseCollectionJsonService): read database list on the server
- View Collection ervice (xe:viewCollectionJsonService): read list of views and folders in a database
- View Service (xe:viewJsonService): read view or folder data (with filtering), create, update and delete documents (limited)
- Document Service (xe:documentJsonService): operate on documents
As you may guess, the "Json"
within the tag names of the controls indicates the usage of the JSON
format for sending the data.
You can find examples of the controls
in the example database within the extension library
download.
For the XPages REST controls you don't
need to configure anything on the Domino server (but for convenience you
could, if we will see later).
Just create a XPage, drag and drop the
desired REST controls and you will be able to access the service.
To show this in more detail and explain
the most important parameters, we will use a very simple sample scenario
with one form 'company' and a view 'companiesByName'.
The services we need to operate on the
company documents in a convenient way are:
- xe:viewJsonService (list existing companies)
- xe:documentJsonService (create, read, update, delete a certain company document)
We could also have used the view JSON
service to update documents, but then you are limited to only those columns,
that map directly to fields in the document.
With the document JSON service we can
even operate with rich text fields and attachments.
Accessing the view data
We start with an empty XPage and add
the REST service control (see screenshot).
Some properties of the control:
- ignoreRequestParams: parameters in the url are ignored for the rest service (you probably know that from the XPages data sources)
- pathInfo: This is a string that identifies your service on the XPage. For the view JSON service in this example it is named "companies".
- service: Here you can assign exactly one concrete rest service, choosing from the given list (see screenshot)
The properties of the view JSON service
are almost self-explanatory, but to mention a few ones that should be taken
into account:
- columns: this property takes elements of the type xe:restViewColumn, which in turn has a property "columnName" (reference to the view column) and "name" (property name of the JSON Object in the output). This mapping applies only to GET requests. There is also a "value" property here, where the output can be computed.
- defaultColumns: if true, all columns in the view will be used
- systemColumns: Special system values, not necessarily available explicit as a view column (e.g. UNID, Form, Response)
- viewName: Name of the view to use for that service
There are also some properties for filter
operations, like "start" and "count" to implement paging
or "search" to do a full text search on the view content.
An addition there are properties for
reacting on document events (like querySaveDocument), which will be explained
in the section dealing with the document service.
The following screenshot shows the view
service properties, used in the example:
Test the API
To access the service, the string set
for the "pathInfo" property must be used. The general URL schema
in XPage context is:
http://{host}/{database}/{XPage name}/{pathInfo}/unid/{unid}?{parameters}
For the view service in this example
we don't want to access single documents and thus can leave out the UNID
part.
I called my database "Test1.nsf"
and my XPage "data.xsp". So my URL is:
http://localhost/Test1.nsf/data.xsp/companies
The URL can be requested by entering
it directly into the browser address bar (request method GET) and the entries
in the view should be returned in JSON format.
There is also a nice tool to test the
API quickly and to see if everything works as expected. It's a Firefox
add-on called RESTClient,
which let's you specify the HTTP method,
URL, request headers and request body. After sending the request, the response
from the server is displayed.
The following screenshot shows the response
in the RESTClient from the view service "companies":
In the response there are JSON properties
that have an @-sign before the name indicating a system (non-user-defined)
column.
The different data types have different
representation formats, for example a string is enclosed in quotes, a number
is not.
A detailed description can be found
in the documentation (file "DominoDataServiceDoc.zip" in the
extension library
download).
Operate on documents
To provide the API part for single documents,
a second REST service control has to be added to the XPage. This time the
"pathInfo" property is "company" and the concrete service
is the document service (xe:documentJsonService).
The following properties are set:
- compact: If "true", the output will not contain any whitespaces (saves bytes)
- defaultItems: If "true", all items and some metadata will be included in the output
- formName: Name of the form to use, when creating new documents
To test the new service I open the following
URL in the RESTClient (the UNID can be copied from the view service response):
http://localhost/Test1.nsf/data.xsp/company/unid/56A63CD8312606F8C1257A54004009DD
The result should now contain every
field in the form plus some meta information (e.g. properties @unid, @form,
$UpdatedBy).
The next step is updating an existing
document. Updating is usually done via the HTTP PUT method. The Extension
Library implementation handles this in a special way. It uses the PUT method
to replace the current document content with the data in the request, discarding
all previous content.
But in most of the times you probably
want to update some items and leave the rest of the document untouched.
This is realized in the Extension Library with another HTTP method called
"PATCH".
At this point it's worth mentioning
that the Domino server by default only allows GET and POST requests. Allowing
also the other methods is no problem via an Internet site document, but
you could also take an alternative approach that also comes in handy, if
your client doesn't support PATCH requests.
The HTTP methods PUT, PATCH and DELETE
can alternatively be replaced by the POST method and an additional HTTP
header called "X-HTTP-Method-Override" that in turn specifies
the method to use.
So, how to test updating an item in
a certain document with the RESTClient?
1. Setting the mehtod override header
In the RESTClient select from the title
bar: Headers -> Custom Header
Then filling out the dialog as shown
in the screenshot:
2. There is another header, that needs
to be set. Otherwise the server won't accept the request.
This is about the content type of the
request, that needs to indicate JSON format:
Header name: Content-Type
Header value: application/json
3. GET a certain document (just to have
data for updating).
4. Change the request method to POST
and make sure the headers are set.
5. Set the data, you want to update
in the request body.
6. Click "Send" and if you
don't get an error message you can check the result by switching back to
the GET method to see the updated value.
Other operations:
Create a new document: set the HTTP
method to POST (without X-HTTP-Method-Override header)
DELETE a document: set the HTTP method
to DELETE (or method POST and X-HTTP-Method-Override header to DELETE)
Programmatically extend the functionality of the document service
If you want to hook into the request
processing, one possibility is the use of the document events like "querySaveDocument".
This way you can do additional tasks
and change or add document data.
The following list is an overview over
the parameters of the different methods.
- queryNewDocument: no parameters
- queryOpenDocument: parameter 'id' (type String)
- querySaveDocument: parameter 'document' (type lotus.domino.Document)
- queryDeleteDocument: paramter 'id' (type String)
- postNewDocument: parameter 'document' (type lotus.domino.Document)
- postOpenDocument: parameter 'document' (type lotus.domino.Document)
- postSaveDocument: parameter 'document' (type lotus.domino.Document)
- postDeleteDocument: paramter 'id' (type String)
If you want to abort the request processing,
all methods starting with 'query' support a Boolean return value. When
the return value is 'false', an exception will be thrown and an error message
will be returned to the client. When it is true, the processing will be
continued.
If you need more control about what
happens and the generated output, you could also create a custom servlet.
How to do this, will be part of a future blog entry.