Skip to content
This repository has been archived by the owner on Feb 17, 2024. It is now read-only.

RAML 1.0 scratchpad

Damian Martinez Gelabert edited this page Sep 18, 2014 · 16 revisions

RAML 1.0

Rename baseUri to baseUrl

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.

Allow '/' in URI parameters

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

Add displayName for methods

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

Examples validation

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.

Add support for JSONP

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 the method property in the jsonp property must exist
  • RAML processors MUST:
    • If the method is different from get, they MUST use the method 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)
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

Add support for headers in JSONP

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

Fix optional headers marker from { * } to {?}

The current value for patterns in header names should be {?}

Allow arbitrarily named Named Parameters

Extend the {?} syntax to all named parameters, except URI parameters.

Make a note that all markdown is GFM

RAML MUST be prescriptive and say which version of Markdown is valid in the documentation.

Remove prescription of JSON schema versions

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.

Allow enum in Named Parameters be used for any parameter type

Remove the restriction that enums MUST only be used with type: string

Document resource type and trait composition

Originally documented here:

https://github.com/mulesoft/api-designer/issues/203

In the case of traits, the rules are:

  1. If the property is in the resource/method, then this will be the final value.
  2. 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:

  1. If the property is in the resource/method, then this will be the final value
  2. 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
  3. 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.

Allow Dynamic, parameter-driven !includes

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

Allow arrays and maps as resource types and traits parameters

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'] } ]

Clarify named parameters authority

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 a default value, the API must act as if the API client has sent the parameter with the value being the value in the default property.

Clarify resource precedence when two URIs collide

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:



Rename named parameter properties for consistency

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

Validations for form parameters of type file

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

Narrow down the list of supported HTTP methods/verbs

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 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.

Allow for custom types and add types root level property

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)

Rename named parameter property pattern for validationPattern

Although it is a little bit longer, it has clearer semantics.

Remove inline Trait and Resource Type declaration

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.

Changes to Security schemes

Fix errors with the Authorization Grants for OAuth 2.0

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 support for extension OAuth 2.0 Authorization Grants

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' ]

Clarify validation of OAuth URIs

The authorizationUri is not mandatory when only the client_credentials authorizationGrant is supported.

Add the signatures property to the OAuth 1.0 settings

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' ]

Remove lists for << merge key

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.

Internationalization for documentation

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.




Date formats

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

Add the cors property

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 is false
  • 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 to false 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:

What does it mean when a resource is allows CORS?

  • 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.

Bodies property

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 definition

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.

Bodies

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.

Using bodies

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

Express parameter dependencies

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 because requireIfNot is not satisfied )
  • /locations?location=1,2&lat=1 (rejected because collidesWith is not satisfied)
  • /locations?location=1,2&long=1 (rejected because collidesWith is not satisfied)
  • /locations?lat=1 (rejected because dependsOn is not satisfied)
  • /locations?long=1 (rejected because dependsOn is not satisfied)

These properties cannot be used on URI parameters, as all URI parameters are mandatory.

Allow to specify a schema element in a larger schema

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
Clone this wiki locally