rfcs/v3/rest_json_api.md
Hasura v3 will auto-generate a JSON:API spec-compliant REST API output. Hasura v3 will only generate these for DDN models. Commands are out of scope of this RFC.
Data, including resources and relationships, can be fetched by sending a GET request to an endpoint.
Responses can be further refined with the optional features described below.
A server MUST support fetching resource data for every URL provided as:
JSON:API supports selecting specific fields of a resource and specific fields of its related resources.
An endpoint MAY also support an include query parameter to allow the client to customize which
related resources should be returned.
A client MAY request that an endpoint return only specific
fields in the response on a per-type
basis by including a fields[TYPE] query parameter. They are called sparse
fieldsets.
GET /articles/1?include=comments
GET /articles/1?include=comments.author
GET /articles/1?include=comments.author,ratings
GET /articles/1/relationships/comments?include=comments.author
GET /articles?include=author&fields[articles]=title,body&fields[people]=name // sparse fieldsets
GET /<modelname>
GET /articles
JSON:API is agnostic about the syntax and implementation of the server. The only requirement is to
have a filter query parameter.
So we propose the following for complex filtering use-cases.
GET /<modelname>?filter[field1]=val1&filter[field2]=val2,val3&filter[field3.reltarget_field1]=val4
GET /comments?filter[post]=1,2&filter[author.id]=12
GET /movies?filter={"$or":[{"name":{"$eq":"Braveheart"}},{"name":{"$eq":"Gladiator"}}]} // url encoded
Both the above syntax are equivalent. If you notice, the last syntax is equivalent to what Hasura generates for its GraphQL API.
Hasura will also generate an OpenAPI schema for complex filtering on nested types. As a result, any auto-generated client would get full auto-complete and type-checking on any nested filtering clauses. Check out https://github.com/hasura/json-api-experiments to see this in action.
GET /<modelname>?sort=field1,-field2
GET /articles?sort=-created,title
The sort order for each sort field MUST be ascending unless it is prefixed with a minus (U+002D HYPHEN-MINUS, “-“), in which case it MUST be descending.
GET /<modelname>?page[limit]=10&page[offset]=0
GET /articles?page[limit]=10&page[offset]=0
The following keys MUST be used for pagination links:
GET /<modelname>/<unique-identifier>
GET /articles/1
GET /articles/1
GET /articles/1/author
JSON:API doesn’t have support for aggregates. It can be supported via JSON:API extensions. But for now, it is kept it out of scope.
JSON:API doesn't have support for exposing endpoints for a one-off job. It can be supported via JSON:API extensions. But for now, it is kept it out of scope.
For now, it is kept out of scope to keep the scope small.
JSON:API supports mutating resources via POST, PUT, PATCH and DELETE HTTP verbs on the
resource endpoints. This is a different model compared to Hasura, where Hasura follows the CQS
(Command-Query separation) pattern.
Supporting first-class mutation of resources via HTTP verbs would be a departure from the Hasura's API model. Hence it is kept out of scope of this RFC for now.
If required, response transformation could be performed with a JSON:API output on Hasura.
Say we want to flatten a field of the JSON response. We want to change article.author.name to
article.autor_name.
Recommended Approach: Use TS Connector
"data": {
"articles": [
{
"id": 1,
"title": "Article Title 1",
"author": {
"name": "Author Name 1"
}
},
{
"id": 2,
"title": "Article Title 2",
"author": {
"name": "Author Name 2"
}
}
[
{ id: 1, title: "Article Title 1", author_name: "Author Name 1" },
{ id: 2, title: "Article Title 2", author_name: "Author Name 2" }
]
Typescript Function
export function author_name(author?: AuthorType): string {
if (!author) {
return "Invalid author";
}
return author.name;
}
Type to Command Relationship
kind: Relationship
version: v1
definition:
name: author_name
source: articles
target:
command:
name: author_name
subgraph: null
mapping:
- source:
fieldPath:
- fieldName: author
target:
argument:
argumentName: author
In the future when computed columns are supported in OpenDD, it can be part of the general response type and not relationships
Responses MUST be according to the JSON:API document structure.
data: the document’s “primary data”, either a single resource object, an array of resource objects, or null.
errors: an array of error objects.
meta: contains non-standard meta-information.
data: The document’s “primary data”.
errors: An array of error objects.meta: A meta object that contains non-standard meta-information.included: Includes related (to the primary data) resource objects and is used to provide
compound documents. The purpose of this section is to reduce the number of requests clients need
to make by including related resources directly in the response.
type and id pair.data resource
objectslinks: Top-level links object contains pagination links (self, next, last).jsonapi: Contains the version of the JSONdescribedby URL.Read more on the resource object.
For the first iteration, to keep things simple, we are not introducing any OpenDD configuration. Any
OpenDD model that is configured with a graphql section will get auto-generated JSON:API endpoints.