Índice
- Servicios Web RESTful (I) - Introducción
- Servicios Web RESTful (II) - API-First vs Code-First
- Servicios Web RESTful (III) - OpenAPI
- Servicios Web RESTful (IV) - OpenAPI Generator
Introducción
OpenAPI, anteriormente conocido como Swagger, es una especificación para describir servicios web RESTful. Permite a los desarrolladores definir la estructura y el comportamiento de una API de manera estandarizada y comprensible tanto para humanos como para máquinas.
Surgió del proyecto Swagger, iniciado en 2010 por Tony Tam. En 2015, SmartBear Software adquirió Swagger y en 2016, bajo el auspicio de la Fundación Linux, se estableció la Iniciativa OpenAPI para promover su desarrollo.
Se puede encontrar más información en el sitio oficial.
Especificación de OpenAPI
La definición de OpenAPI se puede realizar tanto en formato json como yaml, a partir de este punto seguiremos con este segundo formato.
Se compone de las siguientes secciones:
- openapi: es la versión utilizada de OpenAPI, no debe confundirse con la versión de la api que se está definiendo.
- info: da información sobre la api.
- servers: un listado de servidores para conectar con la api.
- paths: las rutas y operaciones que ofrece la api.
- components: contiene los distintos esquemas de los objectos usados en la api.
- security: define los mecanismos de seguridad necesarios para la autenticación y autorización contra la api.
- tags: sirven para dar información adicional.
- externalDocs: documentación externa.
Caso de uso
Aquí se muestra un ejemplo de lo que sería una posible definición de api con la que se verán los principales componentes de la misma y así mismo será la base para una posterior implementación práctica.
openapi: 3.0.4
info:
title: Sample API
description: API for use generation with maven plugin
version: 0.0.1
servers:
- url: http://localhost:8080/api
description: Local server
paths:
/users:
get:
summary: List of users
description: Returns the full list of users without filters
operationId: read
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/Users'
'500':
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
summary: Create or update a user
description: Create or update a new user
operationId: createOrUpdate
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/User'
required: true
responses:
'200':
description: Created or updated
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'500':
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/users/{id}:
get:
summary: User the current id
description: Returns the user filtered by id
operationId: readOne
parameters:
- name: id
in: path
description: user id
required: true
schema:
type: integer
format: int64
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: Not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Users:
type: array
items:
$ref: '#/components/schemas/User'
User:
type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
Error:
type: object
required:
- code
- message
properties:
code:
type: string
enum: [ "400-04", "500-00"]
message:
type: string
- El primer punto es la definición de la versión de OpenAPI que se va a utilizar, en este caso 3.0.4.
openapi: 3.0.4
- A continuación se muestra la información de la api, que incluye un título, una descripción y la versión actual:
info:
title: Sample API
description: API for use generation with maven plugin
version: 0.0.1
- En el apatado servers se definen los servidores contra los que se pueden realizar las llamadas, para el caso actual
localhost. Se compone de:- url del servidor.
- descripción del servidor.
servers:
- url: http://localhost:8080/api
description: Local server
- Bajo paths se definen los distintos endpoints disponibles que se componen de:
- La ruta relativa (la url completa se forma con el server más el path) al recurso.
- El método http sorportado, junto a información del mismo, así como posibles parámetros a enviar.
- En el caso de que exista (métodos POST y PUT) la estructura de la petición que se envía.
- Las posibles respuestas con la estructura de la información recibida.
paths:
/users: # ruta relativa que define /users
get: # método get permitido sobre /users
summary: List of users # resumen de la operación que realiza
description: Returns the full list of users without filters # descripción más detallada sobre la operación que realiza
operationId: read # se utiliza a la hora de generar el código para indicar el nombre del método encargado de la operación
responses: # listado de posibles respuestas
'200': # respuesta cuando todo es correcto con su descripción y contenido
description: Success
content:
application/json: # tipo del contenido, en este caso json
schema: # estructura de los datos que devuele, se utiliza una referencia para poder reutilizar las definiciones
$ref: '#/components/schemas/Users'
'500':
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put: # al estar definido sobre /users indica que aparte del get también se puede utilizar el método put
summary: Create or update a user
description: Create or update a new user
operationId: createOrUpdate
requestBody: # definición del contenido que se puede enviar en la petición (misma estructura que con las respuestas)
content:
application/json:
schema:
$ref: '#/components/schemas/User'
required: true # campo que indica si es obligatorio o no
responses:
'200':
description: Created or updated
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'500':
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/users/{id}: # una nueva ruta relativa, el que contenga {} indica que es un parámetro que va en el propio path
get:
summary: User the current id
description: Returns the user filtered by id
operationId: readOne
parameters: # parámetros que pueden ir en la petición, en este caso el del path
- name: id # nombre del parámetro
in: path # en este caso es a nivel de path, pero también podría ser a nivel de url (query), en una cabecera (header) o en una cookie (cookie)
description: user id # descripción del campo
required: true # si es obligatorio
schema: # tipo, en este caso se indica directamente que es un número
type: integer
format: int64
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: Not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
- Por último en el apartado componentes se definen las estructuras de datos que se pueden enviar o recibir como se ha visto mediante el uso de $ref.
components:
schemas:
Users: # estructura de los usuarios
type: array # es una seria de elementos
items:
$ref: '#/components/schemas/User' # cada elemento es de tipo User
User:
type: object # es una estructura que se componene de id y name y ambos son obligatorios
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
Error:
type: object
required:
- code
- message
properties:
code:
type: string
enum: [ "400-04", "500-00"] # en el caso de que una propiedad tenga que tener valores concretos, se define de esta manera
message:
type: string
Conclusión
Con OpenAPI se puede definir completa y claramente la estructura de las operaciones de un servicio que siguiendo el enfoque de API-First será la base para la generación de los servidores y clientes, punto que continuará en el último de esta serie de artículos:Servicios Web RESTful (IV) - OpenAPI Generator.
Para profundizar más sobre los contratos OpenAPI Specification.