Modelando APIs REST com Swagger
7 minutos de leitura


Autor(a)
alexandre.aquiles
Inscreva-se em nossa Newsletter
Fique por dentro de conteúdos, insights e oportunidades do universo tech. Receba novidades e lançamentos direto no seu e-mail.
7 minutos de leitura

Autor(a)
Fique por dentro de conteúdos, insights e oportunidades do universo tech. Receba novidades e lançamentos direto no seu e-mail.
Atualmente é bem comum que empresas utilizem APIs REST para a integração de aplicações, seja para consumir serviços de terceiros ou prover novos serviços.
Ao consumir uma API existente, precisamos conhecer as funcionalidades disponíveis e detalhes de como invocá-las: recursos, URIs, métodos, Content-Types e outras informações.
Ao prover uma nova API REST, além da implementação, há outras duas preocupações comuns: como modelar e documentar a API?
Em um Web Service do estilo SOAP temos o WSDL, que funciona como uma documentação (para máquinas) do serviço, facilitando a geração automatizada dos clientes que vão consumi-lo. Além disso, podemos modelar nosso serviço escrevendo o WSDL, em uma abordagem conhecida como Contract-First. Não é nada legível nem fácil de escrever, mas funciona. Só que no mundo dos Web Services REST não temos o WSDL. E agora?
Algumas ferramentas para nos auxiliar nessa questão foram criadas, e dentre elas temos: WSDL 2.0, WADL, API Blueprint, RAML e Swagger.
Neste post vamos abordar o Swagger, que é uma das principais ferramentas utilizadas para modelagem, documentação e geração de código para APIs do estilo REST.
O Swagger é um projeto composto por algumas ferramentas que auxiliam o desenvolvedor de APIs REST em algumas tarefas como:
Para isso, o Swagger especifica a OpenAPI, uma linguagem para descrição de contratos de APIs REST. A OpenAPI define um formato JSON com campos padronizados (através de um JSON Schema) para que você descreva recursos, modelo de dados, URIs, Content-Types, métodos HTTP aceitos e códigos de resposta. Também pode ser utilizado o formato YAML, que é um pouco mais legível e será usado nesse post.
Além da OpenAPI, o Swagger provê um ecossistema de ferramentas. As principais são:
Nesse post, vamos focar na parte de modelagem de uma nova API. Futuramente teremos outro post focando na documentação de uma API já existente.
Para modelar nossa nova API, utilizaremos o Swagger Editor. Você pode instalá-lo localmente, executando uma aplicação NodeJS, ou utilizar a versão online em editor.swagger.io.
Vamos modelar a API da Payfast, uma aplicação de pagamentos bem simples que é estudada no curso SOA na prática.
Pra começar, devemos definir algumas informações iniciais, como a versão do Swagger que estamos usando: ```ruby swagger: '2.0'
O título, descrição e versão da API devem ser definidos: ```ruby
info: title: Payfast API description: Pagamentos rápidos version: 1.0.0
Em host, inserimos o endereço do servidor da API, em basePath colocamos o contexto da aplicação e em schemes informamos se a aplicação aceita HTTP e/ou HTTPS.
host: localhost:8080 basePath: /fj36-payfast/v1 schemes: - http - https
De alguma forma, precisamos definir quais dados são recebidos e retornados pela API.
Na nossa API, recebemos dados de uma Transação, que tem um código, titular, data e valor. A partir disso, geramos um Pagamento com id, status e valor.

Em um WSDL, esse modelo de dados é definido através de um XML Schema (XSD). No caso do Swagger, o modelo de dados fica em um JSON Schema na seção definitions do contrato.
De acordo com o JSON Schema, em type podemos usar tipos primitivos de dados para números inteiros (integer), números decimais (number), textos (string) e booleanos (boolean). Esses tipos primitivos podem ser modificados com a propriedade format. Para o tipo integer temos os formatos int32 (32 bits) e int64 (64 bits, ou long). Para o number, temos os formatos float e double. Não há um tipo específico para datas, então temos que utilizar uma string com o formato (só data) ou (data e hora).
Além dos tipos primitivos, podemos definir objetos com um type igual a object. Esses objetos são compostos por várias outras propriedades, que ficam em properties.
No nosso caso, o modelo de dados com os objetos Transacao e Pagamento ficaria algo como:
definitions: Transacao: type: object properties: codigo: type: string titular: type: string data: type: string format: date valor: type: number format: double Pagamento: type: object properties: id: type: integer format: int32 status: type: string valor: type: number format: double
Com o modelo de dados pronto, precisamos modelar os recursos da nossa API e as respectivas URIs. No Payfast, teremos o recurso Pagamento acessível pela URI /pagamentos.
Um POST em /pagamentos cria um novo pagamento. Se o pagamento criado tiver o id 1, por exemplo, as informações estariam acessíveis na URI /pagamentos/1.
Podemos fazer duas coisas com o nosso pagamento: para confirmá-lo, devemos enviar um PUT para /pagamentos/1; para cancelá-lo, enviamos um DELETE.

No Swagger, as URIs devem ser descritas na seção paths:
paths: /pagamentos: post: summary: Cria novo pagamento
/pagamentos/{id}: put: summary: Confirma um pagamento delete: summary: Cancela um pagamento
Para a URI /pagamentos, que recebe um POST, é enviada uma transação no corpo da requisição, que deve estar no formato JSON. É feita uma referência ao modelo Transacao definido anteriormente.
paths: /pagamentos: post: summary: Cria novo pagamento consumes: - application/json parameters: - in: body name: transacao required: true schema: $ref: '#/definitions/Transacao'
Já para a URI /pagamentos/{id}, é definido um path parameter com o id do pagamento. Esse parâmetro pode ser descrito na seção parameters, logo acima da seção paths, e depois referenciado nos métodos.
parameters: pagamento-id: name: id in: path description: id do pagamento type: integer format: int32 required: true paths: /pagamentos: #código omitido...
/pagamentos/{id}: put: summary: Confirma um pagamento parameters: - $ref: '#/parameters/pagamento-id' delete: summary: Cancela um pagamento parameters: - $ref: '#/parameters/pagamento-id'
Definidos os parâmetros de request, precisamos modelar o response.
Depois da criação do pagamento, deve ser retornado um response com o status 201 (Created) juntamente com a URI do novo pagamento no header Location e uma representação em JSON no corpo da resposta.
paths: /pagamentos: post: summary: Cria novo pagamento consumes: - application/json produces: - application/json #código omitido... responses: '201': description: Novo pagamento criado schema: $ref: '#/definitions/Pagamento' headers: Location: description: uri do novo pagamento type: string
Após a confirmação de um pagamento, é simplesmente retornado o status 200 (OK). O mesmo retorno acontece após um cancelamento.
/pagamentos/{id}: put: summary: Confirma um pagamento parameters: - $ref: '#/parameters/pagamento-id' responses: '200': description: 'Pagamento confirmado' delete: summary: Cancela um pagamento parameters: - $ref: '#/parameters/pagamento-id' responses: '200': description: 'Pagamento cancelado'
O contrato final do exemplo utilizado pode ser aberto no Swagger Editor em: bit.ly/swagger-editor-payfast-api
Perceba que no menu superior temos a opção Generate Server para gerar um esqueleto do servidor em Java (JAX-RS e Spring-MVC), PHP (Slim e Silex), Python (Flask), entre outras tecnologias. Há também a opção Generate Client, que gera clientes nessas tecnologias e em diversas outras.
A abordagem utilizada nesse post foi a conhecida como Contract-First ou API-First Development.
Modelamos a API pensando nos dados, nos recursos, URIs, métodos, parâmetros e respostas. Começamos a definição do serviço criando primeiro a API de comunicação, para só posteriormente pensar na implementação.
Esta abordagem gera um desacoplamento entre implementação e interface de uso, além de permitir que tando o lado cliente quanto o lado servidor possam iniciar seu desenvolvimento assim que a API estiver definida, mesmo sem uma implementação finalizada.
Uma outra abordagem (talvez mais comum) é começar pela implementação para só depois pensar na documentação e talvez realizar ajustes de modelagem. Essa abordagem é conhecida como Contract-Last e o uso dela com Swagger será abordado em outro post.
E você? Já usou o Swagger em algum projeto para modelar uma nova API, no estilo Contract-First? Conte-nos como foi a experiência!
Avalie este artigo
datedate-time