Rest API Introduction
Overview
This guide will cover the configuration for the following:
-
REST API General Notes – Describes the topics which covers general REST API implementation such as REST API conventions, client information headers and returning of errors.
-
REST API Authentication – Describes information regarding authentication and authorisation of Enactor REST APIs.
REST API General Notes
This section contains the general implementation notes of Enactor REST APIs. The REST services below will all be implemented as Enactor Application Processes. These will accept and return Request and Response objects in a similar manner to SOAP web services; this ensures a clean and consistent interface when a client is communicating with the service. However, it is recommended that the implementation of the service does not pass around the request and response – if calls to other processes are needed, the request and response parameters should be unwrapped before they are passed on. This allows the implementation details of the services to be more easily reused by other applications.
REST API Conventions
In all the services describes below, the following conventions are applied:
Request Methods
-
POST – This is generally a 'CREATE' operation. Attempts to POST a resource that already exists should fail. A POST to a collection endpoint should create a new record in the collection. The request body will describe the content of the entity being created – this can be empty which should create a new empty record. A POST may also be used in cases where an 'advanced' query is required, in which case the request body describes the query to perform.
-
GET – This is always a 'READ' operation. GET requests should never modify the data associated with the entity. A request body should not be supplied with a GET request.
-
PUT – This is an 'UPDATE/REPLACE' operation. Attempts to PUT a resource that does not already exist should fail. The request body will fully describe the content the entity should have after the service has completed – If the request body is empty, this implies the entity should be reset to an 'empty' state.
-
PATCH – This is a 'MODIFY' operation. Attempts to PATCH a resource that does not already exist should fail. A patch request URL should identify the entity, or part of the entity that is being modified. The request body should contain the content for the modification (the new value for the property for example)
-
DELETE – This is a 'DELETE' operation. Attempts to DELETE a resource that does not already exist should fail. A request body should not be supplied with a DELETE request.
Request Headers
The request headers must include either:
-
A JSON Web Token, provided by the Identity Service. This will contain the secure data provided from the identity service and will be used to validate authorisation to invoke the service.
-
A valid Authorisation header that is validated against the Enactor Database to grant access to the service.
-
If the actor calling the service is a device in the Enactor Estate, then the client device information must be supplied as headers. More details are provided in the Client Information Headers section.
Request Parameters
Unless specified otherwise, Request Parameters contain optional flags that control the behaviour of the service. They should not contain data that relates to the entity being manipulated by the service.
Request Body:
If required, will be a JSON object which describes the content of the entity being manipulated, or the new data to be added to an entity.
In general, the body should not include flags used by the service and should just contain the data for the entity.
Response Status Codes
See the summary table below for details, but in general 200 (OK) or 204 (No Content) should be returned if the operation completes successfully.
Response Body:
Will be a JSON object which describes the updated/modified entity, or list of entities.
The following table summarises the Response Methods and the content of the Response Body for the different request types.
HTTP Request Method Operation Type | Response Status Code and Details | ||
---|---|---|---|
Collections (Eg: /baskets) | Items (Eg: /baskets/{id} ) | ||
POST | Create | 201 (Created) - The Location header should include the reference to
the new item (Eg: /baskets/{id} ). | 404 (Not Found) if {id} does not exist or 409 (Conflict) if {id}
does exist. |
GET | Read | 200 (OK) - Returning the list of baskets in the response body. | 200 (OK) returning the item in the response body or 404 (Not Found) if {id} does not exist. |
PUT | Update/Replace | 405 (Method Not Allowed), unless the service supports replacing the entire collection. | 200 (OK) returning the updated item or 204 (No Content) if the update item is not being returned or 404 (Not Found) if {id} does not exist. |
PATCH | Modify | 405 (Method Not Allowed) unless the service supports updating the entire collection. | 200 (OK) returning the updated item or 204 (No Content) if the
update item is not being returned or 404 (Not Found) if {id} does not
exist. |
DELETE | Delete | 405 (Method Not Allowed) unless the service supports deleting the entire collection. | 200 (OK) returning the deleted item or 204 (No Content) if the
delete item is not being returned or 404 (Not Found) if {id} does not exist. |
Services should also follow common patterns when using the standard HTTP status code where possible:
HTTP Status Code | Meaning | Example |
---|---|---|
2xx | 2xx status codes always indicate a ‘successful' call to a service. This may not mean the service performed the requested operation successfully, however it will mean the request was valid and understood. | |
200 | OK - The request has been received and a response message describing the result of the service call will be sent. A 200 response should generally have a response body. | After calling GET /baskets, this would indicate the list of baskets is available in the response body. |
201 | Created - The request has been received and a new resource has been saved/generated. The location the resource can be retrieved from will typically be returned in the Location header of the response. This status code should generally not return a response body. | After calling POST /baskets with a payload, this would indicate the basket has been stored by the Rest API. |
202 | Accepted - The request has been accepted but has not been completed yet. The Location header of the response should typically provide a URL that will allow the status of the request to be examined. This status code should generally not return a response body. | After calling DELETE /order/{orderNumber}/{lineNumber} , this would
indicate that the request to cancel the order line has been accepted and
will be completed at a later date. |
204 | No content - The request has been processed and the operation completed normally without producing any response body. | After calling POST /export passing an export request, if the request produced no matching records, a 204 status code will be generated. |
3xx | 3xx status codes are used to indicate a resource has been moved to another URL. We do not expect to use these codes within the Enactor Rest API. | |
4xx | 4xx status codes indicate a problem with the client request. | |
400 | Bad Request - This indicates the request could not be understood by the server. | After calling PUT /basket/{basketId} to replace a basket, if the
supplied body is not valid. |
401 | Unauthorised - The request has not been processed as the request did not include sufficient authentication/authorisation details, or the details that were provided do not allow access to the requested service or data. This should typically be reserved for authentication errors that are not dependent on the data in the request itself - in other words, this response can be raised without parsing the request body. | After calling any service that requires a valid user/customer. |
403 | Forbidden - The request has been understood but the service is refusing to perform the requested operation. This will typically be because the client, while succeeding authentication, has asked to perform some operation they are not authorised for. | |
404 | Not Found - The request has been understood, but the service cannot locate the resource that the request relates to. | After calling GET /baskets/{basketId}/{lineNumber} , this would
indicate that either the specified basket could not be found, or the
given line number was not found. |
405 | Method Not Allowed - The request has not been accepted as the specified HTTP method is not appropriate for the requested service. | When attempting to call PATCH /basket/{basketId} this would be
returned as the service does not support PATCH. |
409 | Conflict - The request has been understood but could not be processed as it would result in a conflict. | |
5xx | 5xx status codes indicate a problem with the server while it was processing a request. This is typically not the fault of request itself, although the request may have triggered the error. | |
500 | Internal Server Error - A general error occurred while processing the request. Additional details may be provided if appropriate. |
Client Information Headers
When a client is invoking the Rest API it may supply information to allow the Rest API to identify it:
Header | Description | Example |
---|---|---|
enactor-device-id | This header will identify the id of the device making the request | pos1@0001.enactor |
enactor-location-id | This header will specify the location of the device making the request | 0001 |
enactor-user-id | This header will specify the id of the user making the request. Note that unlike the subject header, this identifier should be for information only and should not be used for authorisation. | 1 |
Returning Errors
If an API call fails, it may response with a general error response. This response has the following fields:
{
"status": "BAD_REQUEST",
"errors": [
{
"description": "description",
"messageBase": "messageBase",
"messageId": "messageId",
"messageText": "messageText",
"errorCode": "errorCode"
},
...
],
"messageText": "messageText",
"errorCode": "errorCode",
"errorStatus": "errorStatus",
"trace": "trace",
"exception": ""
}
with the following meanings:
Field | Usage |
---|---|
status | HTTP Response Status Description (BAD_REQUEST, CONFLICT, etc). |
errors | If available, contains additional detail about errors that occurred while servicing the request. |
errors.description | Additional detail about where the error occurred. |
errors.messageBase | May include detail about the message base for the message id to aid localisation. |
errors.messageId | A message id that contains detail about why an error has been raised. |
errors.messageText | A human readable text for the message id. |
errors.errorCode | An error code that helps identify the type of error that was raised. |
messageText | A human readable text describing the failure. |
errorCode | The HTTP response code or phrase. |
errorStatus | The HTTP response code or phrase. This is deprecated but may still be used in some API responses. |
trace | An internal use string that helps identify where an error was raised. |
exception | An internal use structure that helps identify where an exception was raised. |
REST API Authentication
This section contains the information regarding authentication and authorisation of Enactor REST APIs.
Authentication and Authorisation Filter
In order to protect access to the rest services, they must be protected from access by random parties on the internet (even in cases where anonymous access is allowed). This will be enforced by a filter added 'in front' of the REST services. This filter will perform the following:
-
Capture and validate the Authorisation header or Access token (supplied as a JSON Web Token in the headers) with the Identity Service. If the header or token is invalid the filter will prevent access to the API.
-
Check that the merchant supplied associated with the Access token is authorised to access the API – this could be done by the identity service itself.
Once these conditions have been passed, the filter will then pass the request onto the API method. Using the filter allows us to remove the requirement for the individual services to perform their own authentication and authorisation tests.
Basic/Digest Authentication
In some cases, we may wish to support basic or digest-based authentication for inter-system communication. The credentials supplied in a Basic or Digest based authentication will currently be validated against the Enactor Users database – not the identity service. Where authentication is performed using Basic or Digest based authentication, the user authentication will be used as the 'subject’ for the benefit of the REST API call. As this option does not allow for sensitive data to be encoded into a JWT, this option should only really be used during development, or where the authenticity of the source and content of the request can be guaranteed.
Access Tokens
Services can be authenticated using an Access Token to be supplied when they are invoked. This will be provided by the Enactor Identity Service as a JSON Web Token in the HTTP Headers. It will be used to validate the caller has access to any sensitive data, or to validate that the API being invoked is available to the caller.
Enactor will support two tokens can be passed as http headers:
-
Authorization - This token should be used to validate the identity of the caller of the service.
-
site_token - (This has not been implemented yet) This token should be used to validate the identity of the company on whose behalf the caller is making the request.
Sensitive Data
In some cases, the rest services will need to update transactions and retrieve customer details or other sensitive data. In all cases access to sensitive data must be verified by retrieving the keys used to access it from the identity service before any changes are allowed. For example:
-
A client calls the 'Update Delivery Address' function, supplying an address ID and an Access Token.
-
The Access Token is validated by the Enactor Identity Service which returns a Customer ID as the related data for the logged in principal.
-
The service validates that the customer ID from the Identity Service is associated with the selected address before continuing.
The REST API should not trust any key data (customer IDs for example) that are present in the request.
Anonymous Data Access
In other cases, the REST services will allow anonymous access to data. For example, a customer is permitted to add items to a Basket before they are logged in. In these scenarios there must be some unique, non-sequential identifier used to access the data.
Following is an example:
-
A client calls the 'Add Item to Basket' function. The do not specify a transaction or include an access token. The service prepares a new basket, adds the item and associates it with a new random identifier. It returns the identifier back to the caller as the transaction reference.
-
A client calls the 'Add Item to Basket' function again, this time supplying the transaction reference. The service loads the transaction associated with the reference and updates it.
Authorisation Filter
The authorisation filter is used to prevent users which do not have authorisation using the Rest API. It works by verifying the request includes a valid Authorisation header with either Basic, Digest or Bearer based authentication. When using Bearer, this will be a JWT (Json Web Token) and must have a valid signature and expiration date.
Enactors JWT follows the typical structure of header.payload.signature.
Following is an example JWT:
eyJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJjbGllbnQiLCJzdWIiOiIxIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJ1cGRhdGVkX2F0IjoxNTIyMzIwOTAyLCJpc3MiOiJodHRwOlwvXC93d3cuZW5hY3Rvci5jb1wvIiwicGhvbmVfbnVtYmVyX3ZlcmlmaWVkIjpmYWxzZSwiZXhwIjoxNTIzMzU4MTQwLCJpYXQiOjE1MjMzNTQ1NDQ4Njh9.mQZM3WfaV29MBa_fGepTmUKEAZ82waCtqcmSBA7YVmLL5yPrbGAFS0HIAYmfpJ31R5lPvbTAavyKbFSgB9rXREw8mFErXDosGVn3PNPvHI5trF7QHDsa2ONsNS_nB-0IUAsxkaivamw54oFVgCpZhJRrM1q8r0Cap52wrDXG6cZozJ64jTcpk6Si9yLc1p1OkibTJJ2Z4_l221KknAuGyLgFJp84bLgjRcUCC4BU_womfRSnXCDDBtNpLuPEf2o9JC7GAL4ENtgzY-uKogdegox-NFijGzJT7GAR8H7biScb564SWC_V_4uEsL4s4pR7wmrgi-f9FMEgAinIrvBMaw
The authorisation filter can be bypassed through an enactor.xml property called REST.AuthenticateRestAPI. Without this property, the value defaults to true. True requires authorisation (JWT) to use the Rest API. False does not require authorisation, however the client needs to add a header called "subject" with its value is the customers customer number.
Following is an example enactor.xml property:
<coreProperty name="REST.AuthenticateRestAPI" value="false"/>
Common.env equivalent:
ENACTOR_REST_AUTHENTICATERESTAPI=false
Example request with the value set to false:
GET: http://[SWARM_LEADER_IP]/WebRestApi/rest/baskets/PRIMARY HTTP/1.1
Host: api.james.enactor:8080
subject: 1
Cache-Control: no-cache
Postman-Token: e832402c-002e-4e49-8fe3-f37fed392787
Example request with the value set to true;
GET http://[SWARM_LEADER_IP]/WebRestApi/rest/baskets/PRIMARY HTTP/1.1
Host: api.james.enactor:8080
Authorization: Bearer
eyJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJjbGllbnQiLCJzdWIiOiIxIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJpc3MiOiJodHRwOlwvXC93d3cuZW5hY3Rvci5jb1wvIiwicGhvbmVfbnVtYmVyX3ZlcmlmaWVkIjpmYWxzZSwiZXhwIjoxNjEwNDYyOTk4LCJpYXQiOjE2MDI2ODY5OTgxMjR9.lgk6mVVzfjaNYf53a39E0-1fV6nb0UPMvbCPpSfK49-McHFlKB-OJwsLjN_wJ3Sz_fxcGdQf8do4EpGek_jkGzahRB44HUcmoTocnieJufELZWSfx64G0JFD8I0vWbiFU76egXHMxkiGUou-v0eVYAsvE-bp_ATCXrPzZm1sb4MO5sufMEON1eF1UpUt5E9PFyKbCP3nZCLtaJ-52dZmcRt-8Xm_PpQujyiJPRF9IaVuofxpafoCih6au1oV0PojdZjKjx2bE7cVJkgXRxytIECfpwPCp3Xx_GyvzEZjAUauMIeKTH4Nu7BFJlXQZ-kY40VlSChKnB88q8dZlp5zyA
Cache-Control: no-cache
Postman-Token: bb3dff61-d4b5-48d3-8bb3-2d81d678fcee