Some useful RAML 1.0 snippets.
- Introduction
- JSON API 1.0 Libraries
- OAuth 2.0 types library
- Example
- Issues
- OAS 3.0 refactoring
- TO DO
- Author
- LICENSE
N.B. RAML deprecated in lieu of OAS
With the introduction of Openapi 3.0, we've switched from RAML 1.0 to OAS 3.0 for our API specification language.
Please see https://columbia-it-django-jsonapi-training.readthedocs.io/en/latest/documenting-api.html for a more up-to-date project that documents JSON API 1.0 using OAS 3.0.
Find here some useful RAML 1.0 snippets (mostly as RAML 1.0 Libraries) that can be included in your root RAML API document.
This library defines RAML types for {json:api} 1.0 RESTful API responses.
This library of RAML types is derived directly from the json-api 1.0 specification which is coded using the json-schema.org specification.
The following CHANGES have been made from the schema's YAML:
- resource type is redefined a subclass of resource_post because id is not required for POST request body whereas it is mandatory for response body.
- I couldn't represent allOf for
links
so made apagelinks
type which extendslink
. - Fix attributes and relationships types (patternProperties not directly mappable to RAML)
- Move type: up for readability and changed type: array/items: into just type: itemtype[]
See the related jsonApiCollections.raml Library for useful resourceTypes and traits that uses these types.
Jsonapi uses mediatype application/vnd.api+json
in requests and responses.
Example usage:
uses:
api: jsonApiLibrary.raml
...
/widgets:
get:
responses:
200:
body:
application/vnd.api+json:
type: api.success
properties:
data: widgets[]
Make your API-specific data
types subclasses of api.resource and your methods should use type api.success
for successful responses and api.failure for failure responses.
For reasons I don't quite understand, you must use this with the same uses
key name
(api) in your main api.raml and any other libraries that reference types defined here.
This file is mostly machine-generated by reading the jsonapi.json 1.0 schema and converting to YAML and then RAML.
The json-api specification used to create this derivative work is in the public domain under a Creative Commons Zero v1.0 Universal license.
This is a companion to the jsonApiLibrary.raml Library.
resourceTypes
The collection
and item
resourceTypes follow the {json:api} 1.0 recommendations
regarding URL naming: a resourcePathName should be the same as it's type (both plural nouns). However, because
we may be using RAML Libraries for those type definitions, one can't use resourcePathName but must still
provide a dataType.
The relationshipCollection
is a special resourceType for to-many relationships
that allows GET, POST, PATCH & DELETE.
(Normal collection
s don't allow PATCH or DELETE of the entire collection and the meaning of DELETE for relationships
is quite different.) The relationshipItem
is a special resourceType for to-one relationships
that allows GET & PATCH.
collection required parameters:
- dataType: the response RAML type (e.g.
mythings
). You must also define types named e.g.mythings_post
andmythings_patch
. These are all subclasses of on another with various properties labeled as true. This deals with the requirement that response data must haveid
andtype
keys which post data can leave out theid
but must have all the required primary data attributes and patch data can leave out required attributes as it only sends changes. - exampleCollection: an example collection of the dataType.
- exampleItem: an example item of the dataType.
traits
Traits of pageable
, sortable
, sparse
, filterable
, includable
are provided which describe the various
standard query parameters, including recommended usage.
For convenience, the all-the-things
trait combines all the above-listed traits.
Usage example:
uses:
col: libraries/jsonApiCollections.raml
/widgets:
type:
col.collection:
dataType: wid.widgets
exampleCollection: !include examples/WidgetCollectionExample.raml
exampleItem: !include examples/WidgetItemExample.raml
get:
is: [ col.pageable, col.sparse ]
For reasons I don't quite understand, you must use this with the same uses
key name
(api) in your main api.raml and any other libraries that reference types defined in jsonApiLibrary.raml.
For other reasons I don't understand, this can't just be part of jsonApiLibrary.raml.
The OAuth 2.0 types library currently only defines the
OAuth2success
and OAuth2error
types for the token request endpoint.
An example of using the JSON API libraries consists of the following RAML files:
- Root API -- top-level RAML 1.0 API definition.
- Columbia securitySchemes and traits Library -- locally-defined standards.
- example Widget type definition -- subclasses JSON API
resource
andattributes
types. - exampl Location type definition -- another user API type.
Using the above-defined types, resourceTypes, and traits, we are able stay DRY and have a pretty concise root API document that focuses on what's unique about this API, reusing standard patterns for OAuth 2.0-protected resources that follow the JSON API 1.0 spec.
#%RAML 1.0
title: demo-jsonapi
description: a sample RESTful API that conforms to jsonapi.org 1.0
version: v1
#...
uses:
api: libraries/jsonApiLibrary.raml
loc: libraries/LocationType.raml
wid: libraries/WidgetType.raml
col: libraries/jsonApiCollections.raml
cu: libraries/columbiaLibrary.raml
# the API's resources:
/widgets:
displayName: widgets
description: stuff we have in inventory
type:
col.collection:
dataType: wid.widgets
exampleCollection: !include examples/WidgetCollectionExample.raml
exampleItem: !include examples/WidgetItemExample.raml
get:
is: [ cu.oauth_read_any, col.all-the-things ]
post:
is: [ cu.oauth_create_any ]
While we would have liked to use json-schema.org representations for types, RAML 1.0 does not support type inheritance for JSON schemas:
A RAML processor MUST NOT allow types that define an XML or JSON schema to participate in type inheritance or specialization, or effectively in any type expression. Therefore, you cannot define sub-types of these types to declare new properties, add restrictions, set facets, or declare facets. You can, however, create simple type wrappers that add annotations, examples, display name, or a description.
Luckily the RAML 1.0 type system is based on json-schema.org so it is easy to generate json-schema.org from the RAML type definitions.
There appears to be no standard way to identify the metadata for a RAML 1.0 API as part of the API
definition (e.g. as a well-known resource; Mulesoft's APIkit uses /console/api/?raml
but this is
not even documented anywhere and is not in the API's resource namespace). There is a dearth of client
libraries that can parse compound RAML 1.0 documents (e.g. using libraries and other RAML fragments)
into a compiled JSON representation. One that works well for javascript is
raml-json-enhance-node. It compiles
the RAML 1.0 to this JSON schema.
Perhaps this will be made moot by adoption of Open API 3.0.
{json:api} also appears to lack a standard metadata mechanism for discovering type schemas.
Even though jsonapi requires a type
attribute (as does RAML 1.0), there is no standard place
to find type definitions. Json-schema.org uses "{$ref": "#/definitions/<type>"}
-- a JSON pointer -- for this.
{json:api} response and body types vary in which properties are required or optional. For example, a GET response
requires the type
and id
properties and whatever attributes
have been designated as required for the
primary data. However, a POST allows the id
to be optional as it is often system-generated (and returned with
a 201 Created response). And, a PATCH only wants the attributes
and relationships
that have been changed
to be supplied.
To mitigate this issue, each "user" type must actually be decalared as three types:
- mytype: subclass of mytype_post which makes
id
required. - mytype_post: subclass of mytype_patch which overrides required attributes and relationships.
- mytype_patch: base class which defines all attributes and relationships as optional.
See OAS for a start at refactoring from RAML 1.0 to OAS 3.0.
Still to do:
- Define a local standard for finding API metadata if a global standard isn't available.
- Refactor for OAS 3.0
Alan Crosswell
Copyright (c) 2017 The Trustees of Columbia University in the City of New York
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.