API Description

The Basics

The API is primarily composed by the following elements:

  • Objects:

    • Entity
    • Image
    • Video
    • Frame
    • DescriptorSet
    • Descriptor
    • BoundingBox
  • Connections: express relationship between objects.

  • Commands: perform specific actions on objects (Add/Find/Update/Delete) and the database (GetStatus).

  • Blocks: modify the behavior of the commands.

Queries

ApertureDB expect users to send queries over one of its connectors [REF].

A query is composed by:

  • a string formatted as a JSON array of one or more commands, and
  • [optional] an “array of blobs”.

The array of blobs is used to send and receive (usually, but not always, encoded) visual data. Each element of the array can contain one of the following elements:

  • An encoded Image (either a complete image, a frame, or a bounding box)
  • An encoded Video
  • A feature vector (which is in itself an array of floating point values)
  • A user-defined blob (for Entity objects)

A query is received by ApertureDB, processed, and a response is returned. A response is composed in the same manner as a query:

  • a string formatted as a JSON array with the same number of elements as the query, and
  • [optional] an “array of blobs”, if blobs are returned.

A query is processed transactionally in ApertureDB: either all the commands are correctly executed, or none of them are executed and an error status is returned.

Here is an example of a query and its corresponding response, using the Python connector:

from aperturedb import Connector

db = Connector.Connector("mydatabase.mydomain.com")

query = [ {

    "AddEntity": {
        "class": "Person",
        "properties": {
            "name":      "Luis",
            "email":     "luis@aperturedata.io"
            "unique_id": 30
        }
    }
},{
    "AddImage": {
        "properties": {
            "description":   "profile photo",
            "year_captured": 2020
        }
    }
} ]

# Because we are inserting an image, a blob is expected
# in the blob_array

fd = open("luis_profile_photo.jpg", "rb")
image = fd.read()

blobs_array = []
blobs_array.append(image)

# Execute the transaction
json_response, blobs = db.query(query, blobs_array)

# json_response is a dictionary, we use a helper function to
# print the JSON array nicely.
print(db.get_last_response_str())

Output:

[ {
    "AddEntity": {
        "status": 0
    }
}, {
    "AddImage": {
        "status": 0
    }
}
]

In this example, no blob is returned as a result of the query, and the “blobs” variable will be an empty array.

Here is another example where the opposite happens: no blob is sent as part of the query, but blobs are returned as part of the response:

from aperturedb import Connector

db = Connector.Connector("mydatabase.mydomain.com")

query = [ {
    "FindImage": {
        "constraints": {
            "year_captured": [">=", 2020]
        }
        "results": {
            "list": ["year_captured", "description"]
        }
    }
}]

# Execute the transaction
json_response, blobs = db.query(query)

# json_response is a dictionary, we use a helper function to
# print the JSON array nicely.
print(db.get_last_response_str())

# Check the number of returned images:
print("Number of returned images:", len(blobs))

Output:

[ {
    "FindImage": {
        "status": 0,
        "entities": [
            {
                "year_captured": 2020,
                "description": "profile photo"
            },
            {
                "year_captured": 2021,
                "description": "party with friend"
            }
        ]
    }
}]

Number of returned images: 2

In this case, the array of blobs (“blobs” variable) will have two elements, each of which is an encoded image.

Once the data usage and data collection/preprocessing requirements of an application are understood, it is time to connect the application to ApertureDB server because ApertureDB offers the unique capabilities of storing metadata in a structured graph database as well as takes care of dealing with the actual data through one unified API, described on this page. We provide C++ and Python client libraries for linking with any application to enable communication with ApertureDB.

Using the API

We define a set of JSON-based API calls that allow an application to interact with ApertureDB and exploit its strengths. The table below lists the calls provided, followed by their JSON specification. Our commands can be constructed using some basic building blocks and return results with certain meanings.

A user application will use the ApertureDB API by defining metadata conforming to the query protocol described below and passing along blobs. The client side ApertureDB library provides a simple query function that accepts a JSON string with commands and an array or vector of blobs. Internally, the library wraps the query string and blob in a protobuf (choice for now) and sends it to ApertureDB. It also receives a similarly wrapped response from ApertureDB and returns it to the client. The responses will require JSON parsing on the client side, starting with the metadata string that will indicate how to interpret blobs. We could substitute protobuf here with explicitly sending a string followed by sending binary data OR provide a link within the string block to indicate where to download the actual data from. For now, we will go with the image as a blob in the response message, and have the library in the client unpack the image and place it in a folder. In the future, we will consider adding a flag to indicate that ApertureDB will return urls and generate copies to download in the server.

Keywords

class

The class represents an abstraction specific for the application, and can be either applied to an Entity or to a Connection. Simple examples of classes for Entity objects can be “Person”, “Car”, Animal”, “Brain-Scan”. Simple examples of classes for a Connection objects can be “MadeVisit”, to represent a connection between, say, an Entity of the class a “Person” and an Entity of the class”Visit”.

The class is case sensitive and are matched exactly when searching for entities of the same class.

The class can only be specified for Entities and Connections, as the rest of the objects (like Image or Video) have an implicit class given the nature of said objects.

The class is specified as a JSON String.

The implicit classes for built-in objects are the following:

Object class
Image VD:IMG
Video VD:VID
BoundingBox VD:ROI
DescriptorSet VD:DESCSET
Descriptor VD:DESC

_ref

The _ref value is used to specify a reference to the added entity to be used later (usually, to create a connection to another object) within the same transaction.

The _ref is specified as an Integer number between 1 and 10000.

unique

The unique keyword is used in Find* commands to specify the expectation that only a single Object should be returned as a result. If more than one object is found, the command returns an error code.

The unique value is specified as a JSON Boolean

_uniqueid

Every object has an automatically generated global id associated with it. _uniqueid can be used in the “list” in the properties block to retrieve the _uniqueid of the returned objects.

When used in a constraints block, only the “==” and the “in” operators are supported.

Note: FindConnection does not support the use of _uniqueid.

Supported Formats/Encodings

ApertureDB offers a variety of formats and encoding for images and videos, which can be specified as parameters of the related commands. For instance, a format can be specified when inserting and retrieving Images and BoundingBoxes. Similarly, a codec and/or a container can be specified when inserting and retrieving a Video.

We detail the format and codecs supported as parameters, as follows:

The format parameter can be used to re-encode an image in a format different from the one stored in ApertureDB when retrieving the image, or to re-encode the image before inserting it.

The format parameter is specified as a JSON String.

The supported format are:

  • “jpg”
  • “png”
  • “tdb”

The codec parameter can be used to re-encode a video. When inserting a Video (AddVideo), it will perform the transcoding before persisting it. When retrieving a Video (FindVideo), it will perform the operation on-the-fly, without modifying the stored video.

The supported codecs are:

  • xvid
  • h263
  • h264

The codec parameter can be used to change the container of a video. When inserting a Video (AddVideo), it will perform the change before persisting it. When retrieving a Video (FindVideo), it will perform the change on-the-fly, without modifying the stored video.

The supported video containers are:

  • mp4
  • avi
  • mov