Programming Model

The Programming Model

The GO API generally follows the REST principles for HTTP-based interfaces. This means:

  • Functionality is organized around a set of resource types, e.g. Projects and Users, with
    resource endpoints named accordingly, e.g. /projects and /users.
  • Functions that operate on the resources are implemented with the four HTTP verbs: GET (read),
    POST (create), PUT (update), and DELETE.
  • Each resource object in the system, such as a particular Project or AOI, is uniquely
    represented by an id string.
  • For operations which return results, the HTTP response payloads are always formatted as JSON
    objects.
  • For operations which require input data, the HTTP request payloads are also always formatted as
    JSON objects.
  • All operations require a user token to authenticate you to the Go API.

In the next sections, we will demonstrate each of the four HTTP verbs using the Project resource
type and its associated /projects endpoint.

POST

In the GO API, a Project represents work to be performed, such as "count the number of cars in
downtown San Francisco for every month in 2018". Projects will be described in more detail in a
later section, but for now we're going to just create a simple, empty project with no detection
algorithm, area of interest, or other parameters.

To create resources, we always use the POST verb. We will use the curl command to POST
a JSON-formatted request payload to the GO API's /projects endpoint. The payload will just
contain the name of our project and a short description; we put this data a file named
http/post_project_body.json:

{
    "name": "looking_glass",
    "description": "the looking glass project"
}

The curl command to execute is:

curl -s -S \
    -H "Content-Type: application/json" \
    -H "X-Orbitalinsight-Auth-Token: $GO_API_TOKEN" \
    --data @http/post_project_body.json \
    -X POST \
    $GO_API_URL/projects

That operation will return a response payload similar to this:

{
  "data": {
    "algorithm_ids": [],
    "collaborator_ids": [],
    "created_ts": "2019-08-12T15:54:07.931000+00:00",
    "description": "the looking glass project",
    "id": "wc79nf6R1E-190812",
    "name": "looking_glass",
    "owner_id": "alice",
    "parent_project_id": null,
    "stage": "NOT_STARTED",
    "version_ids": [
      "wc79nf6R1E-190812-1.0.0"
    ]
  },
  "status": 201
}

(Again, here and in subsequent outputs, for clarity of exposition some fields are not shown.)

That returned JSON object contains a status field with the HTTP code of the operation
(201/OK), and a data field containing the new resource.

All GO API operations follow the convention of "wrapping" the actual resource data inside of a
larger object that contains certain metadata, like the status of the operation. We will have more
to say about wrapped objects in a later section; for now, just observe that your project was
created with the correct name (data.name) and description (data.description) and was
assigned an id (data.id).

GET

As seen in the previous section, the POST operation returned the resource object to us, but
let's assume we want to retrieve the object from the server again anyway. We use the GET verb
to retrieve resource objects. In this case, we will do a GET operation on the Project resource
endpoint, qualified with our project's id:

curl -s -S \
    -H "Content-Type: application/json" \
    -H "X-Orbitalinsight-Auth-Token: $GO_API_TOKEN" \
    -X GET \
    $GO_API_URL/projects/wc79nf6R1E-190812

The result is again a wrapped Project object, with the data field containing the same
information we got when we created the project:

{
  "data": {
    "algorithm_ids": [],
    "collaborator_ids": [],
    "created_ts": "2019-08-12T15:54:07.931000+00:00",
    "description": "the looking glass project",
    "id": "wc79nf6R1E-190812",
    "name": "looking_glass",
    "owner_id": "alice",
    "parent_project_id": null,
    "stage": "NOT_STARTED",
    "version_ids": [
      "wc79nf6R1E-190812-1.0.0"
    ]
  },
  "status": 200
}

We can also execute a command to retrieve all of our projects by using GET on the /projects
endpoint, with no qualifying id given:

curl -s -S \
    -H "Content-Type: application/json" \
    -H "X-Orbitalinsight-Auth-Token: $GO_API_TOKEN" \
    -X GET \
    $GO_API_URL/projects

The result will look like this:

{
  "data": [
    {
      "algorithm_ids": [
        "CAR_DETECTOR_ANALYSIS"
      ],
      "collaborator_ids": [],
      "created_ts": "2019-08-09T18:57:06.435000+00:00",
      "description": "the looking glass project",
      "id": "2M_JkbCs08-190809",
      "name": "looking_glass",
      "owner_id": "alice",
      "parent_project_id": null,
      "stage": "NOT_STARTED",
      "version_ids": [
        "2M_JkbCs08-190809-1.0.0"
      ]
    },
    "..."
  ],
  "list_attributes": {
    "limit": 100,
    "offset": 0,
    "total": 14
  },
  "status": 200
}

That wrapped result is a little different than the previous one. The data field contains a
list of Project objects (shortened here for clarity). The result also contains a
list_attributes field, which will be explained shortly.

PUT

To modify a resource, we use the PUT verb. Let's modify the description of our project using
PUT and our project's endpoint. First we create our payload file,
http/put_project_body.json:

{
    "description": "what she found there"
}

and then execute the curl command:

curl -s -S \
    -H "Content-Type: application/json" \
    -H "X-Orbitalinsight-Auth-Token: $GO_API_TOKEN" \
    --data @http/put_project_body.json \
    -X PUT \
    $GO_API_URL/projects/wc79nf6R1E-190812

The operation returns our project resource, with an appropriately updated description field:

{
  "data": {
    "algorithm_ids": [],
    "collaborator_ids": [],
    "created_ts": "2019-08-12T15:54:07.931000+00:00",
    "description": "what she found there",
    "id": "wc79nf6R1E-190812",
    "name": "looking_glass",
    "owner_id": "alice",
    "parent_project_id": null,
    "stage": "NOT_STARTED",
    "version_ids": [
      "wc79nf6R1E-190812-1.0.0"
    ]
  },
  "status": 200
}

DELETE

We are now done with our first project, so let's delete it from the system using the DELETE
verb and our project's endpoint:

curl -s -S \
    -H "Content-Type: application/json" \
    -H "X-Orbitalinsight-Auth-Token: $GO_API_TOKEN" \
    -X DELETE \
    $GO_API_URL/projects/wc79nf6R1E-190812

This operation returns a success status code but no data:

{
  "data": {},
  "status": 200
}

Now if we try to retrieve our project:

curl -s -S \
    -H "Content-Type: application/json" \
    -H "X-Orbitalinsight-Auth-Token: $GO_API_TOKEN" \
    -X GET \
    $GO_API_URL/projects/wc79nf6R1E-190812

we will get an error:

{
  "error": "InvalidRequest",
  "message": "Failed to fetch projects.",
  "status": 400
}

The Data Model

We've now seen enough examples that we can describe how to interpret wrapped response objects from
the GO API. The wrapper's format is:

{
    "status": "(integer)",
    "data": "(object or list of objects)",
    "list_attributes": {
        "limit": "(integer)",
        "offset": "(integer)",
        "total": "(integer)"
    },
    "error": "(string)",
    "message": "(string)"
}

First, all returned objects will contain a status field which will be an integer corresponding
to one of the standard HTTP response codes.

Second, if the status code indicates success (2xx), there will be a data field in the
object. When a single resource object is being returned, it will be the value of that data
field. When multiple resource objects are being returned, as in our GET /projects example, the
value of the data field will be a list containing the object resources.

Third, if a list is being returned in the data field, a list_attributes field will also be
present. The list_attributes object describes the list being returned in a way that allows you
to do “paginated” HTTP requests, e.g. “give me the first 50 Projects” and then “give me the next
50 Projects”. Pagination is discussed in a later section of this Guide.

Fourth, if the status code indicates an error has occurred (4xx or 5xx), the returned
object may have two additional, optional fields. The error field will be a short string
containing the error type. The message field will be human-readable description of the error.

In pseudo-code, wrapped response objects should be handled similar to this:

result = { ... }  # returned object from some HTTP operation
    
if result.status >= 200 and result.status <= 299:
     if type(result.data) == list:
         for item in result.data:
            print(item)
     else:
         print(result.data)
else:
     print(result.status)
     print(result.error)
     print(result.message)

HTTP Operation Notation

For the remainder of this document, we will not spell out the complete curl command lines and
instead use a more traditional, language-independent notation. The HTTP operations in the preceding
sections would be written like this:

POST /projects
    
    GET /projects/$P
    
    GET /projects
    
    PUT /projects/$P
    
    DELETE /projects/$P

Observe that we shorten the URL to only show the resource path, excluding the host name, and that
we use $ placeholders for the resource ids.