REST API recommendations in Jitterbit App Builder
Overview
This document provides guidance for developers looking to implement an App Builder-compatible REST API.
For the purposes of this document, we will assume that the developer is focused on creating a CRUD REST service. Many of the principles used in a CRUD API will be applicable to other APIs. However a CRUD API will likely have the most comprehensive requirements that will interplay with App Builder (paging, searching, filtering etc).
RESTful design principals
To the extent possible, App Builder's REST API follows these RESTful principals:
- Services are stateless.
- Endpoints are modeled as resources.
- GET operations are safe. A "safe" operation is one that does not have side effects. For instance, retrieving a list of customers does not change the list of customers.
- DELETE operations are unsafe, but idempotent. However, whereas the first (successful) request to delete an item will return a 200 status code, the second request will return a 404.
- POST operations are neither safe nor idempotent. Because of this, POST operations may contain partial data.
- HTTP status codes indicate whether an error occurred.
- Media types are used to perform content negotiation. At the moment, however, App Builder only supports JSON (application/json) and UTF-8.
App Builder does not adhere to all RESTful principals:
- Resource request and response bodies are wrapped in an envelope. This allows App Builder to include additional information, such as event messages and validation results.
- Resource responses are not hypermedia: they do not include links to other resources.
Envelope
App Builder REST API request and response bodies are wrapped in an envelope. Envelopes allow data to be sent to and from an API endpoint outside of the endpoint payload.
Request body envelope
The App Builder REST API request body contains these envelope properties:
Property Name | Description |
---|---|
item | The endpoint payload. |
Example JSON
{
"item": {}
}
Response body envelope
The App Builder REST API response body contains these envelope properties:
Property Name | Description |
---|---|
message | The success or failure message for the event. |
status | This is the (duplicated) HTTP status code. |
validations | An array of validation errors/warnings for the endpoint called. |
item or items | The endpoint payload - either a single item or collection of items. |
Example JSON
{
"message": "",
"status": 200,
"validations": [],
"items": []
}
Validations
When errors are encountered, a validation object is added to the validations array in the response envelope. The validation object has the follow properties:
Property Name | Description |
---|---|
message | The validation message. |
severity | The severity of the validation:
|
field | The field referenced by the validation. |
Example JSON
{
"message": "",
"status": 400,
"validations": [
{
"message": "CustomerId is mandatory.",
"severity": "error",
"field": "customerId"
},
{
"message": "CompanyName is mandatory.",
"severity": "error",
"field": "companyName"
}
],
}
Core operations
These are the basic operations that your REST service should support. Some services will of course choose to not implement certain methods (e.g. a read-only service would only implement Get Single/Get Many methods).
Get single
The Get Single operation returns a single record. The identifier for the record is specified in the URL.
HTTP method
GET
Example URL
https://example.com/rest/v1/sales/customers/b603b276-a9bf-4328-88ff-8994176c38d1
Example JSON
{
"item": {
"customerId": "b603b276-a9bf-4328-88ff-8994176c38d1",
"name": "John Henry",
"address": "130 Plutonium Drive"
}
}
Get many
The Get Many operation returns many records for a collection. Oftentimes, this operation is used alongside pagination, to allow a collection of records to be perused.
If possible, a count of the records in the collection should be returned. This allows App Builder to display the record count in the UI as well as informing the UI when the end of the collection has been reached.
HTTP method
GET
Example URL
https://example.com/rest/v1/sales/customers
Example JSON
{
"count": 2,
"items": [
{
"customerId": "b603b276-a9bf-4328-88ff-8994176c38d1",
"name": "John Henry",
"address": "130 Plutonium Drive"
},
{
"customerId": "9775de33-08fc-4cd2-98ef-d91f3d5355b1",
"name": "Sally Keith",
"address": "4500 Neutrino Road"
}
],
// envelope properties
}
Create
The Create operation will create a new record. The identifier for the record exists within the JSON body.
Note the entire record is echoed back in the response. This is useful in cases where some fields are created or updated by the server (such as a record creation time stamp).
HTTP method
POST
Example URL
https://example.com/rest/v1/sales/customers
Example request body JSON
{
"item": {
"customerId": "b603b276-a9bf-4328-88ff-8994176c38d1",
"name": "John Henry",
"address": "130 Plutonium Drive"
}
}
Example response body JSON
{
"item": {
"customerId": "b603b276-a9bf-4328-88ff-8994176c38d1",
"name": "John Henry",
"address": "130 Plutonium Drive"
}
// envelope properties
}
Update
The Update operation will upate an existing record. The identifier for the record is specified in the URL.
Note the entire record is echoed back in the response. This is useful in cases where some fields are created or updated by the server (such as a record update time stamp).
HTTP method
- PUT - Used for a full update. All parameters of the record need to be specified.
- POST - Used for a partial update. Only mandatory parameters of the record need to be specified.
Example URL
https://example.com/rest/v1/sales/customers/b603b276-a9bf-4328-88ff-8994176c38d1
Example request body JSON
{
"item": {
"customerId": "b603b276-a9bf-4328-88ff-8994176c38d1",
"name": "John Henry",
"address": "130 Plutonium Drive"
}
}
Example response body JSON
{
"item": {
"customerId": "b603b276-a9bf-4328-88ff-8994176c38d1",
"name": "John Henry",
"address": "130 Plutonium Drive"
}
// envelope properties
}
Delete
The delete operation will delete a record. The identifier for the record is specified in the URL. No request body needs to be sent for a DELETE.
HTTP method
DELETE
Example URL
https://example.com/rest/v1/sales/customers/b603b276-a9bf-4328-88ff-8994176c38d1
Example response body JSON
{
"item": {
"customerId": "b603b276-a9bf-4328-88ff-8994176c38d1",
"name": "John Henry",
"address": "130 Plutonium Drive"
}
}
Query parameters
Get many
At the collection level, your REST endpoint should support the following features.
Paging
For collections that contain many records, it is often necessary to support paging. To support paging, App Builder defines the following parameters:
Query Parameter | Description | Example |
---|---|---|
$limit | The maximum number of records to retrieve in one request. | $limit=10 |
$offset | From which record offset the fetch should begin. Offsets are zero based so specifying 0 will fetch the first record in the collection. | $offset=10 |
$count | A boolean indicating whether a collection count should be returned. In App Builder, this parameter is considered false by default. | $count=true |
Sorting
App Builder can support simple sorting of fields.
Query Parameter | Description | Example |
---|---|---|
$sort | A comma-delimited list of field names to sort by. Prefix the field name with a dash (-) to sort the field in descending order. In the provided example, sort the collection by country, descending, and companyName, ascending. | $sort=-country,companyName |
Filtering
App Builder provides support for a query filter string. The query filter string supports a subset of the OData 4.0 query string filter specification. For string comparisons, wildcards can be specified using the %
character.
Query Parameter | Description | Example |
---|---|---|
$filter | An OData 4.0 style query string that filters data | $filter=country eq 'united%' |
Operators
Comparison
Operator | Description | Example |
---|---|---|
eq | Equal to the value. | categoryId eq 42 |
neq | Not equal to the value. | categoryId neq 42 |
gt | Greater than the value. | price gt 100 |
lt | Less than the value. | price lt 100 |
ge | Greater than or equal to the value. | price ge 100 |
le | Less than or equal to the value. | price le 100 |
in | Match any value in the list. | categoryId in (1, 2, 3) |
Logical
Operator | Description | Example |
---|---|---|
and | Logical AND | price gt 100 and categoryId in (1,2,3) |
Limitations
- No arithmetic operators
- No or/not logical operators
- No grouping operators
- No query functions
- No parameter aliases
Search
App Builder provides a mechanism to search for records in a collection. This search operates across all searchable fields of the record.
App Builder by default adds wildcards to the beginning and end of the search string.
Query Parameter | Description | Example |
---|---|---|
$q | A search string to apply to all searchable columns of a record. | $q=hello |
Type conventions
JSON types
As a general rule, developers should prefer using the native built-in JSON types. App Builder automatically maps native JSON types so direct use of numerics, booleans, strings, and nulls is encouraged.
Dates
App Builder encodes dates using the ISO 8601 format. All dates are serialized in UTC.
Versioning
To handle future incompatibilities between REST API versions, App Builder includes a version number directly in the REST URL.
Example URL
https://example.com/rest/v1/...
Optional operations
Other operations which may be useful to include for a CRUD REST API.
New
The new operation is used to return record defaults. This is used in advance of creating a record for cases where some data may be pre-filled by the REST server.
HTTP method
- GET
- POST.
Example URL
https://example.com/rest/v1/sales/customers(new)
Example response body JSON
{
"item": {
"customerId": null,
"daysActive": 0
}
// envelope properties
}
JSON - Relational tables conversion
App Builder provides a mechanism to convert between the internal relational table representation of data and JSON expected by REST endpoints.
Arrays to tables
Each array in a JSON structure is considered a separate relational table within App Builder.
As such, the following conversion would apply to an endpoint named "customers(get)":
customers(get) JSON
{
"count": 2,
"message": "Sample message",
"status": 200,
"items": [
{
"customerId": "b603b276-a9bf-4328-88ff-8994176c38d1",
"name": "John Henry",
"address": "130 Plutonium Drive"
},
{
"customerId": "9775de33-08fc-4cd2-98ef-d91f3d5355b1",
"name": "Sally Keith",
"address": "4500 Neutrino Road"
}
],
// envelope properties
}
Resulting table structure
"customers(get) "
Count | Message | Status |
---|---|---|
2 | Sample message | 200 |
"customers(get)/items"
customerid | name | address |
---|---|---|
9775de33-08fc-4cd2-98ef-d91f3d5355b1 | Sally Keith | 4500 Neutrino Road |
b603b276-a9bf-4328-88ff-8994176c38d1 | John Henry | 130 Plutonium Drive |
Writing data
Currently, App Builder only supports writing to a single table during an event. Since each JSON array is considered a separate table, writing an entire object that comprises multiple arrays in a single App Builder event may not be supported.
As a result, look to minimize the usage of JSON arrays where possible, or support writing the arrays in an object in a separate REST API endpoint.
For example a "customer" object may contain multiple addresses. Having an endpoint to write the customer object, and another endpoint to write the addresses allows App Builder to more easily integrate with your REST API.