JSON API (OpenAPI)

JSON API

The JSON API is a path-based JSON API, described by an OpenAPI (opens in a new tab) 3.1 spec, that accepts and returns plain JSON. Actions defined in your schema become JSON endpoints like /api/json/<actionName>.

You can download the OpenAPI 3.1 spec for your JSON API from the API explorer page in the Keel console by clicking on the "API definitions" button in the top-right of the page.

Downloading an OpenAPI spec from the Keel console

Types

The built-in Keel types are mapped to JSON types in the following way:

Keel typeJSON type
Textstring
Numbernumber
Booleanboolean
Timestampstring (ISO8601 format)
Datestring (ISO8601 format)

Enums

Enums defined in your Keel schema are represented as strings in both inputs and responses

enum Category {
  Sports
  Finance
  Politics
}
 
model Post {
  fields {
    category Category
  }
  actions {
    create newPost() with (category)
  }
}

Optional inputs

If an input is marked as optional in your Keel schema then it is valid to completely omit it from the request, otherwise it must be provided.

JSON schema validation

Requests made to your JSON APIs are validated against a JSON schema (opens in a new tab) for that action. If the request does not pass validation the API will return an HTTP 400 along with a list of vaidation errors.

Example of a validation error
{
  "code": "ERR_INVALID_INPUT",
  "message": "one or more errors found validating request object",
  "data": {
    "errors": [
      {
        "error": "Invalid type. Expected: string, given: integer",
        "field": "id"
      }
    ]
  }
}

Creating a new record

You can define an action for creating a new record in your Keel schema using the create action type. In the JSON API these actions accept the write inputs (the ones after with) and return the newly created record.

schema.keel
model Profile {
  fields {
    username Text @unique
    bio Text
  }
  actions {
    create createProfile() with (username, bio)
  }
}

Reading a single record

You can define an action for reading a single record in your Keel schema using the get action type. In the JSON API these actions return the record or null if the record could not be found.

schema.keel
model Profile {
  fields {
    username Text
  }
  actions {
    get getProfile(id)
  }
}

Updating a record

You can define an action for updating a single record in your Keel schema using the update action type. In the JSON API these actions accept an object with where and values keys and return the record that was updated. The read inputs of the action (first set of parenthesis) go in the where object and the write inputs (those after with) go in the values object.

schema.keel
model Profile {
  fields {
    username Text @unique
    bio Text
  }
  actions {
    update updateBio(id) with (bio)
  }
}

Updates with no values

Update actions don't have to take any write inputs. For example you could define an action that publishes a post that uses a @set expression to update the record. For these cases you can omit the values key from the request.

schema.keel
model Post {
  fields {
    published Boolean
  }
  actions {
    update publishPost(id) {
      @set(post.published = true)
    }
  }
}

Listing records

You can define an action for listing many records in your Keel schema using the list action type. In the JSON API the inputs for these actions should be provided under a where key and accept query objects that allow for complex filtering. The return type of these actions is an object containing results and pageInfo keys.

schema.keel
model Book {
  fields {
    title Text
    genre Text
    releaseDate Date
  }
  actions {
    list listBooks(title?, genre?, releaseDate?)
  }
}

Filtering

We can use a list action to perform queries like:

  • Find all books whose title contains the word "Love"
  • Find all books whose genre is "Sci-Fi" or "Crime" and were released in the last year

This is possible because in a list action each input accepts a query object. For example an input that points to a Text field in a Keel schema can be filtered using contains or startsWith.

At least one key must be provided and if multiple keys are provided they are AND'd together.

All Keel types have a corresponding query type that allow filtering in ways that make sense for that type, for example a Text input can use contains whereas a Number input can use greaterThan.

{
  "equals": "cat",
  "notEquals": "cat",
  "contains": "cat",
  "startsWith": "cat",
  "endsWith": "cat",
  "oneOf": ["cat"]
}

Pagination

The input type for a list action has four fields that relate to pagination.

  • first - Only return the first N records. Can be used with after.
  • last - Only return the last N records. Can be used with before.
  • after - Return records after this cursor.
  • before - Return records before this cursor.

The response of a list action contains a pageInfo key which contains startCursor and endCursor fields. These values can be passed to after or before in subsequent queries. For example if you fetched the first 10 book records and in the response the endCursor value was "1234" then to get the next 10 records you would pass "1234" to the after input.

Functions

These docs talk about actions, which is the general term for both built-in actions (implemented by the Keel runtime) and functions (implemented by you using code). There is no difference between how built-in actions and functions are surfaced in the JSON API.