From 8632a2bccbe2fc228e545152c5e4ba5d00fe003f Mon Sep 17 00:00:00 2001 From: Anon Ray Date: Wed, 24 Jul 2024 22:01:58 +0530 Subject: [PATCH 1/2] add RFC for REST API output --- rfcs/v3/rest_json_api.md | 258 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 rfcs/v3/rest_json_api.md diff --git a/rfcs/v3/rest_json_api.md b/rfcs/v3/rest_json_api.md new file mode 100644 index 0000000000000..c7639819401af --- /dev/null +++ b/rfcs/v3/rest_json_api.md @@ -0,0 +1,258 @@ +# REST API Output + +Hasura v3 will auto-generate a [JSON:API](https://jsonapi.org/) spec-compliant REST API output. +Hasura v3 will only generate these for DDN models. Commands are out of scope of this RFC. + +## Fetching Data + +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. + +### Fetching Resources + +A server MUST support fetching resource data for every URL provided as: + +* a self link as part of the top-level links object +* a self link as part of a resource-level links object +* a related link as part of a relationship-level links object + +### Selecting + +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](https://jsonapi.org/format/#document-resource-object-fields) in the response on a per-type +basis by including a `fields[TYPE]` query parameter. They are called [sparse +fieldsets](https://jsonapi.org/format/#fetching-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 +``` + +### Select Many + +``` +GET / + +GET /articles +``` + +#### Filtering + +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 /?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 to see this in action. + +#### Sorting + +``` +GET /?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. + +#### Pagination + +``` +GET /?page[limit]=10&page[offset]=0 + +GET /articles?page[limit]=10&page[offset]=0 +``` + +The following keys MUST be used for pagination links: + +* first: the first page of data +* last: the last page of data +* prev: the previous page of data +* next: the next page of data + +### Select One + +``` +GET // + +GET /articles/1 +GET /articles/1 +GET /articles/1/author +``` + +## Aggregates + +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. + +## Commands + +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. + +### Mutations + +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. + +## Customizations + +If required, response transformation could be performed with a JSON:API output on Hasura. + +### Response Transforms Example + +#### Flatten Response JSON + +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 + +* Becomes part of relationship response object + +```javascript + + "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 + +```javascript +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 + +## Response Document Structure + +Responses MUST be according to the JSON:API document structure. + +* JSON object must be root of every document +* A document MUST contain at least one of the following top-level members: + +``` + 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. +``` + +* The members \`data\` and \`errors\` MUST NOT coexist in the same document. +* Primary data MUST be + * single resource object + * array of resource objects + +### Top-Level Structure: + +- A JSON document **MUST** contain at least one of the following top-level members: + - `data`: The document’s “primary data”. + - is either a single resource object, an array of resource objects, or null. + - `errors`: An array of error objects. + - `meta`: A meta object that contains non-standard meta-information. +- Other Top Level Items + - `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. + - Compound Documents \- Allow responses to include related resources along with the primary + resources. + - A [compound document](https://jsonapi.org/format/\#document-compound-documents) **MUST NOT** + include more than one resource object for each `type` and `id` pair. + - Every included resource object **MUST** be identified via a chain of relationships + originating in a document’s primary data. This means that compound documents require “full + linkage” and that no resource object can be included without a direct or indirect + relationship to the document’s primary data. + - Can also contain relationships and related links, just like the primary `data` resource + objects + - `links`: Top-level links object contains pagination links (`self`, `next`, `last`). + - `jsonapi:` Contains the version of the JSON + - being used and additional meta-information about the API, including a `describedby` URL. + +Read more on the [resource object](https://jsonapi.org/format/\#document-resource-objects). + +# OpenDD config + +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. From b71e0c9f91df7bcdb4348a379b2e29935817d6fa Mon Sep 17 00:00:00 2001 From: Anon Ray Date: Thu, 29 Aug 2024 19:02:49 +0530 Subject: [PATCH 2/2] Update rfcs/v3/rest_json_api.md Co-authored-by: Daniel Harvey --- rfcs/v3/rest_json_api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/v3/rest_json_api.md b/rfcs/v3/rest_json_api.md index c7639819401af..9a6207c920b43 100644 --- a/rfcs/v3/rest_json_api.md +++ b/rfcs/v3/rest_json_api.md @@ -138,7 +138,7 @@ If required, response transformation could be performed with a JSON:API output o #### Flatten Response JSON Say we want to flatten a field of the JSON response. We want to change `article.author.name` to -`article.autor_name`. +`article.author_name`. Recommended Approach: Use TS Connector