RESTful API

Imbo uses a RESTful API to manage the stored images and metadata. Each image is identified by a public key (the “username”) and an MD5 checksum of the file itself. The public key and the image identifier will be referred to as <user> and <image> respectively for the remainder of this document. For all cURL examples imbo will be used as a host name. The examples will also omit access tokens and authentication signatures.

Content types

Currently Imbo responds with images (jpg, gif and png), JSON and XML, but only accepts images (jpg, gif and png) and JSON as input.

Imbo will do content negotiation using the Accept header found in the request, unless you specify a file extension, in which case Imbo will deliver the type requested without looking at the Accept header.

The default Content-Type for non-image responses is JSON, and for most examples in this document you will see the .json extension being used. Change that to .xml to get XML data. You can also skip the extension and force a specific Content-Type using the Accept header:

$ curl http://imbo/status.json

and

$ curl -H "Accept: application/json" http://imbo/status

will end up with the same content-type. Use application/xml for XML.

If you use JSON you can wrap the content in a function (JSONP) by using one of the following query parameters:

  • callback
  • jsonp
  • json
$ curl http://imbo/status.json?callback=func

will result in:

func(
  {
    "date": "Mon, 05 Nov 2012 19:18:40 GMT",
    "database": true,
    "storage": true
  }
)

Resources

In this section you will find information on the different resources Imbo’s RESTful API expose, along with their capabilities:

Status resource

Imbo includes a simple status resource that can be used with for instance monitoring software.

$ curl http://imbo/status.json

results in:

{
  "timestamp": "Tue, 24 Apr 2012 14:12:58 GMT",
  "database": true,
  "storage": true
}

where timestamp is the current timestamp on the server, and database and storage are boolean values informing of the status of the current database and storage drivers respectively. If both are true the HTTP status code is 200 OK, and if one or both are false the status code is 500. When the status code is 500 the status message will inform you whether it’s the database or the storage driver (or both) that is having issues.

Typical response codes:

  • 200 OK
  • 500 Internal Server Error

User resource

The user resource represents a single user on the current Imbo installation.

GET /users/<user>

Fetch information about a specific user. The output contains basic user information:

$ curl http://imbo/users/<user>.json

results in:

{
  "publicKey": "<user>",
  "numImages": 42,
  "lastModified": "Wed, 18 Apr 2012 15:12:52 GMT"
}

where publicKey is the public key of the user, numImages is the number of images the user has stored in Imbo and lastModified is when the user last uploaded an image or updated metadata of an image.

Typical response codes:

  • 200 OK
  • 304 Not modified
  • 404 Not found

Images resource

The images resource represents a collection of images owned by a specific user.

GET /users/<user>/images

Get information about the images stored in Imbo for a specific user. Supported query parameters are:

page
The page number. Defaults to 1.
limit
Number of images pr. page. Defaults to 20.
metadata
Whether or not to include metadata in the output. Defaults to 0, set to 1 to enable.
from
Fetch images starting from this Unix timestamp.
to
Fetch images up until this timestamp.
$ curl "http://imbo/users/<user>/images.json?limit=1&metadata=1"

results in:

[
  {
    "added": "Mon, 10 Dec 2012 11:57:51 GMT",
    "extension": "png",
    "height": 77,
    "imageIdentifier": "<image>",
    "metadata": {
      "key": "value",
      "foo": "bar"
    },
    "mime": "image/png",
    "publicKey": "<user>",
    "size": 6791,
    "updated": "Mon, 10 Dec 2012 11:57:51 GMT",
    "width": 1306
  }
]

where added is a formatted date of when the image was added to Imbo, extension is the original image extension, height is the height of the image in pixels, imageIdentifier is the image identifier (MD5 checksum of the file itself), metadata is a JSON object containing metadata attached to the image, mime is the mime type of the image, publicKey is the public key of the user who owns the image, size is the size of the image in bytes, updated is a formatted date of when the image was last updated (read: when metadata attached to the image was last updated, as the image itself never changes), and width is the width of the image in pixels.

The metadata field is only available if you used the metadata query parameter described above.

Images in the array are ordered on the added field in a descending fashion.

Typical response codes:

  • 200 OK
  • 304 Not modified
  • 404 Not found

Image resource

The image resource represents specific images owned by a user.

GET /users/<user>/images/<image>

Fetch the image identified by <image> owned by <user>. Without any query parameters this will return the original image.

$ curl http://imbo/users/<user>/images/<image>

results in:

<binary data of the original image>

Typical response codes:

  • 200 OK
  • 304 Not modified
  • 400 Bad Request
  • 404 Not found

Image transformations

Below you can find information on the transformations shipped with Imbo along with their parameters.

border

This transformation will apply a border around the image.

Parameters:

color
Color of the border in hexadecimal. Defaults to 000000 (You can also specify short values like f00 (ff0000)).
width
Width of the border in pixels on the left and right sides of the image. Defaults to 1.
height
Height of the border in pixels on the top and bottom sides of the image. Defaults to 1.
mode
Mode of the border. Can be inline or outbound. Defaults to outbound. Outbound places the border outside of the image, increasing the dimensions of the image. inline paints the border inside of the image, retaining the original width and height of the image.

Examples:

  • t[]=border
  • t[]=border:mode=inline
  • t[]=border:color=000
  • t[]=border:color=f00,width=2,height=2
canvas

This transformation can be used to change the canvas of the original image.

Parameters:

width
Width of the surrounding canvas in pixels. If omitted the width of <image> will be used.
height
Height of the surrounding canvas in pixels. If omitted the height of <image> will be used.
mode
The placement mode of the original image. free, center, center-x and center-y are available values. Defaults to free.
x
X coordinate of the placement of the upper left corner of the existing image. Only used for modes: free and center-y.
y
Y coordinate of the placement of the upper left corner of the existing image. Only used for modes: free and center-x.
bg
Background color of the canvas. Defaults to ffffff (also supports short values like f00 (ff0000)).

Examples:

  • t[]=canvas:width=200,mode=center
  • t[]=canvas:width=200,height=200,x=10,y=10,bg=000
  • t[]=canvas:width=200,height=200,x=10,mode=center-y
  • t[]=canvas:width=200,height=200,y=10,mode=center-x
compress

This transformation compresses images on the fly resulting in a smaller payload.

Parameters:

quality
Quality of the resulting image. 100 is maximum quality (lowest compression rate).

Examples:

  • t[]=compress:quality=40

Warning

This transformation currently only works as expected for image/jpeg images.

convert

This transformation can be used to change the image type. It is not applied like the other transformations, but is triggered when specifying a custom extension to the <image>. Currently Imbo can convert to:

  • jpg
  • png
  • gif

Examples:

  • curl http://imbo/users/<user>/images/<image>.gif
  • curl http://imbo/users/<user>/images/<image>.jpg
  • curl http://imbo/users/<user>/images/<image>.png

It is not possible to explicitly trigger this transformation via the t[] query parameter.

crop

This transformation is used to crop the image.

Parameters:

x
The X coordinate of the cropped region’s top left corner.
y
The Y coordinate of the cropped region’s top left corner.
width
The width of the crop in pixels.
height
The height of the crop in pixels.

Examples:

  • t[]=crop:x=10,y=25,width=250,height=150
desaturate

This transformation desaturates the image (in practice, gray scales it).

Examples:

  • t[]=desaturate
flipHorizontally

This transformation flips the image horizontally.

Examples:

  • t[]=flipHorizontally
flipVertically

This transformation flips the image vertically.

Examples:

  • t[]=flipVertically
maxSize

This transformation will resize the image using the original aspect ratio. Two parameters are supported and at least one of them must be supplied to apply the transformation.

Note the difference from the resize transformation: given both width and height, the resulting image will not be the same width and height as specified unless the aspect ratio is the same.

Parameters:

width
The max width of the resulting image in pixels. If not specified the width will be calculated using the same aspect ratio as the original image.
height
The max height of the resulting image in pixels. If not specified the height will be calculated using the same aspect ratio as the original image.

Examples:

  • t[]=maxSize:width=100
  • t[]=maxSize:height=100
  • t[]=maxSize:width=100,height=50
resize

This transformation will resize the image. Two parameters are supported and at least one of them must be supplied to apply the transformation.

Parameters:

width
The width of the resulting image in pixels. If not specified the width will be calculated using the same aspect ratio as the original image.
height
The height of the resulting image in pixels. If not specified the height will be calculated using the same aspect ratio as the original image.

Examples:

  • t[]=resize:width=100
  • t[]=resize:height=100
  • t[]=resize:width=100,height=50
rotate

This transformation will rotate the image clock-wise.

Parameters:

angle
The number of degrees to rotate the image (clock-wise).
bg
Background color in hexadecimal. Defaults to 000000 (also supports short values like f00 (ff0000)).

Examples:

  • t[]=rotate:angle=90
  • t[]=rotate:angle=45,bg=fff
sepia

This transformation will apply a sepia color tone transformation to the image.

Parameters:

threshold
Threshold ranges from 0 to QuantumRange and is a measure of the extent of the sepia toning. Defaults to 80

Examples:

  • t[]=sepia
  • t[]=sepia:threshold=70
thumbnail

This transformation creates a thumbnail of <image>.

Parameters:

width
Width of the thumbnail in pixels. Defaults to 50.
height
Height of the thumbnail in pixels. Defaults to 50.
fit
Fit style. Possible values are: inset or outbound. Default to outbound.

Examples:

  • t[]=thumbnail
  • t[]=thumbnail:width=20,height=20,fit=inset
transpose

This transformation transposes the image.

Examples:

  • t[]=transpose
transverse

This transformation transverses the image.

Examples:

  • t[]=transverse

PUT /users/<user>/images/<image>

Store a new image on the server.

The body of the response contains a JSON object containing the image identifier of the resulting image:

$ curl -XPUT http://imbo/users/<user>/images/<checksum of file to add> --data-binary @<file to add>

results in:

{
  "imageIdentifier": "<image>"
}

where <image> can be used to fetch the added image and apply transformations to it. The output from this method is important as the <image> in the response might not be the same as <checksum of file to add> in the URI in the above example (which might occur if for instance event listeners transform the image in some way before Imbo stores it).

Typical response codes:

  • 200 OK
  • 201 Created
  • 400 Bad Request

DELETE /users/<user>/images/<image>

Delete the image identified by <image> owned by <user> along with all metadata attached to the image.

$ curl -XDELETE http://imbo/users/<user>/images/<image>

results in:

{
  "imageIdentifier": "<image>"
}

where <image> is the image identifier of the image that was just deleted (the same as the one used in the URI).

Typical response codes:

  • 200 OK
  • 404 Not found

Metadata resource

Imbo can also be used to attach metadata to the stored images. The metadata is based on a simple key => value model, for instance:

  • category: Music
  • band: Koldbrann
  • genre: Black metal
  • country: Norway

Metadata is handled via the meta resource in the URI, which is a sub-resource of <image>.

GET /users/<user>/images/<image>/meta

Get all metadata attached to <image> owned by <user>. The output from Imbo is an empty list if the image has no metadata attached, or a JSON object with keys and values if metadata exists:

$ curl http://imbo/users/<user>/images/<image>/meta.json

results in:

[]

when there is not metadata, or for example

{
  "category": "Music",
  "band": "Koldbrann",
  "genre": "Black metal",
  "country": "Norway"
}

if the image has metadata attached to it.

Typical response codes:

  • 200 OK
  • 304 Not modified
  • 404 Not found

PUT /users/<user>/images/<image>/meta

Replace all existing metadata attached to <image> owned by <user> with the metadata contained in a JSON object in the request body. The response body contains a JSON object with the image identifier:

$ curl -XPUT http://imbo/users/<user>/images/<image>/meta.json -d '{
    "beer":"Dark Horizon First Edition",
    "brewery":"Nøgne Ø",
    "style":"Imperial Stout"
}'

results in:

{
  "imageIdentifier": "<image>"
}

where <image> is the image that just got updated.

Typical response codes:

  • 200 OK
  • 400 Bad Request
  • 404 Not found

POST /users/<user>/images/<image>/meta

Edit existing metadata and/or add new keys/values to <image> owned by <user> with the metadata contained in a JSON object in the request body. The response body contains a JSON object with the image identifier:

$ curl -XPOST http://imbo/users/<user>/images/<image>/meta.json -d '{
    "ABV":"16%",
    "score":"100/100"
}'

results in:

{
  "imageIdentifier": "<image>"
}

where <image> is the image that just got updated.

Typical response codes:

  • 200 OK
  • 400 Bad Request
  • 404 Not found

DELETE /users/<user>/images/<image>/meta

Delete all existing metadata attached to <image> owner by <user>. The response body contains a JSON object with the image identifier:

$ curl -XDELETE http://imbo/users/<user>/images/<image>/meta.json

results in:

{
  "imageIdentifier":"<image>"
}

where <image> is the image identifier of the image that just got all its metadata deleted.

Typical response codes:

  • 200 OK
  • 400 Bad Request
  • 404 Not found

Authentication

Imbo uses two types of authentication mechanisms out of the box. It requires access tokens for all GET and HEAD requests made against all resources (with the exception of the status resource), and a valid request signature for all PUT, POST and DELETE requests made against all resources that support these methods. Both mechanisms are enforced by event listeners that is enabled in the default configuration file.

Access tokens

Access tokens for all read requests are enforced by an event listener that is enabled per default. The access tokens are used to prevent DoS attacks so think twice (or maybe even some more) before you remove the listener. More about how to remove the listener in Event listeners.

The access token, when enforced, must be supplied in the URI using the accessToken query parameter and without it all GET and HEAD requests will result in a 400 Bad Request response. The value of the accessToken parameter is a Hash-based Message Authentication Code (HMAC). The code is a hash of the URI itself (hashed with the SHA-256 algorithm) using the private key of the user as the secret key. Below is an example on how to generate a valid access token for a specific image using PHP:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
$publicKey  = '<user>';         // The public key of the user
$privateKey = '<secret value>'; // The private key of the user
$image      = '<image>';        // The image identifier

// The URI
$url = sprintf('http://example.com/users/%s/images/%s', $publicKey, $image);

// Add some transformations
$transformations = array(
    't[]=thumbnail:width=40,height=40,fit=outbound',
    't[]=border:width=3,height=3,color=000',
    't[]=canvas:width=100,height=100,mode=center'
);
$query = implode('&', $transformations);

// Data for the HMAC
$url .= '?' . $query;

// Generate the token
$accessToken = hash_hmac('sha256', $url, $privateKey);

// Output the URI with the access token
echo $url . '&accessToken=' . $accessToken;

If you request a resource from Imbo without a valid access token it will respond with a 400 Bad Request. If the event listener enforcing the access token check is removed, Imbo will ignore the accessToken query parameter completely. If you wish to implement your own form of access token you can do this by implementing an event listener of your own (see Custom event listeners for more information).

Signing write requests

Imbo uses a similar method when authenticating write operations. To be able to write to Imbo the user agent will have to specify two request headers: X-Imbo-Authenticate-Signature and X-Imbo-Authenticate-Timestamp, or two query parameters: signature and timestamp. X-Imbo-Authenticate-Signature/signature is, like the access token, an HMAC (also using SHA-256 and the private key of the user), and is generated using the following elements:

  • HTTP method (PUT, POST or DELETE)
  • The URI
  • Public key of the user
  • GMT timestamp (YYYY-MM-DDTHH:MM:SSZ, for instance: 2011-02-01T14:33:03Z)

These elements are concatenated in the above order with | as a delimiter character, and a hash is generated using the private key of the user. The following snippet shows how this can be accomplished in PHP when deleting an image:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
$publicKey  = '<user>';                 // The public key of the user
$privateKey = '<secret value>';         // The private key of the user
$timestamp  = gmdate('Y-m-d\TH:i:s\Z'); // Current timestamp
$image      = '<image>';                // The image identifier

// The URI
$url = sprintf('http://example.com/users/%s/images/%s', $publicKey, $image);

// The method to request with
$method = 'DELETE';

// Data for the hash
$data = $method . '|' . $url . '|' . $publicKey . '|' . $timestamp;

// Generate the token
$signature = hash_hmac('sha256', $data, $privateKey);

// Request using request headers

$context = stream_context_create(array(
    'http' => array(
        'method' => $method,
        'header' => array(
            'X-Imbo-Authenticate-Signature: ' . $signature,
            'X-Imbo-Authenticate-Timestamp: ' . $timestamp,

        ),
    ),
));
file_get_contents($url, false, $context);

// or, request using query parameters

$context = stream_context_create(array(
    'http' => array(
        'method' => $method,
    ),
));
$url = sprintf('%s?signature=%s&timestamp=%s',
               $url,
               rawurlencode($signature),
               rawurlencode($timestamp));

file_get_contents($url, false, $context);

Imbo requires that X-Imbo-Authenticate-Timestamp/timestamp is within ± 120 seconds of the current time on the server. Both the signature and the timestamp must be URL-encoded when used as query parameters.

As with the access token the signature check is enforced by an event listener that can also be disabled. If you want to implement your own authentication paradigm you can do this by creating a custom event listener.

Errors

When an error occurs Imbo will respond with a fitting HTTP response code along with a JSON object explaining what went wrong.

$ curl "http://imbo/users/<user>/images/<image>.jpg?t\[\]=foobar"

results in:

{
  "error": {
    "code": 400,
    "message": "Unknown transformation: foobar",
    "date": "Wed, 12 Dec 2012 21:15:01 GMT",
    "imboErrorCode":0
  },
  "imageIdentifier": "<image>"
}

The code is the HTTP response code, message is a human readable error message, date is when the error occurred on the server, and imboErrorCode is an internal error code that can be used by the user agent to distinguish between similar errors (such as 400 Bad Request).

The JSON object will also include imageIdentifier if the request was made against the image or the metadata resource.

If the user agent specifies a nonexistent username the following occurs:

$ curl http://imbo/users/<user>.json

results in:

{
  "error": {
    "code": 404,
    "message": "Unknown public key",
    "date": "Mon, 13 Aug 2012 17:22:37 GMT",
    "imboErrorCode": 100
  }
}

if <user> does not exist.