Snapper Grape 2.8 - About the API

The API, as specified here, corresponds to the implementation in Snapper Grape version 2.8

Please also see documentation for data types returned from the API.

Snapper Grape’s API is RESTful. It is stateless and as simple as possible. The API’s resources are defined by their URIs, and the actions are defined by the http verb used. ”GET” fetches a resource, ”PUT” updates a resource, ”POST” adds a new resource, and ”DELETE” removes the resource. The API is not fully built along these verbs, however. Only the API calls defined in this document are available.

The API always returns a JSON response (see separate document about API types).

Usage and cross-site scripting

The API is designed to be used both in server-to-server communication, and client-to-server, using javascript. Cross-site scripting is supported by the API, but you may need to contact Snapper Net Solutions in order to set this up correctly. 

Consistent return object

Snapper Grape API always returns a JSON object with the following attributes:

valid

Boolean
Indicates whether or not an error occured, or if the operation requested was successful (if request is POST/PUT/DELETE).

message

String
Explanatory string about what has/has not happened. Can be ignored, but can be useful both for debugging purposes, or for conveying to end users what has happened in case of errors.

In addition, the API returns an array of the objects we are asking for. If the call we are requesting is ”/api/personcompetences”, the JSON will have an attribute ”personcompetences”, which holds an array of 0 or more PersonCompetence objects.

All objects described in this document has two representations: simple and full. The simple representation is used when returning lists of objects, or when objects are listed in the context of another object. The full representation is used only when a single object is requested via the objects ID (ie. ”/api/personcompetences/123”). However, the object is still inside an array, for consistency.

So when an API call is defined to return ”Array of person objects”, the actual JSON return will look something like this:

{
    valid: true,
    message: "Returning list of persons",
    persons: [
        {person_id: 123, firstname: "Ola", …},
        {person_id: 124, firstname: "Kari", …}
    ]
}


Quick example

We provide a quick and dirty example of logging in, fetching details for the logged in person, and updating the person’s name. The code is written in javascript, and uses jQuery.

// First, log in
var loginData = {
    user_name: "iamauser",
    password: "passwordsshouldbestrong",
    login: 1
};
$.ajax("/api/login", {data: loginData, dataType: "json", type: "POST", success: afterLogin});

function afterLogin(returnData) {
    // We just assume login was OK. Should check several things here.
    // Fetch person's data
    $.ajax("/api/person", {dataType: "json", type: "GET", success: function(data) {
        console.log(data);
    }});

    // Update person's name
    var updatePersonData = {
        person_data: {
            firstname: "Ola",
            lastname: "Nordmann"
        }
    }
    $.ajax("/api/person", {data: updatePersonData, dataType: "json", type: "PUT", 
      success: function(data) {
        console.log(data);
    }});
}

Errors and error codes

Errors returned from the Snapper Grape API, follow the consistent object described above, but adds a errorcode attribute. The errorcode attribute follows more or less the standard http response codes in the 400/500-family. The errors and codes defined here are only the ones that are handled explicitly by the API other errors (server error, not found), will give a proper http error response, with http code set to 500/404/etc, according to the webserver’s fancy.

Example error response:

{"errorcode": 401, "message": "Must be superuser to access this resource", "valid": False}

 

Field customization

The Snapper Grape API provides a way to customize the attributes that are presented in the return object(s). We follow Google's way of doing things, as described here.

In its simplest form, a client can provide a parameter (GET or POST, depending on the verb used) called "fields" with comma separated attribute names. For a /api/persons call, it could look like this: /api/persons?fields=firstname,lastname,email. The result would be a list of person objects with only the attributes firstname, lastname and email exposed (however, the attribute id is always included):

persons: [
    {
        id: 1,
        firstname: "Person", 
        lastname: "One", 
        email: "personone@snapper.no"
    },
    {
        id: 2,
        firstname: "Person", 
        lastname: "Two", 
        email: "persontwo@snapper.no"
    }
]

A more complicated version would be to include the organisation attribute, which is itself an array of objects. Using parentheses, the client can customize that object's attributes too. The call /api/persons?fields=firstname,lastname,email,organisations(name,email) would yield:

persons: [
    {
        id: 1,
        firstname: "Person", 
        lastname: "One", 
        email: "personone@snapper.no",
        organisations: [
            {
                id: 1,
                name: "Snapper Net Solutions",
                email: "post@snapper.no"
            }
        ]
    },
    {
        id: 2,
        firstname: "Person", 
        lastname: "Two", 
        email: "persontwo@snapper.no",
        organisations: []
    }
]

This applies to all fields and all return types described under Types.

Objects with sub-objects of the same type

For object types that have a attributes containing objects (list or single object) of the same type as the main object (Competences, Events, etc, most common as a "children" attribute, but other attributes follow the same principle), the API has two ways of figuring out which fields to use:

  1. Explicitly defined fields for the attribute in question. In the same way as for other sub-objects, the client can define the individual fields to be presented for the children objects: children(title,email)
  2. Implicitly defined fields. If the attribute is not defined in the fields parameter, the sub-objects will be presented with the same set of fields as for the main object.

In other words, there is no way to explicitly define the fields for the main object, but have the children be presented with the default simple or full views.