-
Notifications
You must be signed in to change notification settings - Fork 858
RAML 1.0 scratchpad
The root property should be called baseUrl, because it really is the locator for the hosted API.
Also, it currently says:
The use of the baseUri field is OPTIONAL to allow describing APIs that have not yet been implemented. After the API is implemented (even a mock implementation) and can be accessed at a service endpoint, the API definition MUST contain a baseUri property.
It should always be optional.
The use of the baseUrl field is OPTIONAL.
The spec says:
The baseUri property's value MUST conform to the URI specification [RFC2396] or a Level 1 Template URI as defined in RFC 6570 [RFC6570].
In order to be able to document more versatile APIs, Level 2 templates should also be allowed, but only if the macro is the last piece in the URL
Example:
#%RAML 0.8
title: My Sample API
/files{+path}:
uriParameters:
path:
description: The full path to the desired file
type: string
example: /my/file
This will allow to give semantic names to methods, and simplify SDK or richer client generation.
Example:
#%RAML 0.8
title: My Sample API
/files:
get:
displayName: getFiles
In order to improve the quality of generated RAML specifications, we should add to the spec some wording like the following:
RAML processors MUST validate that examples for named parameters or responses are valid according to the schema, regular expressions or type.
In order to support JSONP a new jsonp
property should be added to methods. This property MUST be interpreted in the following way:
- If present in a method, this operation can be called using JSONP
- If the method is other than
get
, the URI can be called and themethod
property in thejsonp
property must exist - RAML processors MUST:
- If the method is different from
get
, they MUST use themethod
property and send the method's name as a URI parameter - If the
body
property is defined, and the method defines a body, the body must be sent as a URI parameter (URL encoded)
- If the method is different from
Property Name | Description |
---|---|
callback |
The name of the URI parameter used by the API to indicate the name of the Javascript function to call on responses. |
method |
The name of the URI parameter to submit the HTTP method (if different than GET) |
body |
The name of the URI parameter to submit the body of the request |
#%RAML 0.8
title: My Sample API
baseUrl: http://myapi.io
/files:
description: return a list of file metadata
get:
jsonp:
callback: callback
post:
description: create a file
jsonp:
callback: callback
method: APImethod
body: body
body:
example: |
{
'name': 'my-file-name.txt',
'created-date': 1409147946
}
With this example, a request to retrieve file resources MUST be interpreted as a GET to http://myapi.io/files?callback=processResponse
.
With the same example, a file resource creation MUST be interpreted as a GET to /files
This is separate from the main JSONP discussion, because I have not seen a standard for this anywhere
Add a headers
property to jsonp
, if present:
- RAML processors must send any headers defined for the method as a JSON encoded object, where each key in the object is a header.
Property Name | Description |
---|---|
headers |
The name of the URI parameter to submit any extra headers needed by the API |
#%RAML 0.8
title: My Sample API
baseUrl: http://myapi.io
/files:
description: return a list of file metadata
get:
jsonp:
callback: callback
headers: api-headers
The current value for patterns in header names should be {?}
Extend the {?}
syntax to all named parameters, except URI parameters.
RAML MUST be prescriptive and say which version of Markdown is valid in the documentation.
RAML spec says that JSON schemas MUST be draft v 0.3. We should remove the restriction. Since all JSON schemas have the version embedded, we should allow RAML processors, list which versions of JSON schema they support.
Remove the restriction that enums MUST only be used with type: string
Originally documented here:
https://github.com/mulesoft/api-designer/issues/203
In the case of traits, the rules are:
- If the property is in the resource/method, then this will be the final value.
- Traits are processed from left to right in the
is:
property, so the first trait to define the property gets to set the final value.
In the case of resource types, the rules are a bit more complex:
- If the property is in the resource/method, then this will be the final value
- Then resource types are mixed in:
1. The inheritance chain is walked up to the base type, its traits applied, and then the inheriting resource type's properties are mixed in with the parent resource type, where it is the inheriting type's property the ones who overrule the parent.
1. This is done recursively for all parent types, until a single representation for the entire chain has been reached.
1. This 'parent' resource type is then mixed in with the inheriting
resource
- Then the traits are mixed in with the resource as described above
The main guiding rule for both of these is:
Whoever is closest to the resource gets to set the property first, in case of traits, it will be the first one in the list, in the case of resource types, it will be the closest in the inheritance chain.
The following syntax for !includes
should be allowed in resource types and traits.
#%RAML 0.8
title: My Sample API
resourceTypes:
- collection:
get:
post:
body:
example: !include <<resourcePathName!singularize>>.json
In order to have more powerful traits and resource types, we should allow trait and resource types parameters be scalars, arrays, and maps, this will allow resource types like the following:
#%RAML 0.8
title: My Sample API
traits:
- orderBy:
description: Order by field
type: string
enum: <<filterValues>>
required: false
/people:
is: [orderBy: { filterValues: ['age', 'height'] } ]
There is some ambiguity as to who is responsible for filling in the default values for named parameters.
For URI parameters, RAML clients MUST fill the default value into the URI before make requests to the API. For Headers, Form Parameters, Query String Parameters, if the parameter is flagged as not
required
and having adefault
value, the API must act as if the API client has sent the parameter with the value being the value in thedefault
property.
When two resources have the same relative URI, and there are no URI parameters in the URIs, then the RAML should be invalid:
#%RAML 0.8
title: My Sample API
/users:
me:
get:
/users/me:
post:
When there are URI parameters in the relative URIs, it is assumed that the API routing implementation can handle the ambiguity. In such cases, to resolve ambiguity, resources defined earlier in the RAML spec take precedence over resources declared later. In the following example, the definition of the route /users/me
takes precedence over /users/{id}
, and both routes are considered to be different resources.
#%RAML 0.8
title: My Sample API
/users/me:
get:
/users:
{id}:
get:
The spec uses minimum and maximum for parameter validation, but then also uses minLength and maxLength. RAML 1.0 should standardise on a single naming scheme, it should use the full word.
minLength
should become minimumLength
maxLength
should become maximumLength
RAML 1.0 should allow the applicability of minimumLength and maximumLength for parameters of type file
, RAML processors MUST interpret them as the length in BYTES of the file.
It should also include a new property: fileTypes
, which should be a list of valid content-type strings for the file. The file type */*
should be a valid value.
In the following example the named parameter userPicture
can be as large as 300KB, and must be either a JPEG or PNG image, while the file
named parameter must be smaller than 1MB and can be of any type.
#% RAML 1.0
title: My Sample API
types:
userPicture:
type: file
fileType: ['image/jpeg', 'image/png']
maximumLength: 307200
file:
type: file
fileType: ['*/*']
maximumLength: 1048576
RAML 1.0 should narrow the list of supported HTTP methods to:
- GET
- HEAD
- POST
- PUT
- DELETE
- PATCH
Rationale:
(The first 5 as defined in RCF2616 and RFC7231, the last one as defined in RFC5789) Thus removing the following 3 methods which have no clear semantics in an REST API:
- CONNECT: RFC7231 reads:
CONNECT is intended only for use in requests to a proxy. An origin server that receives a CONNECT request for itself MAY respond with a 2xx (Successful) status code to indicate that a connection is established. However, most origin servers do not implement CONNECT.
- TRACE: has no value for a REST API as it is an
echo
type of request and is valuable for debugging integration/transport/proxying issues, not to carry API semantics. - OPTIONS: We might want to revisit the applicability of this method to provide a mechanism for describing APIs, but generally this method does not carry API semantics.
RAML 1.0 should have a way to define named parameter types as a top level entity for later reuse.
In the following example, a named parameter type called userName is defined and later used to validate a uriParameter.
#%RAML 0.8
title: My Sample API
types:
userName:
type: string
example: aUserName
validationPattern: \w{1,15}
/users/{id}:
uriParameters:
id:
type: userName
A root level type cannot overwrite RAML defined types (such as string
, number
, etc)
Although it is a little bit longer, it has clearer semantics.
RAML 1.0 should not allow the definition of inline resourceTypes in the type
property of a resource or the definition of traits. This is highly ambiguous.
The highlighted wording should be removed.
The value of the type attribute MUST be either a) one and only one of the resource type keys (names) included in the resourceTypes declaration, or b) one and only one resource type definition map.
The list should be clear regarding the Authorization Grant names:
- Authorization code grant:
authorization_code
- Resource owner password credentials grant:
password
- Client credentials grant:
client_credentials
- Implicit grant:
implicit
- Refresh token grant:
refresh_token
#%RAML 0.8
title: My Sample API
securitySchemes:
- oauth_2_0:
description: |
OAuth 2.0 implementation.
type: OAuth 2.0
settings:
authorizationUri: https://www.myapi.com/1/oauth2/authorize
accessTokenUri: https://www.myapi.com/1/oauth2/token
authorizationGrants: [ authorization_code, password, client_credentials, implicit, refresh_token ]
Add a property to the OAuth 2.0 settings extensionAuthorizationGrants
, which should be a list of any extension Authorization grant types supported by the Authentication server, since these can be anything that the OAuth vendor has defined, it is the vendor's responsibility to document how those should work.
#%RAML 0.8
title: My Sample API
securitySchemes:
- oauth_2_0:
description: |
OAuth 2.0 implementation.
type: OAuth 2.0
settings:
authorizationUri: https://www.myapi.com/1/oauth2/authorize
accessTokenUri: https://www.myapi.com/1/oauth2/token
authorizationGrants: [ authorization_code, password ]
extensionAuthorizationGrants: [ 'urn:ietf:params:oauth:grant-type:saml2-bearer' ]
The authorizationUri
is not mandatory when only the client_credentials
authorizationGrant is supported.
RAML 1.0 should add one more property signatures
, which should be a list of the signature methods used by the server. If this property is missing, it is assumed that the Authentication server allows any signature method defined in RFC5849.
Valid values for the signature methods are:
- HMAC-SHA1
- RSA-SHA1
- PLAINTEXT
#%RAML 0.8
title: My Sample API
securitySchemes:
- oauth_1_0:
description:|
OAuth 1.0 continues to be supported for all API requests, but OAuth 2.0 is now preferred.
type: OAuth 1.0
settings:
requestTokenUri: https://api.mysampleapi.com/1/oauth/request_token
authorizationUri: https://api.mysampleapi.com/1/oauth/authorize
tokenCredentialsUri: https://api.mysampleapi.com/1/oauth/access_token
signatures: [ 'HMAC-SHA1', 'PLAINTEXT' ]
The root level properties: schemas
, resourceTypes
, and traits
are lists of dictionaries. User testing has demonstrated that lists are hard to write and read by humans.
We should make those properties, maps, and allow use of the merge operator to extend the list of traits, resource types, schemas, etc.
IMPORTANT: Since the merge key in YAML is ambiguous in this case
RAML 1.0 should clarify that RAML processors should be able to parse more than one merge key operator per mapping
Example of a trait definition:
#%RAML 0.8
title: My Sample API
traits:
secured:
headers:
Authorization:
description: Send this header with the secret token
example: Bearer 71543fa6a11044b0a9f3a8354ddcb00e
searchable:
queryParameters:
q:
description: The search string
Example of a trait definition, including traits remotely:
#%RAML 0.8
title: My Sample API
traits: !include http://myapi.com/raml/traits/traits.raml
Example of a trait definition, mixing local and remote traits:
#%RAML 0.8
title: My Sample API
traits:
secured:
headers:
Authorization:
description: Send this header with the secret token
example: Bearer 71543fa6a11044b0a9f3a8354ddcb00e
<<:
!include http://myapi.com/raml/traits/traits.raml
<<:
!include http://myapi.com/raml/traits/moretraits.raml
In this last example, any trait declared in the traits.yaml
will be added to the local traits. If a trait with the same name has been declared before, it will not be overwritten.
By adding a locales
root level property, and a keyword to reference text bundles, RAML 1.0 can provide support for localization of documentation.
A resource bundle is a YAML file, which contains a mapping, where each key is the name of a text resource, and each value is the value for that text resource string in a given locale.
#%RAML 0.8
title: !bundle title
locales:
en_US: !include docs/en_US.bundle.yaml
es: !include docs/es.bundle.yaml
/users:
description: !bundle users.description
Where docs/en_US.bundle.yaml
contains
title: My Sample API
users.description: The users resource provides access to all users in the system
Where docs/en_US.bundle.yaml
contains
title: Mi API de ejemplo
users.description: El recurso users provee acceso a todos los usuarios en el sistema
RAML processors must pick the resource bundle which best matches the consumers locale.
Modify the types in named parameters, to add the following types:
Type | Description |
---|---|
iso-date |
A date encoded as defined in ISO 8601 |
iso-time |
A time encoded as defined in ISO 8601 |
iso-datetime |
A combined date and time encoded as defined in ISO 8601 |
RAML 1.0 should include a property to indicate that a method is accessible from a different origin.
The cors
property can be:
- In a method
- The
false
YAML boolean value, to indicate that the method cannot be accessed from a different origin. This is the default value. RAML processors should assume that if the property is missing, the value isfalse
- The
- In the root scope or in a resource scope
- A mapping with the following properties, affect the response headers of the preflight request:
Property name | Description |
---|---|
allow-methods |
A list of methods in the resource, if missing, it is assumed that all methods in the resource can be reached across origins |
allow-origin |
A list of the origin domains which can make requests to the API. '*' means that ANY origin domain can make requests. |
allow-credentials |
A boolean value indicating whether or not the actual request can be made using credentials. |
expose-headers |
A list of headers that will be exposed through the CORS enabled method. |
max-age |
Indicates in seconds how long the results of a preflight request can be cached. |
allow-headers |
A list of header names that indicates which HTTP headers can be used when making the actual request. |
The cors
property can be specified:
- In a method:
cors
can be set tofalse
to turn CORS off in a method - In a resource: The resource is CORS enabled, all methods in the resource will use that CORS configuration, except for methods which have been marked as not available through CORS
- At the root level: All methods in all resources will use that CORS configuration, except for methods which have their own CORS configuration
In the following example the POST
method to users is CORS enabled to all origins:
title: My sample API
/users:
cors:
allow-origin: *
post:
In the following example, all methods in the API are CORS enabled, except for operations on the /users
resource:
title: My sample API
cors:
allow-origin: *
/users:
post:
cors: false
/pages:
get:
post:
- Consumers of the API trust that the resources and methods marked with the property can be called by web applications
- APIs implement CORS support as defined in the (CORS specification)(http://www.w3.org/TR/cors/).
- The API must respond to the CORS pre-flight requests to the resource.
- The values of the headers of the preflight request should be filled with the values in the
cors
configuration.
RAML 1.0 should allow the following:
- Allow more than one example for each schema
- Give a way to tie schemas and examples as bundles to avoid duplication in resource definitions
- Allow specifying the type of a schema explicitly
A body can be used to describe the body of a request or the body of a response. It is a map with the following properties:
Property Name | Description |
---|---|
schema |
A mapping with the schema definition |
example |
A string with a single example for the body. |
examples |
A mapping of examples, where the key is the name of the example |
An example is a simple map with the following properties
Property Name | Description |
---|---|
description | A string with a short description of the example. |
example | A string with a single example for the body. |
A schema is a simple map with the following properties
Property Name | Description |
---|---|
type |
A string describing the language in which the resource is described: valid values for this field are json-schema/draft-03 , json-schema/draft-04 , xml-schema . |
definition |
A string with the schema definition written in the language and syntax described by schemaType. |
Add a root property bodies
, is a map, each key in it, is the name of a body, each value is a map with a body definition.
Now, when a RAML creator wants to use a body, it has a choice of defining the body as described above, or reference a root level body defined by name in the bodies
root level property.
In the following example, 2 bodies are defined, user
and users
, both are referenced automatically from a resourceType, using resourcePathName
, and user
is also referenced from the /users/me
resource.
title: My Sample API
defaultMediaType: application/json
bodies:
user:
schema:
type: json-schema/draft-03
definition: |
{}
examples:
adminUser:
description: An `admin` user has the `admin` property set to `true` and has the `allowed-operations` collection populated with the all the actions it can perform
example: |
{ an example of the JSON here }
normalUser:
description: A `normal` user does not have the `admin` property turned on.
example: |
{ an example of the JSON here }
users:
schema:
type: json-schema/draft-03
definition: |
{}
example: |
{ an example of the JSON here }
resourceTypes:
collection:
post:
body: <<resourcePathName!singularize>>
get:
body: <<resourcePathName>>
/users:
type: collection
/me:
get:
responses:
200:
body: user
To express some level of dependencies between named parameters we should add the following properties to the named parameter definitions:
Property Name | Description |
---|---|
dependsOn |
A list of named parameters which must be sent together with this named parameter. |
collidesWith |
A list of named parameters which must not be used together with this named parameter. |
requiredIfNot |
This parameter expresses that the current named parameter is mandatory unless any of the other named parameters in the list is used. |
In the following example, the lat
and long
query parameters must be sent together unless the location
named parameter is being sent.
title: My Sample API
/locations:
get:
queryParameters:
lat:
dependsOn: [long]
requiredIfNot: [location]
collidesWith: [location]
long:
dependsOn: [lat]
collidesWith: [location]
location:
requiredIfNot: [lat, long]
collidesWith: [lat, long]
With that configuration, the following requests are valid:
/locations?lat=1&long=2
/locations?location=1,2
The following should be rejected:
-
/locations
(rejected becauserequireIfNot
is not satisfied ) -
/locations?location=1,2&lat=1
(rejected becausecollidesWith
is not satisfied) -
/locations?location=1,2&long=1
(rejected becausecollidesWith
is not satisfied) -
/locations?lat=1
(rejected becausedependsOn
is not satisfied) -
/locations?long=1
(rejected becausedependsOn
is not satisfied)
These properties cannot be used on URI parameters, as all URI parameters are mandatory.
When specifying a request or response body's schema using JSON or XML schema, the schema
property may point to a schema definition which may contain more than a single object or resource.
We should update the body
definition by making the schema property include the name of the element in case of XML-schema, the object id in case of JSON-Schema, or an arbitrary identifier in case of another type of schema.
Property Name | Description |
---|---|
objectIdentifier | If type is json-schema/draft-03 or json-schema/draft-04 , it should be the object id URI. If the type is xml-schema, it should be the name of the element . |
bodies:
user:
schema:
type: json-schema/draft-04
definition: |
{
"id": "http://my.sample.api/user-schema",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"name": {}
},
"required": [ "name" ]
}
objectIdentifier: http://my.sample.api/user-schema
bodies:
user:
schema:
type: xml-schema
definition: |
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
...
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
objectIdentifier: shiporder