REST API Conventions
IDs and UIDs
IDsMany GroveStreams resources can identified externally by an ID. IDs can be assigned by users and by GroveStreams API calls and are optional. They can be any string with a limit of 512 characters. Examples of resource IDs are a device's serial number, a device's MAC address, or a device data stream's identifier such as "temperature".
UIDs
Each GroveStreams resource is identified internally by a Universally Unique Identifier (UID). UIDs are assigned by GroveStreams and are mandatory. A GroveStreams UID is a version 5 SHA-1 hashed universally unique identifier (UUID). No two GroveStreams objects have the same uid. Developers should NEVER create their own UIDs for their new GroveStreams entities. Always let GroveStreams create a new entity for you with a unique uid by appending "/new" to your GET URIs or leave the uid attribute blank during the PUT and GroveStreams will create one for you and return it with the entity that was inserted into the store.
A UID represented as a STRING data type takes 36 characters to represent. Here's an example of a UID: 3F2504E0-4F89-11D3-9A0C-0305E82C3301
A UID represented as a 16-byte (128 bit) number only takes 16 bytes.
The downside of UUIDs is that they are not easy for humans to work with because of the large number of characters and in the STRING format they consume a lot of bytes. So why do we use UUIDs for our internal entity identifiers versus say a unique LONG number?
- The global uniqueness of a UUID will allow GroveStream entities to be passed around without the worry of "id collisions".
- UUID generation scales. There is not a single uid
generator where a bottleneck can occur and we'll never run out of
UUIDs.
- The SHA-1 hash provides enough randomness to prevent a malicious user from guessing a uid.
- GroveStreams stores uids as 16 byte representations so
they're not consuming much disk space and index look-ups on 16
bytes isn't much slower than say an 8 byte LONG key - at least not
enough to outweigh the benefits of UUIDs.
- In a high performance large distributed store, such as
GroveStreams, entities need to be evenly partitioned across
hundreds of servers. UUIDs give our entity key indexes the
randomness needed for an even distribution across all servers. You
don't need to know exactly what this means - just know that it
allows you to insert and extract a lot of data very quickly.
Security
TokensA GroveStreams API token is an security identifier that is passed with an API call as a query string parameter or as a cookie. When passed as both a parameter and a cookie, GroveStreams will use the parameter token.
Tokens:
- org
- This is the uid of the organization the API call is for.
All organization calls need this token only if the session token
is used. api_key calls do not require the org token as the org is
inferred based on the organization the api_key resides within.
- session
- The session token is created during the POST login or
POST login_guest resource calls. The user credentials passed to
the login resource will be associated with the session uid to
determine access rights for each API call. Session tokens will
expire during long time periods between API calls.
- api_key
- The api_key token is used for cases where a user email
and password should not be hard-coded or stored in a file.
Api_keys should be used inside devices or external web pages that
make API calls to GroveStreams. Api keys can have very granular
API rights assigned to them and can be restricted from devices
with specific IP addresses or from specified domains. The api_key
token is not the
api_key resource UID, it is the api key's secret key. API keys
are created and managed by a GroveStreams organization owner. The
org token is not required when the api_key token is being used.
- "Authorization: Bearer **AccessToken**" HTML Header (OAuth 2.0)
- OAuth is used for cases where a user email
and password should not be hard-coded or stored in a file or stored on a device. OAuth should also be used when
each device should have its own
unique security token that expires and needs to be refreshed frequently. GroveStreams is an OAuth 2.0
authorization server and can be used by other APIs such as Amazon's Alexa for authentication. More information
can be found on the GroveStreams OAuth Page.
GroveStreams will use the api_key token for API calls passed with both an api_key and a session token.
SSL
GroveStreams supports SSL. Change http to https in the Resource URL to secure your calls to GroveStreams:
https://grovestreams.com/api
SSL encryption and decryption come with a performance cost. You will get better performance not using SSL if your data is not sensitive data and allows you to do so.
Date and Times
We refer to a date and time with millisecond precision as datetime throughout our API documentation. The GroveStreams API passes around datetimes as single LONG (8 bytes) data type values representing milliseconds since epoch January 1,1970 UTC. This allows for datetimes roughly +- 290 million years to millisecond precision from the epoch. Throughout the API documentation you'll see this format referred to as "epoch millis". Whenever a datetime is discussed in the documentation as a LONG data type it is safe to assume it is in "epoch millis" UTC format.Handling datetimes as "epoch millis" is common practice in the programming world as it simplifies datetime management and improves performance. Most of the major programming languages have a date or time library that handles the conversion to and from human readable datetimes and "epoch millis". GroveStreams is written in Java 6.0 and adheres to the JDK standards for managing datetimes.
GroveStreams has support for time zones, leap years and daylight savings time during datetime calculations. GroveStreams does not support leap seconds as most applications don't have a need for this, most computer clocks are not accurate enough to be able to reflect it and supporting it would impact performance.
Request and Response Formats
The GroveStreams API uses JSON for almost all of its request and response body formats. Why does GroveStreams rely mainly on JSON?- GroveStreams is all about performance and JSON is faster and more scalable than XML
- JSON, when formatted, is a standard and is human readable
- JSON is supported by all major programming languages, all major browsers and is easy to work with (see www.json.org)
Compression
The GroveStreams API supports compression for request/response
bodies. We highly encourage using compression as it will make your
product and GroveStreams more scalable.
Add a request header "Accept-Encoding :
gzip, deflate" to your request and GroveStreams will return your
request compressed.
Add a request header "Content-Encoding :
gzip" to your request when the body is compressed as gzip.
Sever-side Caching
The GroveStreams web servers will cache resource response requests for 10 seconds. This allows our servers to handle viral requests. The GroveStreams user interface frequently appends an argument called "_dc" with a unique number onto its API calls to avoid server caching for users with "Edit" rights.HTTP Request Errors
GroveStreams has two types of error codes. HTTP status codes and internal error codes. HTTP status codes come back as HTTP status code errors. GroveStreams internal error codes will be part of the response body along with a description of the actual error.GroveStreams Internal Error Codes
Grove Streams will map its internal error code with the following HTTP status codes:
Internal Error Code |
HTTP Status Code |
Description |
UNKNOWN_EXCEPTION | 500 |
Internal server error |
ENTITY_MISSING | 404 |
Resource not found |
SESSION_EXPIRED | 500 |
Session token expired due to inactivity. Watch for
SESSION_EXPIRED in the response body to determine if a user
should be re-authenticated. |
RATE_LIMIT_EXCEEDED |
403 |
Call rate limit has been
exceeded. |
ACCESS_DENIED | 403 |
session or api_key tokens do not have rights for the
action (PUT, POST, GET, DELETE) or resource (i.e. component,
cycle, unit, ...). |
ENTITY_VALIDATION_FAILURE | 422 |
Resource failed validation during a PUT or SAVE. This
error will also return a list of all validation warnings and
errors. |
CAPTCHA_VALIDATION_FAILURE | 422 |
Captcha challenge failed. |
REQUEST_VALIDATION_FAILURE | 400 |
Slightly different than an entity validation error.
Usually caused by malformed uid keys or other types of parsing
errors. |
EXPRESSION_PARSING | 500 |
Stream derivation expression parsing error. |
EXPRESSION_EVALUATION | 500 |
Stream derivation expression evaluation error. |
EXPRESSION_UNKNOWN | 500 |
Stream derivation unknown expression error. |
OAUTH_TOKEN_EXPIRED | 400 |
OAuth2 access token expired. |
OAUTH_INVALID_CLIENT | 401 |
OAuth2 invalid token. |
OAUTH_INVALID_GRANT | 400 |
OAuth2 invalid grant. |
List of HTTP status codes
Sample Request Error:
This is an example of the response body when a session has expired.
HTTP status code was: 401 Unauthorized
Response Body was:
{
"message": "Session expired.",
"errCode": "SESSION_EXPIRED",
"success": false
}
Sample Request Error:
This is an example of a "POST component" where the component definition had warnings and errors.
HTTP status code was: 422 Unprocessable Entity
Response Body was:
{
"message": "ERROR: '': Invalid name size. Range is
1 to 500 characters.<br>WARNING: '/Percent of Memory Used -
bytes/Variable/var1': Derived stream expression does not contain
dependent variable name 'var1'.<br>ERROR: '/Percent of Memory
Used (WOP) - bytes/Variable/free': Functions cannot be performed on
a stream base cycle.<br>",
"errCode":
"ENTITY_VALIDATION_FAILURE",
"validationResult": {
"validation": [
{
"message": "Invalid name
size. Range is 1 to 500 characters.",
"pathName": "",
"itemType": "component",
"valMsgType": "ERROR",
"itemUid":
"59d9d98d-bd17-4b7c-a99a-77b49fbad29b"
},
{
"message": "Derived
stream expression does not contain dependent variable name
'var1'.",
"pathName": "/Percent of Memory Used - bytes/Variable/var1",
"itemType": "stream",
"valMsgType": "WARNING",
"itemUid":
"c8886c4c-0b21-4722-b7ae-599c24374a1f"
},
{
"message": "Functions
cannot be performed on a stream base cycle.",
"pathName": "/Percent of
Memory Used (WOP) - bytes/Variable/free",
"itemType": "stream",
"valMsgType": "ERROR",
"itemUid":
"1999ddb7-25c0-4d5a-8835-b1c947049633"
}
]
},
"success": false
}