>>Author: Thomas Ladehoff >>Ort: Kiel (Schwentinental)URL: http://www.assono.de/blog/d6plinks/REST-Services-with-the-XPages-Extension-Library
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:
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:
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):
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.
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.