API Standards
2022-01-04
All our APIs follow a basic set of rules that provide consistent requests and responses for the API. This document provides the basic rules that you get when you use our platform.
Objects
Objects should be returned in collections and objects and we follow a path structure that reflects this:
collection/{collectionobjectID}
ObjectIDs should be abstract UUIDs that do not contain any identifiable information. UUID v4 format is preferred as they are generated using random numbers and not timestamps (unlike UUID v1). Again, the goal is to limit any meaningful info from the IDs
Here's a quick sample of the UUID format:
19914fd1-aa7a-4c58-acb8-969bcc123bce
Collections
A "collection" is a collection of objects. So, if you have your blog in our API, for example, you can expect to find it in the blogs collection:
GET /v1/blogs
{
"objects" : [
{
object" : {
"blogtitle" : "This is a blog",
"blog": "**Markdown** makes storing formatted text easy...",
"category" : "misc"
}
}
"objectID" : "f9debc51-db17-4db9-a342-52b95b372c08",
],
"totalObjects": 100,
"returned": 1,
"page": 0,
"size": 1,
"sortOrder": "asc",
"filters": {}
}
Note that the collection returns some basic meta data that you can use to help navigate your data:
totalObjects
: The total number of objects/records in the collectionreturned
: How many objects got returned in this responsepage
: Which page of results you're on (NOTE we start couting at 0)size
: How many objects the page could have returned (this may be bigger thanreturned
because you might only have 4 objects in your collection on a page size of 20)sortOrder
: "asc" means the oldest objects were returned first, "desc" means the objects were returned newest to oldest
Subcollections Subcollections are a great way to add security to a group of objects under a master object ID. The collection pattern continues with the subcollection and its object id:
collection/{collectionobjectID}/subcollection
Which returns a collection of objects within this subcollection and lets you drill down to the individual object under that subcollection.
collection/{collectionobjectID}/subcollection/{subcollectionobjectID}
The pattern supports multiple subcollections so you may also have
collection/{collectionobjectID}/subcollection2
And, of course, you can have sub/sub collections but you will want to consider your data structure to avoid too much nesting.
Filters
You can change what gets returned with some basic query parameters such as:
GET /v1/blogs?sortOrder=desc&size=1&page=2
sortOrder
: asc|desc sorts based on thecreated
timestamp of the objectsize
: [integer] the number of objects to return in this one request. This can be handy to grab just one object withsize=1
or everything with a ridiculously large number (not a good idea)page
: [integer] a number to select the page of results you're on (NOTE we start counting at 0)
Filter on Field Values
You can also add a filter using one or more of your fieldnames in the object itself. So if I wanted to just return blogs in the security category I could request
GET /v1/blogs?category=API+Security
Wildcards
Fields can include a wildcard in the form of an *
at the end of the string you are filtering on to search for a substring. For example
GET /v1/blogs?category=API*
This does two things:
- Returns all records with a substring of the search (eg
dog*
will returndogged
andboondoggle
) - Sets search to case-insensitive (eg.
dog*
will returnBig Dog
andlittledoggy
)
Ranges (greater than/less than)
Field filters can include $gt:
and $lt:
(note the colon). For example:
GET /v1/blogs?posted=$gt:2022-12-31
You can compound the filters to create a range:
GET /v1/blogs?posted=$gt:2022-12-31&$lt:2023-02-01
to get all blogs posed in January 2023
And you can still include the standard filters for size, page, and sort order.
Posting to a Collection
We create new objects by POST
ing to the collection. So if I want to create a new blog I would POST
to /v1/blogs
POST /v1/blogs
Authorization: Bearer {token}
{
"blogtitle" : "My blog title",
"blog" : "A nice thing happened while I was making an API",
"category" : "articles"
}
The API will respond with the object you created, including the meta data for the objectID
{
"object": {
"blogtitle" : "My blog title",
"blog" : "A nice thing happened while I was making an API",
"category" : "articles"
},
"objectID": "6dce1470-1900-11ed-8039-af237906caea",
"created": 1660172515127,
"modified": 1660172515127
}
Objects
See above (Posting to Collections) to create an object
You request an object with its objectID
GET /v1/blogs/6dce1470-1900-11ed-8039-af237906caea
Which will return the same payload that the original POST
request returned:
{
"object": {
"blogtitle" : "My blog title",
"blog" : "A nice thing happened while I was making an API",
"category" : "articles"
},
"objectID": "6dce1470-1900-11ed-8039-af237906caea",
"created": 1660172515127,
"modified": 1660172515127
}
Objects have some consistent metadata:
objectID
: The objectID is a machine-generated uuid that represents this single object. This is the ID that you use in the path (/v1/collection/{objectID})created
: A numeric timestamp (epoch time) for when this object was first created. This is generated by the API and can't be changed.modified
: A numeric timestamp (epoch time) for when the object was last updated. This is often the same value ascreated
unless someone edited the object.
Updating an Object
Just a with the POST
, you don't send the metadata when you PUT
, just the fields from your API contract:
PUT /v1/blogs/6dce1470-1900-11ed-8039-af237906caea
Authorization: Bearer {token}
{
"blogtitle" : "My Updated Blog Title",
"blog" : "A nice thing happened while I was making an API",
"category" : "articles"
}
This will respond with the updated payload and a new modified
timestamp:
{
"object": {
"blogtitle" : "My Updated Blog Title",
"blog" : "A nice thing happened while I was making an API",
"category" : "articles"
},
"objectID": "6dce1470-1900-11ed-8039-af237906caea",
"created": 1660172515127,
"modified": 1660458132994
}
Deleting an Object
When you want to DELETE
an object you simply make the request with the DELETE verb to the object ID
DELETE /v1/blogs/6dce1470-1900-11ed-8039-af237906caea
If the object you are deleting exists, you will receive a 200 OK
and a message telling you that you have deleted the object:
{
"msg": "resource 6dce1470-1900-11ed-8039-af237906caea removed"
}
If, however, you attempt to delete it again or try to delete an object that doesn't exist, you'll get the 404 Not Found
error
{
"error": "resource not found",
"errorCode": "404"
}
Errors
Note: this document is in early stages and error standards are evolving
Errors are formatted in a JSON response such as
{
"error" : "the reason for this error"
}
If an object is requested that doesn't exist you should receive a 404
response code and a human readable error. When you try to access an object or collection not described in your API you should receive a 400
Bad Request.