Web Services Guide¶
This is a client guide to using Sondra’s automatically generated REST APIs. The primary audience for this guide are application developers who wish to understand the conventions that Sondra uses. Each API has full autogenerated documentation and self-describing schemas that support standard REST access for objects (documents), filtering collections, and “method calls” which implement more complex server-side application logic than simple CRUD operations support, e.g. login and logout support for Authentication.
Making calls¶
The following section describes conventions for making web-service requests and interpreting their responses.
Requests¶
Requests are made using standard HTTP and HTTPS calls. Most browsers, jQuery, and as well as cURL and wget should support all manner of calls supported by these. When a body is required (or optional) for a call, the body is assumed to be JSON. All calls return JSON by default, if no format specifier is supplied as part of the call.
Alternative Request Syntax¶
Query parameters can always be supplied to modify the call being made, even if the call also supplies a JSON object in the body. Additionally, long query strings may be overwhelming or poorly supported on some browsers. For the situation in which a query string is too long to be manageable, a special body JSON can be supplied as the body of a POST request. The JSON must adhere to the following schema:
{ "type": "object",
"required": ["__q"],
"properties": {
"__q": {
"type": "object",
"description": "Query string parameters"
},
"__method": {"enum": ["GET","POST","PUT","PATCH","DELETE"]},
"__objs": {
"description": "The object or list of objects that constitute the request body",
"oneOf": [
{"type": "object"},
{"type":"array", "items": {"type": "object"}}
]
}
}
Responses¶
Except for autogenerated help, all formats return some manner of JSON. Some methods and aggregations return “bare” values e.g. a string, integer, or number. Bare values are not valid JSON, so these values will be wrapped in a dummy object according to their type:
{"_": <value>}
In addition, because empty responses are not handled well by most browsers, a null return from a service call will result in an empty JSON object, {}.
In general, all webservices are self-describing with auto-generated help and JSON-schemas. JSON-schemas are very slightly enhanced to improve the interpretation of linkages across collections. See Schemas for more information.
Errors¶
Errors in production (non DEBUG) code will be returned as JSON in the very near future. For now they are returned in whatever form the underlying web framework (e.g. Flask, Django, etc) returns exceptions. JSON encoded errors may have their own schemas defined at the Suite level, however at a minimum they conform to this schema:
{
"type": "object",
"properties": {
"errorName": {"type": "string"},
"requestedUrl": {
"type": "string",
"format": "url"
},
"format": {
"enum": ["json", "geojson", "help", "schema"]
}
"requestType": {
"enum": [
"application", "collection", "document",
"application_method", "collection_method", "document_method"
]
}
"requestMethod": {"enum": ["GET", "POST", "PATCH", "PUT", "DELETE"]},
"message": {"type": "string"}
}
}
Authentication¶
Please make sure to expose and call APIs over HTTPS. JWT security relies on encryption to be effective.
APIs that support authentication as supplied by Sondra must include the auth app as part of their API. The auth app has auto-generated documentation that covers it entirely, and it is not in the scope of this document to replicate that here. However, there are a few basic points covered again here for login, logout, and making authenticated webservice calls.
Logging In¶
This method issues a new JSON Web Token and caches it as valid for the time being (300 seconds by default).
URL Form:
http://localhost:5000/auth.login
Request object properties
- username (str)
- The username (often the same as email address).
- password (str)
- The user’s password.
Returns an encoded JSON Web Token as a bare object {"_": <jwt>}
Logging Out¶
This method revokes a JSON Web Token, invalidating it.
URL Form:
http://localhost:5000/auth.logout
Request object properties
- token (string, JWT)
- The currently valid JWT
Returns an empty response, the blank object {}.
Renewing a Token¶
This method renews the token for a currently logged in user.
URL Form:
http://localhost:5000/auth.renew
Returns a new JWT that has been freshly issued.
Making Authenticated Requests¶
Once you obtain a JWT by logging in, you may use this JWT to authenticate requests. JWTs in Sondra by default must be renewed (see above, Renewing a Token every five minutes (300 seconds). This can be changed on the server by deriving a new subclass of the Auth app.
Query Parameters
- _auth (string, JWT)
- This is valid on all requests for authenticated application, suites, collections, and documents. The JWT, as returned by auth.login (Logging In) is the value of _auth.
Authentication Service Exceptions¶
AuthenticationError [1]¶
Occurs when a request is made that requires authentication to complete, and the call was made anonymously.
ValidationError¶
Occurs when a request is made with a token that is expired or whose issuer is not recognized.
ParseError¶
Occurs when a request is made with a token that is corrupted or unreadable for any reason.
Schemas¶
Schemas follow JSON-Schema format and use the jsonschema package to validate documents that will be added to persistent collections. JSON-Schema is strictly followed, with only a few minor additions.
- refersTo
Applies to schema type “string” and provides a prefix for linking foreign keys to other API endpoints, specifically other collections. The value of refersTo is itself a string in URL format and must refer to a collection. Single objects will be validated against this string in the same manner as JSON-schema’s pattern specifier. The difference between refersTo and pattern is that refersTo must be a valid URL and must also be a collection API endpoint. This allows code to make certain assumptions (such as formats and metadata endpoints) about the endpoint, whereas a pattern can be any valid regular expression.
See Collection Python documentation for more details.
Suite schema¶
URL Form:
http://localhost:5000/schema
The suite schema is a “dummy schema” that contains suite-wide definitions that are referenced by other schemas within a suite’s set of enclosed applications. Additionally, it contains another property:
- applications - whose value is a list of URLs to the schema of all applications in the suite.
Application schema¶
URL Form:
http://localhost:5000/application;schema
The application schema is a “dummy schema” that contains application-wide definitions that are referenced by schemas within a application’s set of enclosed collections and documents. Additionally, it contains two properties:
- collections - whose value is a list of URLs to the schema of all collections in the suite.
- methods - whose value is an object whose property names are method slugs, and whose property values are the request and response schema of all methods that attach at the application level.
Collection schema¶
URL Form:
http://localhost:5000/application/collection;schema
The collection schema defines the validation set for all documents within a single collection. Additionally, it contains two properties:
- methods - whose value is an object whose property names are method slugs, and whose property values are the request and response schema of all methods that attach at the collection level.
- documentMethods - whose value is an object whose property names are method slugs that can be called at the individual document level, and whose property values are the request and response schema of all methods that attach at the document level.
Document schema¶
URL Form:
http://localhost:5000/application/collection/primary-key;schema
The document schema mirrors the collection schema and mainly exists for completeness. Generally you should use the collection schema. In addition, it contains a property:
- methods - whose value is an object whose property names are method slugs, and whose property values are the request and response schema of all methods that attach at the document level.
Method schemas¶
URL Form:
http://localhost:5000/application.method;schema
http://localhost:5000/application/collection.method;schema
http://localhost:5000/application/collection/primary-key.method;schema
Requesting a schema directly on the method call returns the named schema from the “methods” (or documentMethods) section of the schema for that class (application, collection, or document).
Auto-generated help¶
URL Form:
http://localhost:5000/help
http://localhost:5000/application;help
http://localhost:5000/application.method;help
http://localhost:5000/application/collection;help
http://localhost:5000/application/collection.method;help
http://localhost:5000/application/collection/primary-key;help
http://localhost:5000/application/collection/primary-key.method;help
Help for every level of an API heirarchy can be retrieved by using the format specifier ;help at the end of the URL. Help is completely auto-generated from docstrings (using Markdown, reStructuredText, or Google formats, see suite docs) in the definition of each Python class definition and each schema that makes up the API. Help is available in HTML format. Currently localized help is not supported for APIs, but this may happen in the future.
Operations on Collections¶
Collections support the standard REST CRUD operations: Create, List, Update, and Delete.
URL Form:
http://localhost:5000/application/collection;format
POST: Create¶
Create a new document. Raises an error if the document already exists in the database.
Request¶
Accepts JSON in the post body. If the JSON is an array, then each document in the array is added in turn. If it is an document, then that document will be added.
Response¶
The response will be a JSON array of the URLs of added documents.
Errors¶
- KeyError if any of the POSTed documents already exist in the database by primary key.
- ValidationError if any of the POSTed documents do not fit the collection schema.
GET: List and Filter¶
Retrieve a listing of documents in the given format, or retrieve an HTML form for entering a new document. Note that filtering parameters described here can also be accessed via POST using the Alternative Request Syntax.
Request¶
- flt (JSON object or list, see Simple filters)
- A (list) of simple filter(s), which will be performed in sequence to narrow the result.
- geo (JSON object, see Spatial filters)
- A spatial filter which will be used to limit the spatial extent of results.
- agg (JSON object, see Aggregations)
- An object that describes aggregations to perform on the query
- start (int)
- The index of the first document to return.
- limit (int)
- The maximum number of documents to return.
- end (int)
- The index of the last document to return.
Simple filters¶
Simple filters are JSON objects that narrow down the documents being returned. Currently these do not support the use of indexes, but they may in the future. They are performed by successive applications of the “filter” method in ReQL.
Each filter must conform to the following JSON specification:
{ "op": "<operator>",
"args": { "lhs": <field-name>, "rhs": <value> }}
Operators
- ==: Equality check. Equivalent to .filter(r.row(lhs).eq(rhs))
- !=: Inequality check. Equivalent to .filter(r.row(lhs).eq(rhs))
- >: Strictly greater than. Equivalent to .filter(r.row(lhs).gt(rhs))
- >=: Greater or equal to. Equivalent to .filter(r.row(lhs).ge(rhs))
- <: Strictly less than. Equivalent to .filter(r.row(lhs).lt(rhs))
- <=: Less than or equal to. Equivalent to .filter(r.row(lhs).le(rhs))
- match: Regex match. Equivalent to .filter(r.row(lhs).match(rhs))
- contains: Containment check. Equivalent to .filter(r.row(lhs).contains(rhs))
- has_fields: Field presence check. Equivalent to .filter(r.row(lhs).has_fields(rhs))
Spatial filters¶
Spatial filters narrow down the returned documents using RethinkDB’s geographic operators. There must be at least one spatial property defined on the Collection or the inclusion of a spatial filter will result in an error. Spatial filters must conform to the following JSON schema:
{
"type": "object",
"required": ["op", "test"],
"properties": {
"against": {"type": "string"},
"op": {"$ref": "#/definitions/op"},
"test": {"type": "object", "description": "GeoJSON geometry or distance object"}
},
"definitions": {
"op": {
"type": "object",
"required": ["name"],
"properties": {
"name": {"enum": ["distance", "get_intersecting", "get_nearest"])
"args": {"type": "array"},
"kwargs": {"type": "object"}
}
}
}
Spatial operators
Spatial operators all work exactly the same as their corresponding RethinkDB commands. The “test” is a geometry to test against. Geometries should be described in GeoJSON. Distance isn’t very useful yet, since it returns distances without primary keys. Against is the geometric index to test against. If left blank, it is the default geometry field.
Only one spatial filter may be supplied.
Aggregations¶
Aggregations transform returned documents and often supply summaries of data. Aggregtions must conform to the following JSON schema:
{
"type": "object",
"required": ["name"],
"properties": {
"name": {"enum": [
"with_fields",
"count",
"max",
"min",
"avg",
"sample",
"sum",
"distinct",
"contains",
"pluck",
"without",
"has_fields",
"order_by",
"between"]
},
"args": {"type": "array"},
"kwargs": {"type": "object"}
}
}
Again, these operators work the same way as their RethinkDB counterparts. Consult the ReQL API documentation for more information. Only one aggregation may be supplied.
Response¶
Unless an aggregation was specified, the response is a list of documents that conform to the collection schema. If an aggregation (or distance) was specified, then the result will be a bare JSON object, {"_": <value>}.
PUT. Replace¶
Replace an document currently in the database with a new document.
Query Params
- durability (hard | soft)
- Same as RethinkDB insert.
- return_changes (boolean=True)
- Same as RethinkDB insert.
Request¶
Accepts JSON in the PUT body. If the JSON is an array, then each document in the array is replaced in turn. If it is an document, then that document will be added.
Response¶
The response will be the same as the RethinkDB response to an insert.
Errors¶
- KeyError if any of the PUT documents do not already exist in the database by primary key.
- ValidationError if any of the PUT documents do not fit the collection schema.
PATCH. Update¶
Update document(s) in place. Raises an error if a supplied document does not already exist in the database. The semantic difference between a PATCH and a PUT request is that the PATCH request retrieves the document first and updates that document with the values provided in the PATCH. The primary key must be present in each replacement document for a lookup to occur.
Query Params
- durability (hard | soft)
- Same as RethinkDB insert.
- return_changes (boolean=True)
- Same as RethinkDB insert.
Request¶
Accepts JSON in the PATCH body. Like PUT and POST, PATCH can be, if the JSON is an array, then each document in the array is updated in turn. If it is an document, then that document will be updated.
Response¶
The response will be the same as the RethinkDB response to an insert.
Errors¶
- KeyError if any of the PATCH documents do not already exist in the database by primary key, or if a primary key is not supplied.
- ValidationError if any of the PUT documents do not fit the collection schema.
DELETE. Delete¶
Delete documents in place. Raises an error if the document doesn’t exist in the first place, or if the entire collection would be deleted, unless specifically requested to delete everything.
Request¶
Accepts a JSON list of primary keys or index keys in the body, OR accepts simple and spatial filters.
Query Params
- durability (hard | soft)
- Same as RethinkDB insert.
- return_changes (boolean=True)
- Same as RethinkDB insert.
- delete_all (true | false)
- Set this flag on the query string if you want to
- flt (JSON object or list, see Simple filters)
- A (list) of simple filter(s), which will be performed in sequence to narrow the deletion.
- geo (JSON object, see Spatial filters)
- A spatial filter which will be used to limit the spatial extent of the deletion.
- index (str index name)
- If index is supplied then the keys to be deleted are assumed to be index keys instead of primary keys.
Response¶
The same as the RethinkDB delete response.
Errors¶
- KeyError if any of the DELETE documents do not already exist in the database by primary key.
- PermissionError if no filters or primary keys have been supplied (all documents in the collection would be deleted) and delete_all is not true.
Operations on Documents¶
Documents support the standard REST CRUD operations: Create, Detail, Update, Replace, and Delete.
URL Form:
http://localhost:5000/application/collection/primary-key;format
POST and PUT. Replace¶
Replace the referenced document with the given document. Raises an error if the primary key exists and conflicts with the primary key of the document.
Request¶
Accepts a single JSON object in the body.
Query Params
- durability (hard | soft)
- Same as RethinkDB insert.
- return_changes (boolean=True)
- Same as RethinkDB insert.
Response¶
The response will be the same as RethinkDB’s save method.
Errors¶
- KeyError if the POSTed document already exists in the database by primary key.
- ValidationError if the POSTed document does not fit the collection schema.
PATCH. Update¶
Update document in place. Raises an error if a supplied document does not already exist in the database or if a primary key is present in the supplied document and conflicts with the document key. The semantic difference between a PATCH and a PUT or POST request is that the PATCH request retrieves the document first and updates that document with the values provided in the PATCH.
Query Params
- durability (hard | soft)
- Same as RethinkDB save.
- return_changes (boolean=True)
- Same as RethinkDB save.
Request¶
Accepts a single JSON in the PATCH body.
Response¶
The response will be the same as the RethinkDB response to an save.
Errors¶
- KeyError if the PATCH document does not already exist in the database by primary key or conflicts with the existing key.
- ValidationError if the PATCH document does not fit the collection schema.
DELETE. Delete¶
Delete an document. Raises an error if the document doesn’t exist to be deleted.
Request¶
The request body should be bare.
Query Params
- durability (hard | soft)
- Same as RethinkDB insert.
- return_changes (boolean=True)
- Same as RethinkDB insert.
Response¶
The same as the RethinkDB delete response.
Errors¶
- KeyError if the DELETE document does not already exist in the database by primary key.
Complete URL scheme reference¶
- /schema
- GET. Suite-wide schema. Typically this includes definitions that are common for the entire suite, including valid filter names, dates, times, geography, and localization.
- /help
- GET. Suite-wide help with links to applications. Help is autogenerated from schema definitions and from docstrings in the class.
- /{application};schema
- GET. Application-wide schema.
- /{application};help
- GET. Application-wide help with links to collections. Help is autogenerated from schema definitions and from docstrings in the class.
- /{application}.{method-name};schema
- GET. Method schema for application.
- /{application}.{method-name};help
- GET. Autogenerated help for the method.
- /{application}.{method-name};json
- GET, POST. Applicationlication method call.
- /{application}/{collection};schema
- GET. Collection schema.
- /{application}/{collection};help
- GET. Autogenerated help for the collection.
- /{application}/{collection};json
- GET, POST, PUT, DELETE. Get, Add, Update, or Delete documents of the collection, respectively.
- /{application}/{collection};geojson
- GET, DELETE. Get or Delete documents of the collection, respectively, but as GeoJSON FeatureCollections.
- /{application}/{collection}.{method-name};schema
- GET. Method schemas for a collection-wide method.
- /{application}/{collection}.{method-name};help
- GET. Autogenerated help for the collection method.
- /{application}/{collection}.{method-name};json
- GET, POST. Call a collection method.
- /{application}/{collection}/{document};schema
- GET. Same as /{application}/{collection};schema, generally speaking.
- /{application}/{collection}/{document};help
- GET. Autogenerated help for document methods.
- /{application}/{collection}/{document};json
- GET, POST, PUT, DELETE. Get, Replace, Update, or Delete document, respectively.
- /{application}/{collection}/{document};geojson
- GET, DELETE. Get or Delete document, respectively, but as a GeoJSON Feature.
- /{application}/{collection}/{document}.{method-name};schema
- GET. Document method schema.
- /{application}/{collection}/{document}.{method-name};help
- GET. Document method help.
- /{application}/{collection}/{document}.{method-name};json
- GET, POST. Document method call.
[1] | (1, 2) The following exceptions are not yet supported, but will be very soon. Currently all authorization and authentication errors raise a standard Python PermissionError on exception. |