mjl > sherpa > specification
Intro | API documentation | Consuming | Specification | Implementations | FAQ | Why
Sherpa is still work in progress! It works well, but the specification might still change.

Specification

A Sherpa API is provided at a URL, for example https://www.sherpadoc.org/example/. Sherpa API's are designed to be easy to implement on the server side, and easy to use on the client (browser) side. A Sherpa API is usually implemented using a library, but writing Sherpa support directly into your application is also a viable option. This document describes how Sherpa API's work and what you must do to implement a Sherpa API.

Sherpa API's summarized:

This specification continues with the URL endpoints a Sherpa API must implement. We use sherpaweb's "Example API" as an example: https://www.sherpadoc.org/example/.

GET <URL>/sherpa.json

An API describes itself by a JSON file at called sherpa.json. Try opening it. It provides a document like the following.

{
    "id": "example",
    "title": "Example API",
    "version": "0.0.1",
    "sherpaVersion": 0,
    "baseurl": "https://www.sherpadoc.org/example/",
    "functions": [
        "requestCount",
        "_docs"
    ]
}

A GET on the API URL must return a JSON document (as shown above). All fields are required and must not be null.

Field Type Description
id string Short ID for this API. The JavaScript library stores the API object in a global variable with this name. Must match regular expression "[a-zA-Z][a-zA-Z0-9_]+"
title string Full human-readable name of this API.
version string Descriptive version string. Could be in the form of major.minor.patch. But a single API endpoint should not really have different "major" versions at different times. Incompatible API versions are best deployed at a new endpoint.
sherpaVersion int Version of the Sherpa specification. This specification is still work in progress, that's why it is still at version 0. In the future, backwards compatible changes (e.g. adding fields to the JSON object describing the API) may be made without increasing the version number. For incompatible changes, the version number will be increased. If a client library loads a Sherpa API with a version number is does not support (either too old or too new), it must generate an error.
baseurl string URL for this API.
functions array of string List of methods exported by the API. Parameter types and return types are not part of the API. Requiring specification of such types would make the API significantly more complex and much harder to keep programming language-independent. Most scripting languages would not make use of it anyway. The parameter and return value types should be specificied in the API documentation. Function names must match regular expression "[a-zA-Z_][a-zA-Z0-9_]+", though functions starting with an underscore have special meaning as described later.

GET <URL>/sherpa.js

This JavaScript library makes it trivial for frontend developers to start using a Sherpa API.

This library must set a global variable with the name of the "id" field from sherpa.json. This variable must be an object providing all functions exported by the API. Calling such a function from JavaScript must return a "thenable": an object with an attribute called then that has the signature "function(resolved, rejected) {...}". Resolved will be called with the result of a successful API call. Rejected will be called with an error object if the call failed. Error objects are described later in this document.

The thenable-objects can be transformed by setting the attribute _wrapThenable on the API object. By default, this is a function returning its parameter. Frontend developers may set this to a function that calls new Promise(thenable), for full promise-support.

The API object has a field _sherpa, containing the JSON document from sherpa.json.

POST <URL>/functionName

A HTTP POST to the API URL followed by the function name calls that function. The request body must be a JSON document with a params field, an array with parameters. An example:

{
    "params": [
	"test",
	123
    ]
}

The response is again a JSON document with fields result and/or error. A response must have at least one of those fields. Both can be present, but then one of them must be null.

On success, the result field contains the function return value. This value can be any valid JSON type, e.g. boolean, an array, an object, etc. The value of field "result" is passed as argument to the resolved function in the JavaScript library. An example:

{
    "result": ["limited", "imagination"]
}

On error, the error field contains an error object. An error object in turn contains at least the following fields:

An example error response:

{
    "error": {
        "message": "no permission to modify table X"
        "code": "permissionDenied"
    }
}

Error messages should start with a lower case letter and not end with a dot. This lets you easily combine (prepend/append) strings that create a full error message for display to the user.

For forward compatibility, Sherpa API developers should not provide function names starting with an underscore other than those specified in this document.

Error codes

HTTP status codes are not used to indicate success or failure. The POST should almost always return a status 200 "OK", so even if the function called returned an error. The exception is if the function name does not exist. In that case, the HTTP status should be 404 "File not Found". The rationale is that if an API disappears, or a programmer used an incorrect API URL, function calls would return status 404 as well, so Sherpa libraries should expect and gracefully handle 404's.

Sherpa defines several commonly used error codes, all starting with "sherpa":

sherpaHttpError
Unexpected HTTP-level error occurred, like incorrect HTTP response status code (i.e. not 200 and not 404).
sherpaBadFunction
Function does not exist in this API. This might be returned by the server, or generated by the client library code.
sherpaBadRequest
Bad request body. Invalid JSON, or missing "params"-field.
sherpaBadParams
Function was not called with the correct number/type of parameters.
sherpaBadResponse
The HTTP response status code indicated success, but the response could not be parsed (e.g. malformed JSON in the body).
sherpaClientError
A client-side library error has occurred.
sherpaServerError
A server-side error has occurred. Typically an unhandled error while executing the function call.
sherpaNoAPI
No API seems to be available at this URL (it returned a 404).

GET <URL>/functionName

Instead of using HTTP POST, you can also call a function with a HTTP GET. An optional query string parameter body (defaulting to no parameters) in the same format as the POST JSON body can be set to pass parameters. The response is the same as for HTTP POST requests.

JSONP is also supported: If the query string parameter callback is present, the repsonse will be a JavaScript file that calls the specified callback with the response object as parameter.

GET <URL>/

A GET on the Sherpa API base URL can provide free-form, useful information about the API. A typical response is to show a minimal page explaining this is a Sherpa API, and that has the JavaScript API loaded for quick experimentation, followed by a link to the documentation and more information about Sherpa in general.

See sherpaweb's example: www.sherpadoc.org/example/.

Additional requirements

The endpoints above are all that is needed to implement a Sherpa API. This section lists additional requirements.

The HTTP responses must include CORS-headers allowing use from other domains. This means the HTTP OPTIONS method must also be supported.

All data in Sherpa is UTF-8. This includes JSON request and response bodies, and JavaScript. Sherpa API's should check that the Content-Type of POST function calls is application/json. If the "charset" is set, it should be "utf-8". In the future, other content-types might be treated differently.

All Sherpa function call responses should disallow caching by setting a response header "Cache-Control: no-store".

Sherpa API's don't have to support HTTP HEAD requests on function URLs.

Documentation

A Sherpa API provides documentation through the function _docs. It is a function like any other and as such can be called through a HTTP POST. The result is a JSON document that must adhere to a simple format. Sherpaweb renders this document. The object is a toplevel "documentation"-object, that looks like this:

{
    "title": "Title for this section of the documentation",
    "text": "Body of the documentation for this section, as markdown.",
    "functions": [
        {
            "name": "requestCount",
            "text": "requestCount(): int\n\nReturn the number of times this function has been called since this API was last restarted.",
        },
        ...
    ],
    "sections": [
       ... nested "documentation"-objects ...
    ]
}

Documentation can be hierarchically arranged. With a top-level documentation object introducing the API. And further topics divided in sections, each with their functions. The full list of provided functions must be specified in sherpa.json. The documentation provides functions explicitly so tools like sherpaweb can place the functions in the right section and provide functionality to call a function.

Both the main text and function text fields should be markdown. This allows you to easily create structure, or even include HTML for richer documentation.

The text-field in a "function"-object should start with a line containing the function signature, showing its parameters with types, and the return type (in free-form).