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.

  • get: Buscar um cliente
  • put: Alterar um cliente
  • delete: Deletar um cliente

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!