Wiki Spaces

Documentation
Projects
Resources

Get Help from Others

Q&A: Ask OpenMRS
Discussion: OpenMRS Talk
Real-Time: IRC Chat | Slack

Documentation

Page tree
Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 15 Next »

This is the technical api documentation for the Webservices.rest Module

Conventions

Because there are so many options when creating REST urls, we have laid out a set of conventions that all REST developers should follow.  This will keep our web service api looking neat and uniform across all different types of objects and modules.

  • For resource,
    • GET /ws/rest/resource?q=query = search
    • GET /ws/rest/resource/uuid = retrieve
    • POST /ws/rest/resource = create
      • Request body contains data to persist (not in request params)
    • POST /ws/rest/resource/uuid = partial update of the resource
      • Request body contains just the fields to update (not in request params)
    • PUT = replace value of entire object (we don't use this yet)
    • DELETE /ws/rest/resource/uuid = void for data, retire for metadata
    • DELETE /ws/rest/resource/uuid?purge=true = purge (aka delete from the database entirely)
  • Do not put verbs into the URL. Represent this idea with sub-resources.
    • For example, instead of addNameToPerson we POST to /ws/rest/person/uuid/names
  • URLS:
    • Are prefixed with /ws/rest/ due to servlet forwarding in openmrs
    • All lowercase
    • No special characters (e.g. no spaces or underscores)
    • Hyphens are ok if absolutely necessary
    • No extensions allowed (acceptHeader will be used to specify json or xml content. All json for release 1.0)
  • Sub-resources (i.e. things like personname or patientidentifier which belong to a parent resource) should have their URIs inside the URI of their parent (like /ws/rest/person/uuid/names/nameuuid)
  • Domain objects that are separately managed get their own URI. (e.g. /ws/rest/enrollment/uuid instead of /ws/rest/program/uuid/enrollments/uuid)
  • Hide (aka don't expose) "helper" classes as much as possible (e.g. web service clients should never see ConceptSet, etc)
  • Resource names should usually be the same as the domain objects they represent, but they may differ if the domain object name is confusing.
    • For example org.openmrs.PatientProgram is /ws/rest/enrollment

When saving or editing a property on a "Concept" object, the conceptDatatype property can be simply the uuid. In addition, for most metadata, the "name" is unique across all active metadata, so that can also be used in place of the uuid when saving as well (POST or PUT).

Representations

The objects returned by web service calls are variable in their properties. In general there are three different representations that exist: ref, default, full. It is possible for modules to provide more representations for their objects. (TODO: document what method to call to get the available reps)

To change between representations, use the "v" query parameter: ...?v=ref or ...?v=full. Using ...?v=default is invalid. Simply leave that parameter off.

Web service calls that return lists of objects will put those objects into the "ref" representation.

Ref

When an object is a child resource on another object (e.g. conceptDatatype property on Concept object) the full ConceptDatatype object is not returned by default.  Instead a "ref" kind of class with String properties for uuid, links, and a display fills the concept.conceptDatatype property.  The ref looks like this:

Ref example
concept.conceptDatatype \->
{
display: "Numeric",
uuid: "8d4a4488-c2cc-11de-8d13-0010c6dffd0f",
links: {
  self: "http:/../openmrs/ws/rest/conceptdatatype/8d4a4488-c2cc-11de-8d13-0010c6dffd0f"
  }
}

To fetch the full ConceptDatatype data, a second call to the links.self uri: http:/../openmrs/ws/rest/conceptdatatype/8d4a4488-c2cc-11de-8d13-0010c6dffd0f is needed.

Default

This representation is returned for objects when there is no "v=" parameter given. Most properties will be included and "refs" of some subobjects will also be listed.

Full

The full representation is meant when to be used when subsequent calls are not desired or you need some uncommonly needed properties (like audit info).

API Documentation

For general REST web service information and user documentation, see the module page

Resources

Every available object in the ws module is written up as a resource. The resource class defines the properties that are exposed and the setters that are available. The resource also defines the representations and what goes in them (ref vs default vs full).

See documentation about resources here: REST Web Service Resources

Subresources

There are some objects that are not defined or do not make sense apart from another parent object. These we refer to as subresoruces. Examples are PersonNames, PersonAddresses, ConceptNames, etc. You can act on subresources under the parent url:
Examples:

Adding a person name
POST /ws/rest/person/uuidofperson/names
Body content:
{givenName: "John", familyName: "Smith"}
Editing a person's name
POST /ws/rest/person/uuidofperson/names/uuidofname
Body content:
{givenName: "Johnny"}

Authentication

Nearly every method in the OpenMRS API requires authentication, therefore, some every method in the webservices module needs to have an authenticated user in order to work.

There is a filter defined on the module that intercepts all calls and authenticates the given request. 

Currently only BASIC authentication is supported.  Header arguments values of __ and __ are expected. 

Alternatively, a session token can be used.  GET /openmrs/ws/rest/session with the BASIC credentials will return the current token value.  This token should be passed with all subsequent calls as a cookie named jsessionid=token.

A resource can have any number of "links" in the links attribute. Generally these will be links to other representations (see above) but could be to other types of relationships between objects: things like "parent", etc.

A "ref" representation will contain a link to "self" that is the default rep. A "default" rep will have a link to "full" that is the same object expect with all properties included.

ETag

(available with OpenMRS v1.8.1 or higher due to the Spring Framework 3.0.5 requirement)

The module also adds an ETag to response headers when presenting resources to clients. ETags have been implemented in shallow-mode (i.e. they save client bandwidth, but not server-side processing). As described here, as a client application you may want to look at ETag when making REST calls.

From the wikipedia article:

In typical usage, when a URL is retrieved the web server will return the resource along with its corresponding ETag value, which is placed in an HTTP "ETag" field:

ETag: "686897696a7c876b7e"

The client may then decide to cache the resource, along with its ETag. Later, if the client wants to retrieve the same URL again, it will send its previously saved copy of the ETag along with the request in a "If-None-Match" field.

If-None-Match: "686897696a7c876b7e"

On this subsequent request, the server may now compare the client's ETag with the ETag for the current version of the resource. If the ETag values match, meaning that the resource has not changed, then the server may send back a very short response with an HTTP 304 Not Modified status. The 304 status tells the client that its cached version is still good and that it should use that.
However, if the ETag values do not match, meaning the resource has likely changed, then a full response including the resource's content is returned, just as if ETags were not being used. In this case the client may decide to replace its previously cached version with the newly returned resource and the new ETag.

Example using curl:

$ curl -i -u admin:test http://127.0.0.1:8080/openmrs/ws/rest/patient?q=Dar

RESPONSE HEADER IS:

HTTP/1.1 200 OK
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: JSESSIONID=1jw2itu9oyt5v;Path=/openmrs
Content-Type: application/json;charset=UTF-8
*ETag: "078c5b8fe25b332a40b4174bd38f5ee90"*
Content-Length: 399
Server: Jetty(6.1.10)
$ curl -i -u admin:test http://127.0.0.1:8080/openmrs/ws/rest/patient?q=Darius

RESPONSE HEADER IS:

HTTP/1.1 200 OK
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: JSESSIONID=1jw2itu9oyt5v;Path=/openmrs
Content-Type: application/json;charset=UTF-8
*ETag: "078c5b8fe25b332a40b4174bd38f5ee90"*
Content-Length: 399
Server: Jetty(6.1.10)

We see that both the ETag are same and hence the client knows that the response would be the same and can save bandwidth.

After some days, if Darius's records have not been updated then, the client can send the ETag and check for modifications:

$ curl -i -H 'If-None-Match:"078c5b8fe25b332a40b4174bd38f5ee90"' -u admin:test http://127.0.0.1:8080/openmrs/ws/rest/patient?q=Darius

RESPONSE IS:

HTTP/1.1 304 Not Modified
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: JSESSIONID=dlcztsmushgm;Path=/openmrs
Content-Type: application/json;charset=UTF-8
ETag: "078c5b8fe25b332a40b4174bd38f5ee90"
Content-Length: 0
Server: Jetty(6.1.10)

From the 304 Not Modified, we know that the records are the same and the client doesn't have to get the data again.

  • No labels