Overview

SparqFest is developing a RESTful API for you to use in building your own applications.

Written by George Reese

Last published at: April 22nd, 2023

The SparqFest is a RESTful API that uses standard HTTP methods and response codes and accepts JSON payloads while providing JSON responses. This API is currently in development, but you can use the documentation in this section to familiarize yourself with its core principles and architecture. We intend to roll out version 2 in March 2023 (version 1 is the current, internal API).

API Structure

You can make calls against our API using any language or tools like curl. There is no special signing process an we require only one header for authorization. You may optionally specify other headers to make it easier to deal with the complexity of SparqFest date management.

Endpoints

We currently have 5 API endpoints. Which endpoint you use depends on the festival with which you are interacting:

  • api-lon.sparqfest.live (London)
  • api-mon.sparqfest.live (Montreal)
  • api-nca.sparqfest.live (Northern California)
  • api-par.sparqfest.live (Paris)
  • api-sao.sparqfest.live (São Paulo)

All interaction must happen over HTTPS. HTTP is not supported for our API.

URI Structure

Our resources are divided into namespaces and APIs. At the very top is the name of the target festival and a namespace with one or more APIs underneath. Each API, in turn, may have any number of resources.

The only SparqFest namespace exposed to clients is “festival”.

A SparqFest URL thus looks like:

https://[endpoint]/api/[version]/[app]/[namespace]/[path-to-resouce]

The current version of the API is v2.

Thus, the endpoint for interacting with submitters (part of the "account" API) for a festival hosted in Montreal is (let's name the app “example-fest”):

https://api-mon.sparqfest.live/api/v2/example-fest/festival/account/people/submitter

Specifying Resources

A given resource may be accessible via multiple points in the URI hierarchy. In particular, objects that are associated with a specific edition of a festival may be accessed through the edition or by providing the edition as a query parameter. For example, selections belong to a specific edition of the festival. The API does not allow you to list all selections. Instead, you may only list selections for a specific edition.

You have two options for listing selections:

  1. GET /api/v2/:application/festival/programming/selection?edition_id=:edition_id
  2. GET /api/v2/:application/festival/edition/:edition_id/programming/selection

Both approaches are equally valid and neither is preferred. When referencing a specific selection, however, you can skip the edition information:

GET /api/v2/:application/festival/programming/selection/:selection_id

The edition-specific URI also works:

/api/v2/:application/festival/edition/:edition_id/programming/selection/:selection_id

To simplify the learning curve, we will use the edition-specific URIs for edition-specific resources in all documentation. Feel free, however, to use the shortcuts where available.

Discovery

We support one special resource outside the domain of any specific festival, our lookup API.

Only Approved Clients

The discovery mechanism described in this section is available only to approved clients. If you are building a general-purpose client for all SparqFest customers, we recommend you seek approval for your application. If you are building an application for a specific festival, however, you do not need this lookup functionality.

 

You can discover the location of any festival by calling any endpoint and requesting the resource lookup?festival=[name]:

https://api-mon.sparqfest.live/v2/lookup?festival=Minnesota+WebFest&client_id=[client_id]

You should pass in the x-authorization header with the bearer token set to your client secret.

This lookup is simply a name search on supported festivals that will allow the use of your client. By default, a festival allows all clients.

The rules for the search are:

  • A search with fewer than 3 characters will return an empty list unless the app name matches exactly
  • Searches are done on app name, festival name, and festival host
  • Searches are case-insensitive
  • If a festival is restricting clients, it will appear in the results only if your client is allowed

Is the festival site located in the sparqfest.live domain?

It's easy to guess the name of any festival hosted in the sparqfest.live domain without doing a lookup: myfestival.sparqfest.live => myfestival

 

Minnesota WebFest, for example is a festival hosted in Northern California at https://www.mnwebfest.org. You can query any endpoint query any of the following queries and get information back on Minnesota WebFest:

  • festival=mnwf
  • festival=Minnesota
  • festival=Minnesota+WebFest
  • festival=www.mnwebfest.org

The purpose of the lookup functionality is to make it possible for you to offer search capabilities to your users so they can find the festival they want to interact with.

The response looks like this:

curl -H "x-authorization: Bearer CLIENT_SECRET" "https://api-mon.sparqfest.live/api/v2/lookup?festival=Snowfall&client_id=CLIENT_ID"
                                                                                                                                                                                                                         
{
	"festivals": [
		{
			"id": "0d985121-f578-45ea-b4fd-60ef996f0c28", 
			"application": "example", 
			"name": "Snowfall", 
			"short_name": "Snowfall",
			"web": "example.sparqfest.live", 
			"api": "api-nca.sparqfest.live", 
			"abbreviation": "SNW", 
			"title": {"en": "Welcome to Snowfall Online Events"},
			"base_uri": "https://api-nca.sparqfest.live/api/v2/example",
			"href": "https://api-nca.sparqfest.live/api/v2/example/festival",
		}
	], 
	"status_code": 200, 
	"timestamp": 1677697508195
}

Canonical and Convenience URIs

Every resource has at least one canonical URI that can be used to operate on it. 

In some instances, you may fetch that resource from other points in the API structure. We call these URIs “convenience URIs”. Typically, convenience URIs exist when the canonical URI is buried inside a deep structure. For example, the canonical URI for a submission category is:

https://endpoint/api/v2/[app]/festival/edition/[edition_id]/submitting/submission_category/[category_id]

The length of the URI is not what is at issue. The issue is that you need to know both the edition ID and the category ID in order to construct the canonical URI. You can therefore reach that submission category via the convenience URI:

https://endpoint/api/v2/[app]/festival/submitting/submission_category/[category_id]

Convenience URIs work only for requests that operate on a known ID. They do not work for things like creating a new submission category because the system needs to know the edition into which you are creating the category.

Methods

We use DELETE, GET, HEAD, PATCH, POST, and PUT methods to perform operations that match the common behavior of those HTTP methods.

DELETE

Deletes the names resource. What it means to “delete” a resource depends on the semantics associated with that resource. Depending on the resource in question, a DELETE can return either a 202 or a 204. 

Most resources will return a 204. If the delete operation cannot be performed immediately, however, it will return a 202 with a job ID to use in tracking the progress of the operation.

A DELETE never returns a 404. If the requested resource does not exist, the system simply returns a 204.

GET

Requests one or more resources. 

A GET request against a general endpoint will result in all instances of that resource to which the user has access being returned. In some cases, you can have the server pre-filter the results through the use of query parameters. You may also request only the IDs to be returned by setting the parameter ids_only=true.

A GET request for a specific ID will result in the return of just that once instance. 

Successful GET requests return HTTP 200. A request for a resource that does not exist will result in a 404.

HEAD

We use the HEAD operation to support two critical functions to increase client performance and reduce bandwidth usage.

All HEAD requests use the same API semantics as a GET. The primary difference is that no body is returned, just a header with information about the resource. Thus, a 204 is a successful HEAD request instead of a 200.

A HEAD request against a general endpoint like festival/account/people/submitter will return a header key of x-count that gives you the number of records that would be returned had you issued a GET.

A HEAD request against a specific ID will return a head with a header key of x-ts-modified that tells you the UTC Unix timestamp (milliseconds since the epoch) when the ID was last modified. This call can save you from doing unnecessary re-fetches of resources.

PATCH

The PATCH method is for updating select attributes of a resource. When replacing an entire object, you should use PUT instead. A PATCH is always performed against a specific ID.

A successful PATCH will generally return a 204 with no body. On occasion, it may return a 202 with an asynchronous job ID in the body. These exceptions are documented for each resource and are required when an update cannot be done immediately. You may use the job ID to track the process of the update.

The most common error during a PATCH is a 400 error. This error indicates that one or more of the values being updated did not properly validate.

POST

In contrast with PATCH, POST is always performed against a general endpoint. The purpose of an HTTP POST is to create a new resource with a new ID. 

The result of a successful POST is a 201 with the ID of the newly created item in the body of the response as well as an href that you can use immediately to fetch the resource.

As with PATCH, 400 is the most common error and it indicates that one or more of the fields did not validate, or you did not pass in a required field.

PUT

PUT operations are rare in the SparqFest API. They are typically used to replace a complex attribute for a given resource. For example, a resource might have a “posters” attribute with a bunch of keys identifying different kinds of posters. To replace the landscape poster, you would make a PUT to [resource_url]/[resource_id]/posters/landscape to replace the current value of the landscape poster. If there is no current value, the PUT will create that value.

A successful PUT always returns a 204 with no body. An error of 400 indicates that the value you have provided is not appropriate.

Status Codes and Errors

We use standard HTTP codes across the board in the SparqFest API. Status codes 200-299 represent success conditions, 400-499 represent user errors, and 500-599 represent system errors.

The API does not generally return any 3xx responses except where the user is directly interacting with the API (for example, during the OAuth process). Those are not situations that you as a developer need to worry about.

Error Formats

The standard error format for most error codes includes the following fields:

  • language
  • error
  • message

Some error messages may contain additional fields to help further processing. 

On occasions, typically where we need to comply with another specification, we will return a different format. Those exceptions are documented.

Here's a sample response for a 401 error:

{
	"language": "en",
	"error": {
		"en": "You must login before performing this operation.",
		"es": "Debe iniciar sesión antes de realizar esta operación."
	},
	"message": "You must login before performing this operation."
}

Success Codes

Particular care should be paid when executing a request that may take a long time. Any method that cannot execute within a 30 second window will return an HTTP 202 with a job ID for you to track. Where this can happen, it is documented for the resource in question.

It is consistent with this version of the API to change the response for any DELETE, POST, PUT, or PATCH to a 202 without warning. It is therefore a best practice for all such requests to check the status code for a 201, 202, or 204 and act accordingly.

200 OK

The result of HTTP a successful GET request in which a JSON body is part of the response. The only exception to this rule is for the OAuth authentication flows where the OAuth standard demands a 200 response to some other method.

201 CREATED

The result of a successful HTTP POST resulting in the creation of a new object. In this situation, the body of the response will contain a JSON object with two fields:

  • id - the system-generated ID for the newly created object
  • href - the canonical endpoint you can use to fetch the newly created object

You do not need to store the HREF returned to you. It is simply the same URL you would expect for fetching the resource. We provide it, however, as a convenience to reduce the need for you to construct the URL as the most common thing done after creating a resource is fetching it.

202 ACCEPTED

We return a 202 for any HTTP DELETE, PATCH, POST, or PUT that might take more than 30 seconds to process. The JSON body will contain a single attribute, “id”, that serves as a tracking ID for you to track the progress of the operation.

204 NO CONTENT

Requests that result in no body being returned (for example, a delete) return an HTTP 204 on success.

Client Errors

The most common status codes for client errors are 400 and 405. Though technically an “error code”, 404 is typically reserved to legitimate requests that result in no object.

400 BAD REQUEST

This response most often occurs when you PATCH, POST, or PUT data that does not meet validation requirements. If, for example, you make a POST that fails to include a required field, you will receive a 400 with a payload indicating what field failed validation.

When your request fails validation, it stops processing and returns the 400 immediately with just one field in the payload. It does not go through the work of validating all fields.

The body includes two attributes:

  • field - the name of the field that failed validation
  • error - a multi-lingual description of the error
  • message - a description of the error in the primary language of the festival

Example:

{
	"language": "en",
	"field": "name",
	"error": {
		"en": "The field name is a required field.",
		"es": "El campo name es un campo obligatorio."
	},
	"message": "The field name is a required field."
}

What languages show up in the error field vary from festival to festival. The field names are not translated.

Exception: If you pass in an invalid_scope during an OAuth request, the system will return a 400 with the following body:

{
	"error": "invalid_scope",
	"error_description": "The requested scope is invalid, unknown, or malformed."
}

This distinction complies with the OAuth specification.

401 UNAUTHORIZED

The request you attempted requires a logged-in user for processing and you are not yet authenticated. To make this request succeed, you must first authenticate. 

This response will contain a body in the standard error format.

Exception: If an operation fails during the OAuth authentication process due to issues with your client (passing in a bad secret, for example), that request will return a 401 with the following body:

{
	"error": "invalid_client",
	"error_description": "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method."
}

When performing a GET on an endpoint that returns multiple results, the HTTP response can be a 200 with an empty list instead of a 401. This variance exists because there are some APIs that are open to the public for search, but it returns a filtered list of only objects under that endpoint to which there is public access. If none of the objects are publicly accessible, but the endpoint itself is, then the response is 200 with an empty list. 

403 FORBIDDEN

The request you attempted has been denied either because the user does not have access to that resource or the scopes granted to your client by that user do not allow the operation. 

This response will contain a body in the standard error format.

404 NOT FOUND

The requested resource does not exist. There is no body with this error code.

405 METHOD NOT ALLOWED

You attempted an operation against a resource that does not support that operation. For example, if you call a DELETE on the festival resource, you will receive a 405 since the API does not support the ability to delete festivals. 

This method contains a standard error body which generally is a message saying this request is not supported. 

SparqFest Errors

SparqFest errors should not happen, but they do. When they do happen, we will return an error with a status code in the 500-599 range.

The most common code is a 500.

500 INTERNAL SERVER ERROR

Some error happened in the system that we failed to catch. This can result from a bug in the code to one of our backend systems returning an error to us. Another cause of a 500 error can be the failure of a third-party service with which we are interacting.

500 is also the error code we return when we just don't know what is going on, but it's not good.

The body of this error will contain a standard error, though the messaging in the error may not match the specified language since the error message may be coming from an external service.

502 BAD GATEWAY

Something bad is happening in our Amazon Web Services environment. The most common causes of this error are AWS outages and work being done on our infrastructure.

This error does not come from SparqFest, but from Amazon Web Services. Therefore the content of the response body can come in any format. 

503 SERVICE UNAVAILABLE

The request cannot be executed right now. This can happen because our servers are overwhelmed or because we are being told by a third-party needed to execute the operation that they cannot execute it for us. You can wait a brief pause a retry an operation resulting in a 503 error.

The body of this error will contain a standard error, though the messaging in the error may not match the specified language since the error message may be coming from an external service.

504 GATEWAY TIMEOUT

If a request takes more than 30 seconds to perform, it will time out and you will receive a 504 error. This error comes from Amazon Web Services and does not conform to our error format.

You should retry any request that results in this error code.

5xx (PASS THROUGH FROM EXTERNAL SERVICE)

For many API calls, we make our own API calls to other services. These services can fail and give us their own error messages with their own error codes. If the error is actionable by you, we pass this error through to you. 

On occasion, third-parties may also send back 4xx error codes when they should be sending 5xx errors. We try to translate when we are able. 

Request Headers

The SparqFest API leverages two potential request headers, neither is required for non-authenticated requests. The x-authorization header is required for any request that demands authenticated access.

 x-authorization

This header is described in more detail in the discussions on authentication. It contains your OAuth access token:

GET [ENDPOINT]
x-authorization: Bearer ABC123DEF567

x-timezone

A discussion on festival time management is beyond the scope of this overview, but this optional header helps with those calculations. It should be the local time zone of for the current location of the user:

GET [ENDPOINT]
x-timezone: America/Chicago

Request and Response Bodies

All request and response bodies are JSON unless otherwise noted.