Vamos continuar implementando nossa API utilizando Contract First. Para melhor aprendizado, vamos usar a mesma estrutura da primeira etapa, porém agora iremos trabalhar com um recurso que podemos implementar um CRUD.
Vamos implementar um CRUD simples de clientes, onde não iremos focar nas regras de negócio, mas sim na interface da API. A principal alteração vai acontecer no api.yml que estará em destaque deste artigo. Vamos conhecer alguns padrões do Swagger e alguns exemplos do que o Swagger pode nos oferecer.
Como essa documentação serve, tanto para o desenvolvedor que vai implementar essa API, tanto para um cliente que não é técnico, não faz sentido esse documento estar somente dentro de um projeto. Pensando nisso temos um repositório de APIS que se chama Swaggerhub, onde podemos subir e visualizar as especificações. Hoje vamos trabalhar com essa API: https://app.swaggerhub.com/apis/redspark7/cliente/1.0.0
openapi: 3.0.0
info:
description: API para trabalhar com Clientes
version: "1.0.0"
title: Cliente API
contact:
email: adm@redspark.io
license:
name: Apache 2.0
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
servers:
- url: /v1
Neste inicio só adicionamos mais informações, como contato de quem vai cuidar essa APINeste inicio só adicionamos mais informações, como contato de quem vai cuidar essa API
paths:
/cliente:
get:
operationId: getAllclientes
summary: Buscar todos os clientes
responses:
200:
$ref: '#/components/responses/OkList'
500:
$ref: '#/components/responses/ErroGenerico'
post:
operationId: postCliente
summary: Realiza a criação de um cliente
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ClienteRequest'
responses:
201:
$ref: '#/components/responses/Criado'
400:
description: '#components/responses/ErroEnvio'
500:
$ref: '#/components/responses/ErroGenerico'
Aqui estamos adicionando dois endpoints no path /cliente, pois são os únicos que não responder nesse caminho. O primeiro irá retornar todos os clientes e o segundo vai adicionar um novo cliente. Veja que nos lugares dos parâmetros de envio e responses, eles são componentes, vamos entender eles mais abaixo.
/cliente/{id}:
parameters:
- in: path
name: id
schema:
type: integer
format: int64
required: true
example: 1
description: id do cliente
Estamos definindo um novo caminho com uma variável “id”. O novo path ficaria /cliente/{id}. Um detalhe bem legal é que estamos definindo essa variável do tipo path para todos os métodos que estiverem dentro desse caminho.
get:
operationId: getCliente
summary: Pegar um cliente
responses:
200:
$ref: '#/components/responses/Ok'
404:
$ref: '#/components/responses/NotFound'
500:
$ref: '#/components/responses/ErroGenerico'
put:
operationId: putCliente
summary: Alterar um cliente ja existente
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ClienteRequest'
responses:
202:
$ref: '#/components/responses/Aceito'
404:
$ref: '#/components/responses/NotFound'
500:
$ref: '#/components/responses/ErroGenerico'
delete:
operationId: deleteCliente
summary: deletar um cliente
responses:
204:
$ref: '#/components/responses/SemConteudo'
404:
$ref: '#/components/responses/NotFound'
500:
$ref: '#/components/responses/ErroGenerico'
Neste trecho, estamos definindo os restantes dos endpoints que iremos trabalhar.
Veja que em nenhum momento define a variável id na request deles e todos utilizando componentes.
components:
responses:
Ok:
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/ClienteResponse'
OkList:
description: retorno da lista
content:
application/json:
schema:
$ref: '#/components/schemas/ClienteResponseList'
Criado:
description: Criado com sucesso
content:
application/json:
schema:
$ref: '#/components/schemas/ClienteResponse'
Aceito:
description: Aceito
content:
application/json:
schema:
$ref: '#/components/schemas/ClienteResponse'
SemConteudo:
description: Recurso deletado
NotFound:
description: cliente não encontrado
ErroEnvio:
description: Erro de envio de cliente
ErroGenerico:
description: Erro Interno do servidor
Aqui estamos criando componente do tipo response para todos os retornos possíveis, algum somente uma mensagem simples e outras encapsulados atrás da propriedade “$ref” um objeto. Esses objetos vão ser criados logo abaixo.
schemas:
ClienteResponse:
type: object
description: objeto que representa um cliente
required:
- id
- nome
- dataNascimento
- profissao
- cnpj
- email
properties:
id:
type: string
example: 1
nome:
type: string
example: Vinicius Monteiro
dataNascimento:
type: string
format: full-date
example: 2020-02-21
profissao:
type: string
example: Analista de Sistemas
cnpj:
type: integer
format: int32
example: 1234567890
email:
type: string
format: email
example: adm@redspark.io
ClienteRequest:
type: object
description: objeto que representa um cliente
required:
- nome
- dataNascimento
- profissao
- cnpj
- email
properties:
nome:
type: string
example: Vinicius Monteiro
dataNascimento:
type: string
format: full-date
example: 2020-02-21
profissao:
type: string
example: Analista de Sistemas
cnpj:
type: integer
format: int32
example: 1234567890
email:
type: string
format: email
example: adm@redspark.io
Agora iremos criar os objetos dentro de “schemas”. Basicamente temos dois objetos bem parecidos, o ClienteResponse com a propriedade (id) e o ClienteRequest sem. Definimos o tipo deles como objeto, uma pequena descrição, determinamos quais campos serão obrigatórios (no nosso caso serão todos) e cada campo colocar o tipo dele uma formatação e um pequeno exemplo que vai auxiliar quem estiver tentando entender nosso serviço olhando somente nossa documentação.
ClienteResponseList:
type: array
items:
$ref: '#/components/schemas/ClienteResponse'
Por último temos um schema do tipo array referenciando um objeto já criado (ClienteResponse), assim teremos uma lista desse tipo.
Com isso já temos nossa interface definida. Veja a implementação complete no link: https://github.com/vqmonteiro/Cliente
No próximo passo iremos trabalhar mais alguns tipos de campo dentro do swagger e implementar uma lógica de tratativa de erro mais interessante. Até mais!