Skip to content

Instantly share code, notes, and snippets.

@jgornick
Created June 2, 2021 20:48
Show Gist options
  • Save jgornick/950118e222f155be4e052d78f46454d0 to your computer and use it in GitHub Desktop.
Save jgornick/950118e222f155be4e052d78f46454d0 to your computer and use it in GitHub Desktop.
JSON:API - OpenAPI
openapi: 3.0.2
info:
version: 1.0.0
title: "{json:api} Specification"
description: >
An include file to define the [{json:api} 1.0 specification](http://jsonapi.org/format).
N.B. I've got some confusion going on between a validating a jsonapi schema and defining one!
This file also provides a limited demonstration of jsonapi with path items for collections, items
and their methods. You should be able to open in a modern version of
[swagger-editor](https://github.com/swagger-api/swagger-editor) or
[swagger-ui-watcher](https://github.com/moon0326/swagger-ui-watcher).
This file was created by downloading the [schema definition](http://jsonapi.org/schema)
and then editing as needed to make it useful with the Open API Specification. It is subject
to the `CC0 1.0 Universal` license as it is derived from the {json:api} specification.
Several changes had to be made to that schema since it is non-normative and primarily only documented
the results of GET operations. See especially definitions of `post_datum`, `post_resource`, `datum`,
and `metaonly` that were added.
**USAGE**
You can reference definitions in this schema with `$ref` as defined in the OAS specification, but
be aware that the
"[[Reference Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#reference-object)]
cannot be extended with additional properties and any properties added SHALL be ignored." So $refs are pretty
useless if you are trying to keep things DRY.
Specifically, you'll need to copy and the path items into your own schema doc and "extend" them by adding
what you need (e.g. security, additional parameters, referneces to your app's request/response schemas, etc.).
For example:
```
paths:
/courses/:
get:
description: Returns a collection of courses
operationId: find courses
security:
- basicAuth: []
- oauth: [auth-columbia, read]
parameters:
# I wish I could pull all these in at once...
- $ref: './jsonapi.yaml#/components/parameters/include'
- $ref: './jsonapi.yaml#/components/parameters/sort'
- $ref: './jsonapi.yaml#/components/parameters/pageSize'
- $ref: './jsonapi.yaml#/components/parameters/pageNumber'
- name: 'filter[id]'
in: query
description: exact id
required: false
style: form
schema:
$ref: './jsonapi.yaml#/components/schemas/id'
responses:
'200':
description: course response
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/CourseCollection'
'401':
description: not authorized
content:
application/vnd.api+json:
schema:
$ref: './jsonapi.yaml#/components/schemas/error'
```
You can locate this file on a web server or in a local directory and `$ref` it appropriately; `swagger-ui-watcher`
will follow the `$ref`s and can be used to "bundle" your schema into a single JSON document as follows:
```
swagger-ui-watcher -b myapp.json --path myapp.yaml
```
contact:
name: Alan Crosswell
email: [email protected]
url: "http://www.columbia.edu/~alan"
license:
name: CC0 1.0 Universal
url: "https://creativecommons.org/publicdomain/zero/1.0/"
externalDocs:
description: Read more about {json:api} here
url: https://jsonapi.org/
servers:
- url: "{serverURL}"
description: provide your server URL
variables:
serverURL:
default: http://localhost:8000/v1
description: path for server
# not sure why but swagger-editor only prompts for the variable if there's more than one server listed.
- url: "{serverURL}"
description: provide your server URL
variables:
serverURL:
default: http://localhost:8000/v1
description: path for server
# Example generic paths and their methods: path parameters are {collection} and {id}
paths:
/{collection}/:
parameters:
- name: collection
in: path
required: true
schema:
type: string
get:
description: get a collection
operationId: get collection
parameters:
- $ref: '#/components/parameters/include'
- $ref: '#/components/parameters/sort'
- $ref: '#/components/parameters/pageSize'
- $ref: '#/components/parameters/pageNumber'
responses:
'200':
description: "[OK](https://jsonapi.org/format/#fetching-resources-responses-200)"
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/success'
'404':
description: "[Not found](https://jsonapi.org/format/#fetching-resources-responses-404)"
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/failure'
default:
description: collection response
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/JSONAPIresponse'
post:
description: "[add](https://jsonapi.org/format/#crud-creating) item to a collection"
operationId: post item
requestBody:
description: item to post
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/post_datum'
responses:
'201':
description: >-
[Created](https://jsonapi.org/format/#crud-creating-responses-201).
Assigned `id` and/or any other changes are in this response.
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/datum'
'202':
description: >-
Accepted for [asynchronous processing](https://jsonapi.org/recommendations/#asynchronous-processing).
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/datum'
headers:
Content-Location:
description: URL for status of processing
schema:
type: string
format: uri-reference
'204':
description: >-
[Created](https://jsonapi.org/format/#crud-creating-responses-204) with the supplied `id`.
No other changes from what was POSTed.
'403':
description: "[Forbidden](https://jsonapi.org/format/#crud-creating-responses-403)"
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/failure'
'404':
description: >-
[Related resource does not exist](https://jsonapi.org/format/#crud-creating-responses-404).
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/failure'
'409':
description: "[Conflict](https://jsonapi.org/format/#crud-creating-responses-409)"
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/failure'
default:
description: other post response
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/JSONAPIresponse'
/{collection}/{id}/:
parameters:
- name: collection
in: path
required: true
schema:
type: string
- name: id
in: path
required: true
schema:
$ref: '#/components/schemas/id'
get:
description: get an item
operationId: get item
responses:
'200':
description: "[OK](https://jsonapi.org/format/#fetching-resources-responses-200)"
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/datum'
'404':
description: "[Not found](https://jsonapi.org/format/#fetching-resources-responses-404)"
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/failure'
default:
description: get item response
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/JSONAPIresponse'
patch:
description: "[update](https://jsonapi.org/format/#crud-updating) an item"
operationId: patch item
requestBody:
description: item to patch
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/datum'
responses:
'200':
description: "[OK](https://jsonapi.org/format/#crud-updating-responses-200)"
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/datum'
'202':
description: >-
Accepted for [asynchronous processing](https://jsonapi.org/recommendations/#asynchronous-processing).
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/datum'
headers:
Content-Location:
description: URL for status of processing
schema:
type: string
format: uri-reference
'204':
description: >-
[Patched](https://jsonapi.org/format/#crud-updating-responses-204).
No other changes from what was PATCHed.
'403':
description: "[Forbidden](https://jsonapi.org/format/#crud-updating-responses-403)"
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/failure'
'404':
description: >-
[Resource does not exist](https://jsonapi.org/format/#crud-updating-responses-404).
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/failure'
'409':
description: "[Conflict](https://jsonapi.org/format/#crud-updating-responses-409)"
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/failure'
default:
description: get item response
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/JSONAPIresponse'
delete:
description: "[delete](https://jsonapi.org/format/#crud-deleting) an item"
operationId: delete item
responses:
'200':
description: "[OK](https://jsonapi.org/format/#crud-deleting-responses-200)"
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/onlymeta'
'202':
description: >-
Accepted for [asynchronous processing](https://jsonapi.org/recommendations/#asynchronous-processing).
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/datum'
'204':
description: >-
[Deleted](https://jsonapi.org/format/#crud-deleting-responses-204).
'404':
description: >-
[Resource does not exist](https://jsonapi.org/format/#crud-deleting-responses-404).
content:
'application/vnd.api+json':
schema:
$ref: '#/components/schemas/failure'
# Following is {json:api} schema definition in a form suitable for $ref usage
components:
schemas:
JSONAPIresponse:
oneOf:
- $ref: "#/components/schemas/success"
- $ref: "#/components/schemas/failure"
- $ref: "#/components/schemas/info"
success:
type: object
required:
- data
properties:
data:
$ref: "#/components/schemas/data"
included:
description: >-
To reduce the number of HTTP requests, servers **MAY** allow
responses that include related resources along with the requested
primary resources. Such responses are called `compound documents`.
type: array
items:
$ref: "#/components/schemas/resource"
uniqueItems: true
meta:
$ref: "#/components/schemas/meta"
links:
description: Link members related to the primary data.
allOf:
- $ref: "#/components/schemas/links"
- $ref: "#/components/schemas/pagination"
jsonapi:
$ref: "#/components/schemas/jsonapi"
additionalProperties: false
failure:
type: object
required:
- errors
properties:
errors:
type: array
items:
$ref: "#/components/schemas/error"
uniqueItems: true
meta:
$ref: "#/components/schemas/meta"
jsonapi:
$ref: "#/components/schemas/jsonapi"
links:
$ref: "#/components/schemas/links"
additionalProperties: false
info:
type: object
required:
- meta
properties:
meta:
$ref: "#/components/schemas/meta"
links:
$ref: "#/components/schemas/links"
jsonapi:
$ref: "#/components/schemas/jsonapi"
additionalProperties: false
onlymeta:
properties:
meta:
$ref: "#/components/schemas/meta"
additionalProperties: false
meta:
description: >-
Non-standard meta-information that can not be represented as an
attribute or relationship.
type: object
additionalProperties: true
data:
description: >-
The document's `primary data` is a representation of the resource or
collection of resources targeted by a request.
oneOf:
- $ref: "#/components/schemas/resource"
- description: >-
An array of resource objects, an array of resource identifier
objects, or an empty array ([]), for requests that target resource
collections.
type: array
items:
$ref: "#/components/schemas/resource"
uniqueItems: true
- $ref: "#/components/schemas/nulltype"
post_datum:
description: >-
singular item being [created](https://jsonapi.org/format/#crud-creating).
`id` is optional and may be ignored if supplied and created by the system.
properties:
data:
$ref: "#/components/schemas/post_resource"
datum:
description: singular item
properties:
data:
$ref: "#/components/schemas/resource"
resource:
description: Resource objects appear in a JSON API document to represent resources.
type: object
required:
- type
- id
properties:
type:
$ref: "#/components/schemas/type"
id:
$ref: "#/components/schemas/id"
attributes:
$ref: "#/components/schemas/attributes"
relationships:
$ref: "#/components/schemas/relationships"
links:
$ref: "#/components/schemas/links"
meta:
$ref: "#/components/schemas/meta"
additionalProperties: false
# unfortunately $ref resource and tring to change required doesn't work.
post_resource:
description: A POSTable resource object has an optional id.
type: object
required:
- type
properties:
type:
$ref: "#/components/schemas/type"
id:
$ref: "#/components/schemas/id"
attributes:
$ref: "#/components/schemas/attributes"
relationships:
$ref: "#/components/schemas/relationships"
# not clear what it means to try to POST links but the spec says POST a Resource Object...
links:
$ref: "#/components/schemas/links"
meta:
$ref: "#/components/schemas/meta"
additionalProperties: false
relationshipLinks:
description: >-
A resource object **MAY** contain references to other resource objects
(`relationships`). Relationships may be to-one or to-many. Relationships
can be specified by including a member in a resource's links object.
type: object
properties:
self:
description: >-
A `self` member, whose value is a URL for the relationship itself (a
`relationship URL`). This URL allows the client to directly
manipulate the relationship. For example, it would allow a client to
remove an `author` from an `article` without deleting the people
resource itself.
$ref: "#/components/schemas/link"
related:
$ref: "#/components/schemas/link"
additionalProperties: true
links:
type: object
additionalProperties:
$ref: "#/components/schemas/link"
link:
description: >-
A link **MUST** be represented as either: a string containing the link's
URL or a link object.
oneOf:
- description: A string containing the link's URL.
type: string
format: uri-reference
- type: object
required:
- href
properties:
href:
description: A string containing the link's URL.
type: string
format: uri-reference
meta:
$ref: "#/components/schemas/meta"
attributes:
description: >-
Members of the attributes object (`attributes`) represent information
about the resource object in which it's defined.
type: object
# properties:
# ^(?!relationships$|links$|id$|type$)\w[-\w_]*$:
# type: object
# description: Attributes may contain any valid JSON value.
additionalProperties: false
# TODO: This validates rather than defines:
relationships:
description: >-
Members of the relationships object represent
references from the resource object in which it's defined to other
resource objects. N.B. this is validation, not useful for inclusion.
type: object
# properties:
# ^(?!id$|type$)\w[-\w_]*$:
# $ref: "#/components/schemas/relationship"
additionalProperties:
$ref: "#/components/schemas/relationship"
relationship:
description: A single relationship description
type: object
properties:
links:
$ref: "#/components/schemas/relationshipLinks"
data:
description: Member, whose value represents `resource linkage`.
oneOf:
- $ref: "#/components/schemas/relationshipToOne"
- $ref: "#/components/schemas/relationshipToMany"
meta:
$ref: "#/components/schemas/meta"
anyOf:
- required:
- data
- required:
- meta
- required:
- links
additionalProperties: false
relationshipToOne:
description: >-
References to other resource objects in a to-one (`relationship`).
Relationships can be specified by including a member in a resource's
links object.
anyOf:
- $ref: "#/components/schemas/empty"
- $ref: "#/components/schemas/linkage"
reltoone:
description: A singular relationship
type: object
properties:
links:
$ref: "#/components/schemas/relationshipLinks"
data:
$ref: "#/components/schemas/relationshipToOne"
meta:
$ref: "#/components/schemas/meta"
reltomany:
description: A multiple relationship
type: object
properties:
links:
$ref: "#/components/schemas/relationshipLinks"
data:
$ref: "#/components/schemas/relationshipToMany"
meta:
$ref: "#/components/schemas/meta"
reltoonedata:
description: A singular relationship, data only.
type: object
properties:
data:
$ref: "#/components/schemas/relationshipToOne"
reltomanydata:
description: A multiple relationship, data only.
type: object
properties:
data:
$ref: "#/components/schemas/relationshipToMany"
relationshipToMany:
description: >-
An array of objects each containing `type` and `id` members for to-many
relationships.
type: array
items:
$ref: "#/components/schemas/linkage"
uniqueItems: true
empty:
$ref: "#/components/schemas/nulltype"
linkage:
description: The `type` and `id` to non-empty members.
type: object
required:
- type
- id
properties:
type:
type: string
id:
type: string
meta:
$ref: "#/components/schemas/meta"
additionalProperties: false
pagination:
type: object
properties:
first:
description: The first page of data
oneOf:
- type: string
format: uri-reference
- $ref: "#/components/schemas/nulltype"
last:
description: The last page of data
oneOf:
- type: string
format: uri-reference
- $ref: "#/components/schemas/nulltype"
prev:
description: The previous page of data
oneOf:
- type: string
format: uri-reference
- $ref: "#/components/schemas/nulltype"
next:
description: The next page of data
oneOf:
- type: string
format: uri-reference
- $ref: "#/components/schemas/nulltype"
jsonapi:
description: An object describing the server's implementation
type: object
properties:
version:
type: string
meta:
$ref: "#/components/schemas/meta"
additionalProperties: false
error:
type: object
properties:
id:
description: A unique identifier for this particular occurrence of the problem.
type: string
links:
$ref: "#/components/schemas/links"
status:
description: >-
The HTTP status code applicable to this problem, expressed as a
string value.
type: string
code:
description: >-
An application-specific error code, expressed as a string value.
type: string
title:
description: >-
A short, human-readable summary of the problem. It **SHOULD NOT**
change from occurrence to occurrence of the problem, except for
purposes of localization.
type: string
detail:
description: >-
A human-readable explanation specific to this occurrence of the
problem.
type: string
source:
type: object
properties:
pointer:
description: >-
A JSON Pointer [RFC6901] to the associated entity in the request
document [e.g. `/data` for a primary data object, or
`/data/attributes/title` for a specific attribute].
type: string
parameter:
description: A string indicating which query parameter caused the error.
type: string
meta:
$ref: "#/components/schemas/meta"
additionalProperties: false
nulltype:
description: OAS doesn't allow the null type so use this.
type: object
nullable: true
default: null
id:
type: string
description: "[resource object identifier](https://jsonapi.org/format/#document-resource-object-identification)"
type:
type: string
description: "[resource object type](https://jsonapi.org/format/#document-resource-object-identification)"
parameters:
include:
name: include
in: query
description: "[list of included related resources](https://jsonapi.org/format/#fetching-includes)"
required: false
style: form
schema:
type: string
sort:
name: sort
in: query
description: "[fields to sort by](https://jsonapi.org/format/#fetching-sorting)"
required: false
style: form
schema:
type: string
pageSize:
name: "page[size]"
in: query
description: size of page for paginated results
required: false
schema:
type: integer
format: int32
pageNumber:
name: "page[number]"
in: query
description: page number of results
required: false
schema:
type: integer
format: int32
pageLimit:
name: "page[limit]"
in: query
description: limit for this page of paginated results
required: false
schema:
type: integer
format: int32
pageOffset:
name: "page[offset]"
in: query
description: collection items offset for paginated results
required: false
schema:
type: integer
format: int32
# unable to properly represent fields and filters? swagger-edit appears to not implement this correctly.
fields:
name: fields
in: query
description: "sparse fieldsets: `fields[TYPE]=field1,field2,...`"
required: false
style: deepObject
schema:
type: string
filter:
name: filter
in: query
description: "filter[NAME]=value(s)"
required: false
style: deepObject
schema:
type: string
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment