Introducción a RAML

RAML es un lenguaje de modelado para APIs RESTful. El nombre viene de las siglas (en inglés) RESTful API Modeling Language. Es de fácil lectura y escritura porque está basado en YAML y usa JSON para especificar las estructuras de datos (schemas).

Además de las ventajas de escribir nuestra API centrándonos en el contrato o interface que queremos ofrecer, se puede utilizar RAML para generar la documentación, el código cliente para consumirla, la estructura básica (scaffolding) del servicio o incluso un server que nos devuelva respuestas simuladas para hacer pruebas.

En este post vamos a ver los conceptos fundamentales, a través de ejemplos de RAML acompañados de una explicación básica de su significado. Para ello hagamos de cuenta que necesitamos armar una API de un catálogo de canciones.

Lo primero que necesito agregar es la versión de RAML que voy a usar (en este caso la 0.8), el título, ambos datos obligatorios, la URL base, que es opcional durante el desarrollo pero requerida cuando implementemos y la versión de la API:

#%RAML 0.8
title: Cancionero API
baseUri:http://cancionero.com.ar/api/{version}
version: v1

 

Las cosas que definamos a nivel de la raíz aplican para el resto del documento, por ejemplo podemos especificar que nuestra API utiliza por defecto json para intercambiar datos:

mediaType: application/json

 

Esto es práctico porque nos evita tener que hacerlo cada vez que definamos un request o response. Sin embargo RAML es muy flexible y nos permite cambiar ese valor por defecto para una acción particular.

Una vez que tenemos estos datos básicos podemos pasar a los recursos y sus métodos:

#%RAML 0.8
title: Cancionero API
baseUri: http://cancionero.com.ar/api/{version}
version: v1
mediaType: application/json
/canciones:
  get:
    description: obtiene todas las canciones del catálogo

 

Todos los recursos empiezan con “/”, dentro estarán los métodos que tiene ese recurso, en este ejemplo es un get.
La descripción es opcional pero recomendada en todos los casos por que es entonces fácil darse cuenta que al acceder con un GET a http://cancionero.com.ar/api/v1/canciones nuestra API devolverá un listado de las canciones en formato JSON.

Como este listado puede ser muy largo podemos usar parámetros en la URL (query string) para filtrarlo:

/canciones:
  get:
    description: obtiene todas las canciones del catálogo
    queryParameters:
      autor:
        description: autor o intérprete del tema
      genero:
        description: genero musical (rock, jazz, funk, etc.)

 

El tipo de dato por defecto es string, los tipos de datos posibles son: string, date, boolean, number, integer y file.
Un request ahora podría ser entonces http://cancionero.com.ar/api/v1/canciones?autor=pink+floyd

Si además queremos describir la respuesta:

/canciones:
  get:
    description: obtiene todas las canciones del catálogo
    queryParameters:
      autor:
        description: autor o intérprete del tema
      genero:
        description: genero musical (rock, jazz, funk, etc.)
    responses:
      200:
        body
          schema: |
            { "$schema": "http://json-schema.org/draft-03/schema",
              "type": "array",
              "description": "canciones",
              "items": 
                {
                  "type": "object",  
                  "properties": {
                    "id": { "type": "integer" },
                    "titulo": { "type": "string"},
                    "autor": { "type": "string"},
                    "genero": { "type": "string" },
                    "duracion":{ "type": "number" }
                }
              }
            }

 

En este caso estamos describiendo la respuesta cuando el status de la misma es 200. Para ello se usa un JSON Schema (en estos ejemplos son de la versión 3).

También podemos agregar un ejemplo de una respuesta:

          example: |
            [
              {
                 "id" : "1",
                 "titulo": "Black Dog",
                 "autor": "Pink Floyd",
                 "genero": "Rock",
                 "duracion": "4:54"
              },
              {
                 "id" : "2",	      
                 "titulo": "In the flesh",
                 "autor": "Pink Floyd",
                 "genero": "Rock",
                 "duracion": "4:15"
              },
              {
                 "id" : "3",
                 "titulo": "Paraíso",
                 "autor": "Spinetta y los socios del desierto",
                 "genero": "Rock",
                 "duracion": "5:21"
              }
            ]

 

Con esto nos quedó el método GET del recurso /canciones definido.
Vamos a agregar otro método al recurso, un POST para agregar canciones al catálogo:

  post:
    body:
      schema: |
        { "$schema": "http://json-schema.org/draft-03/schema",
          "type": "object",
          "description": "canción",
          "properties": 
          {
            "id": { "type": "integer" },
            "titulo": { "type": "string"},
            "autor": { "type": "string"},
            "genero": { "type": "string" },
            "duracion":{ "type": "number" }
          }
        }

 

Pero esperen un segundo, tendría sentido que cualquier usuario pueda agregar canciones a nuestro catálogo en forma anónima ?
Vamos a asumir que no y entonces volvemos a la raíz de nuestro RAML para agregar seguridad con OAuth 2:

#%RAML 0.8
title: Cancionero API
baseUri:http://cancionero.com.ar/api/{version}
version: v1
securitySchemes:
  - oauth_2_0:
      type: OAuth 2.0
      describedBy:
        headers:
          Authorization:
            description: utilizado para enviar el access token
            type: string
      settings:
        authorizationUri: https://cancionero.com.ar/oauth2/authorize
        accessTokenUri: https://cancionero.com.ar/oauth2/access_token
        authorizationGrants: [ code, token ]
        scopes:
          - basic
          - full

 

Una vez definido eso volvemos a nuestro POST y agregamos securedBy utitizando el nombre que le dimos a nuestro esquema de seguridad entre corchetes:

  post:
    securedBy: [oauth_2_0]

 

De esta forma para el recurso /canciones se pueden realizar pedidos GET de forma anónima pero no POST. Si en vez de eso quisiéramos que OAuth 2 aplique a toda la API tenemos que poner el securedBy en la raíz de nuestro RAML.

Los recursos se pueden anidar:

/canciones:
  get:
  /{id}:
    get:
      description: obtener los detalles de una canción por id
      responses:
        200:
          body:
            schema: |
              { "$schema": "http://json-schema.org/draft-03/schema",
                "type": "object",
                "description": "canción",
                "properties": 
                {
                  "id": { "type": "integer" },
                  "titulo": { "type": "string"},
                  "autor": { "type": "string"},
                  "genero": { "type": "string" },
                  "duracion":{ "type": "number" }
                }
              }

En este ejemplo el recurso anidado está encerrado entre corchetes, eso significa que es un parámetro.
Esto quiere decir que un request GET a /canciones/123 debería devolver una respuesta JSON con los datos de la canción que tiene ese Id.

De forma similar voy a agregar un método para borrar canciones por Id.

/canciones:
  get:
  /{id}:
    get:
      description: obtener los detalles de una canción por id
    delete:
      securedBy: [oauth_2_0]
      description: borrar una canción por id
      responses:
        200:
          description: la canción fue borrada

 

El securedBy nos está diciendo que como en el caso del POST, sólo un usuario autorizado podrá borrar canciones.

Qué pasa si el id no existe ? Puedo agregar una respuesta para especificar este caso usando el status Not Found (404) de HTTP:

/canciones:
  get:
  /{id}:
    delete:
      description: borrar una canción por id
      responses:
        200:
          description: la canción fue borrada
        404:
          description: no se encontró una canción con ese Id

 

Y con eso tenemos los conceptos básicos de RAML. El ejemplo completo que usamos lo podés bajar de acá: https://github.com/woodp/IntroRAML/blob/master/cancioneroAPI.raml

Hay mucho más para ver sobre RAML

Otros ejemplos:

– Notes Examples API: http://static-anypoint-mulesoft-com.s3.amazonaws.com/API_examples_notebooks/raml-design3.html

– Congo API for Drones Deliveries: http://static-anypoint-mulesoft-com.s3.amazonaws.com/API_examples_notebooks/raml-design1.html

– Remote Medicine Example API: http://static-anypoint-mulesoft-com.s3.amazonaws.com/API_examples_notebooks/raml-design4.html

 

El API Designer de MuleSoft, te permite crear y probar tus API’s:

http://www.mulesoft.com/platform/api/api-designer

 

Docs:

– Tutorial: http://raml.org/docs.html
– Spec: http://raml.org/spec.html

 

Parser y otros proyectos: http://raml.org/projects.html

Anuncios

2 comentarios en “Introducción a RAML

  1. Hello Pedro!
    I need your help to make some modifications in RAML Parser for .NET. I’d like to add support for new custom word in RAML scheme for local needs. I’m not an expert with coffeeScript and JS ecosystem, so could you explain how should I update/rebuild project (coffeeScript/js files) to make changes visible in .NET.

    Cheers,
    Andrey

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s