1

Diseñando y documentando tus APIs utilizando RAML

La mayoría de los proyectos en los que participamos en mi trabajo requieren diseñar e implementar APIs de acceso para las aplicaciones móviles y webapps. Este diseño requiere definir un sistema de autenticación (por ejemplo uno basado en tokens como puede ser JWT) y cada uno de los endpoints que serán accesibles. En esta definición de endpoints debemos decidir que campos de entrada y de salida tendrá cada uno.

Para diseñar una buena API se requiere emplear los verbos HTTP adecuadamente utilizando RESTFul, pero también debemos de implementar un diseño intuitivo, una buena documentación y que ésta represente fielmente a la implementación. A parte de que la implementación sea buena, es muy importante que la documentación asociada a ella sea completa y esté actualizada al 100% teniendo controlado el comportamiento esperado por cada request. En mi opinión, mantener este compromiso suele ser bastante complicado pero utilizando las herramientas adecuadas se puede simplificar y beneficiar al equipo de desarrollo, y a los futuros desarrolladores que se puedan encargar del desarrollo software.

¿Que es RAML y por qué usarlo en nuestras APIs?

RAML es el acrónimo de “Restful Api Modeling Language” y se trata de un lenguaje de modelado para definir apis REST con una sintaxis bastante sencilla y fácilmente comprensibles tanto para seres humanos como para sistemas software. Este lenguaje permite definir recursos, métodos, parámetros, respuestas, tipos de medios y otros componentes HTTP básicos. Básicamente es una especificación no propietaria y totalmente independiente basada en YAML y JSON. En otras palabras, lo que nos permite es escribir la especificación de las apis siguiendo un estándar.

La gran ventaja de implementar API con RAML es que te centras totalmente en el “contrato” que ofrece el endpoint; esto permite comenzar generando la documentación, para la cual una vez esté lista, existen distintos generadores que nos generan el “scaffolding” básico del servicio e incluso servicios que nos devuelvan respuestas simuladas para arrancar con nuestro testing.

Esta metodología favorece el proceso de testing aportándonos el entorno perfecto para usar TDD. Básicamente, definimos la api, escribimos tests para consumir esa api y empezamos a construir la implementación real y necesaria para validar tanto los tests como la especificación descrita.

¿Como escribir RAML?

Puedes escribirlo tan solo con un fichero normal con la extensión .raml y procesarlo con distintas herramientas. Personalmente usamos una herramienta oficial de Mulesoft llamada Api Designer (https://github.com/mulesoft/api-designer). Esta herramienta es un editor construido con angularjs y que puedes instalar a través de NPM en tu ordenador.

npm install -g api-designer

Ejemplo de diseño en RAML

#%RAML 0.8title: examle 
version:1.0baseUri: http://example.local/api
traits:
  - secured:
      description: Some requests require authentication
      headers:
        X-User:
          description: Token to authenticate the user
          required: true
  - unsecured:
      description: This is not secured
  - pageable:
      queryParameters:        offset:          description: Skip over a number of elements by specifying an offset value for the query
          type: integer
          required: false
          example:20          default:0        limit:          description: Limit the number of elements on the response
          type: integer
          required: false
          example:80          default:10
  - unauthorized:
      responses:401:
          description: User Not Authorized, token invalid
          body:
            application/json:
              schema: |
                {
                  "$schema": "http://json-schema.org/schema#",
                  "type": "object",
                  "description": "User not authorized",
                  "properties": {
                    "error": {
                      "description": "The error definition",
                      "type": "string"
                    }
                  },
                  "required": ["error"]
                }
              example: |
                {
                  "code": 401,
                  "error": "Not Authorized"
                }
  - badRequest:
      responses:400:
          description: Bad Request
          body:
            application/json:
              example: |
                {
                  "code": 400,
                  "error": "Bad Request"
                }
                         
  - internalError:
      responses:500:
          description: Internal Server Error
          body:
            application/json:
              schema: |
                {
                  "$schema": "http://json-schema.org/schema#",
                  "type": "object",
                  "description": "Internal Server Error",
                  "properties": {
                    "error": {
                      "description": "The error definition",
                      "type": "string"
                    }
                  },
                  "required": ["error"]
                }
              example: |
                {
                  "error": "Internal Server Error"
                }
  - missingParams:
      responses:400:
          description: Bad Request, parameters missing
          body:
            application/json:
              schema: |
                {
                  "$schema": "http://json-schema.org/schema#",
                  "type": "object",
                  "description": "Parametter Missing",
                  "properties": {
                    "error": {
                      "description": "The error definition",
                      "type": "string"
                    }
                  },
                  "required": ["error"]
                }
              example: |
                {
                  "error": "Parametter Missing"
                }
                
/callback/order:
 /sim:
    displayName: postSimOrderAction
    description: Set New Sim from External Provider
    is: [ unauthorized, internalError]
    post:      is: [ unauthorized, internalError]
      description:" Set New Sim from External Provider"      body:
        application/json:
          schema: callbacksim
          example: |
            {
             "trackingId": "dsn16zueuw",
             "iccid": "89341231321312",
             "checksum": "4d4fdcca079a2c98ef327f597b6cadfe8731feec94d8d2aabfcfe3db66d98410ca0201fc3df419a7534843f03fcbefe3afe4d9917f37719863254b45ae71fdf1"
            }
      responses:200:
          body:
            application/json:
              example: |
                {
                  "result": "OK",
                }
 /contract:
    displayName: postSignContractOrderAction
    description: Set ContractSign from External Provider
    is: [ unauthorized, internalError]
    post:      is: [ unauthorized, internalError]
      description:" Set New Sim from External Provider"      body:
        application/json:
          schema: callbacksigncontract
          example: |
            {
             "trackingId": "dsn16zueuw",
             "date": "16/02/2016 15:23",
             "checksum": "4d4fdcca079a2c98ef327f597b6cadfe8731feec94d8d2aabfcfe3db66d98410ca0201fc3df419a7534843f03fcbefe3afe4d9917f37719863254b45ae71fdf1"
            }          
      responses:200:
          body:
            application/json:
              example: |
                {
                  "result": "OK",
                }

Escribe tu comentario
+ 2