Coder Social home page Coder Social logo

Comments (10)

huogerac avatar huogerac commented on August 28, 2024 4

Bem legal, ter esta tarefa para padronizar! criar algo inicial para ir modelando o lançamento e tratamento de erros.

Eu gostaria de apresentar aqui uma linha um pouco relacionado com isto, mas é mais abrangente, é o OpenAPI que tambem tem seu estilo de exibir os erros.

Por exemplo,
Vamos dizer que ao tentar obter uma Notícia via ID. E que este ID não existe na base:

  • A camada de serviço pode lançar um DoesntExistError
  • A camada de API captura e transforma em um 404 como uma mensagem amigável.
{
  "detail": "Tabnews ID: 42 not found!",
  "status": 404,
  "title": "Not Found",
  "type": "...."
}

Eu tentei criar uma versão bem inicial do OpenAPI para o tabnews, pensando mais nos status_code e input/output.
Segue abaixo:

## Validate it at: https://apitools.dev/swagger-parser/online/

openapi: 3.0.2

info:
  version: 0.1.0
  title: Tabnews (side project) API Backend
  description: API and database for auth, users and news
  contact:
    name: Tabnews
    email: [email protected]
    url: https://tabnews-web.vercel.app/

servers:
  - url: https://tabnewspy.herokuapp.com/api/
    description: Development

paths:
  /api/version:
    get:
      operationId: api.api_version
      summary: Returns the API version
      tags:
        - Status
      responses:
        200:
          description: Success

  /api/auth/login:
    post:
      operationId: api.auth.login
      summary: User login to get a JWT Token
      tags:
        - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - email
                - password
              properties:
                email:
                  type: string
                  example: [email protected]
                password:
                  type: string
                  example: "@bC1234"
      responses:
        200:
          description: JWT Access Token
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    $ref: "#/components/schemas/User"
                  token:
                    type: string
                    example: Encripted.JWT.Token
                  refresh_token:
                    type: string
                    example: Another.Encripted.JWT.Token.With.Long.Expiration
        400:
          description: Bad request. You must send an email and password
        401:
          description: Email or password is not valid

  /api/auth/github/login:
    get:
      operationId: api.auth.github_login
      description: Login github
      tags:
        - Auth
      responses:
        302:
          description: Redirect to the authorization

  /api/auth/github/authorize:
    get:
      operationId: api.auth.github_authorize
      description: Token
      tags:
        - Auth
      responses:
        302:
          description: Redirect to the frontend

  /api/tabnews:
    get:
      operationId: api.tabnews.list_tabnews
      summary: Returns the latest tabnews
      tags:
        - Tabnews

      responses:
        200:
          description: The lastest Tabnews
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Tabnews"

    post:
      operationId: api.tabnews.create_tabnews
      summary: Create a new Tabnews
      tags:
        - Tabnews
      security:
        - jwtAuth: [tabnews:create]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - title
              properties:
                title:
                  type: string
                  example: 101 facts that prove the Earth is flat
                  minLength: 12
                description:
                  type: string
                  example: Despite being a maiority, in absolute terms, few people know the real truth...

      responses:
        201:
          description: Tabnews created succesfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Tabnews"
        400:
          description: Invalid data to create a Tabnews
        401:
          description: No Authorization
        403:
          description: No Permission

components:
  securitySchemes:
    jwtAuth:
      type: oauth2
      x-tokenInfoFunc: services.token.check_token_info
      flows:
        authorizationCode:
          tokenUrl: "url"
          authorizationUrl: "url"

  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: John Doe
        email:
          type: string
          example: [email protected]

    Author:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: John Doe
        avatar:
          type: string
          example: http://example.com/img/avatar/jose_thumb.png
          nullable: true

    Tabnews:
      type: object
      properties:
        id:
          type: integer
          example: 42
        title:
          type: string
          example: Python is a great option for backend and APIs
        description:
          type: string
          nullable: true
        author:
          $ref: "#/components/schemas/Author"
        created_at:
          type: string
          format: date-time
          example: 2021-01-11T11:32:28Z

p.s:

  • Este YAML pode ser alterado online com este editor: https://editor.swagger.io/
  • Sei que a sugestão é não usar JWT, este YAML está com JWT, mas deve ser uma alteração pequena para usar autenticação via session/cookie
  • Pode notar que as permissões são com base em recursos ao invés de role

Também tentei integrar no Next-JS o OpenAPI, mas falhei miseravelmente:
https://github.com/jellydn/next-swagger-doc 😞

Dai acabei fazendo com uma stack que tenho mais conhecimento, então esta versão rodando no Heroku foi feita com Python/Flask

from tabnews.com.br.

filipedeschamps avatar filipedeschamps commented on August 28, 2024 3

Excelente pergunta @rhandrade ! Nós devemos usar os status code sim ao retornar a request no controller 👍 então como você já pode deduzir pelo status code se a request teve sucesso ou não, acho redundante colocar uma propriedade/flag a mais na resposta. Incusive a maioria das bibliotecas que consomem endpoints http vão escolher continuar ou jogar um erro dependendo do status code retornado.

O exemplo que coloquei é meio mock, mas sobre a parte de faltar alguns campos ali, a gente poderia usar o 400 Bad Request que é o mais comum... ou o 422 Unprocessable Entity que não é tão comum, mas é bem específico nessa condição, olha a descrição que legal:

The 422 (Unprocessable Entity) status code means the server
understands the content type of the request entity (hence a
415(Unsupported Media Type) status code is inappropriate), and the
syntax of the request entity is correct (thus a 400 (Bad Request)
status code is inappropriate) but was unable to process the contained
instructions. For example, this error condition may occur if an XML
request body contains well-formed (i.e., syntactically correct), but
semantically erroneous, XML instructions.

from tabnews.com.br.

rhandrade avatar rhandrade commented on August 28, 2024 3

Que maneiro @huogerac. Achei a ideia de usar a OpenAPI sensacional por ela já ser um padrão para descrever APIs bem difundido. Quanto ao exemplo que você deu talvez não seria necessário colocar o status code dentro do objeto, como o @filipedeschamps tinha comentado na minha dúvida...

Esses dias tava fuçando na API beta do OpenAI e curti o modo como eles retornam os erros, deixo um exemplo abaixo. A requisição nesse caso retornou um status code 404 com o seguinte objeto:

{
  "error": {
    "code": null,
    "message": "Engine not found",
    "param": null,
    "type": "invalid_request_error"
  }
}

from tabnews.com.br.

liverday avatar liverday commented on August 28, 2024 3

Criei um PR #129 como proposta da padronização dos erros utilizando o onErrorHandler do next-connect. Creio que a sugestão que o @filipedeschamps funciona muito bem, tanto nos casos de erros singulares, como nos erros múltiplos.

from tabnews.com.br.

rhandrade avatar rhandrade commented on August 28, 2024 2

Show @filipedeschamps, agora consegui entender melhor essa questão. Vlw 👍

from tabnews.com.br.

brunofamiliar avatar brunofamiliar commented on August 28, 2024 2

Olá pessoal! Essa issue foi resolvida no PR #131 certo? o que acham de fecharmos para focar nas pendências ainda existentes?

from tabnews.com.br.

rhandrade avatar rhandrade commented on August 28, 2024 1

Show @filipedeschamps... Pelo que entendi identificaríamos os erros pelo status code da requisição. Ai fiquei com uma dúvida.

No exemplo que você deu o erro ocorreu devido a uma regra da aplicação. Nesses casos devemos responder com um status 200, indicando que o servidor processou a requisição e por algum motivo deu erro e incluir uma flag dentro da resposta mostrando que teve um erro (tipo um "success": false), ou usamos os status 4xx para indicar isso, como um 400, por exemplo?

Sempre fico em dúvida nessa parte, porque fico tentado encontrar o melhor status code para descrever o problema retornado. No exemplo que você deu e olhando a definição do http status code, talvez o status 400 não seria a melhor opção, visto que o servidor conseguiu entender a requisição. 🤔

from tabnews.com.br.

filipedeschamps avatar filipedeschamps commented on August 28, 2024

Show pessoal, estou voltando nessa thread :)

Sobre um objeto de erro singular, como é feito no caso onde é preciso retornar múltiplos erros? Por exemplo numa validação de um formulário em que mais de 1 campo pode não passar na validação?

Mas sobre o OpenAPI num geral, ele é uma descrição de como a API funciona, e também define os padrões de resposta, e com isso consegue gerar documentação, correto? To pesquisando a respeito. Quem usa, fala muito bem, mas não to conseguindo achar uma adoção massiva ao ponto de me sentir confortável em colocar essa abstração em cima das respostas. Mas vou estudar mais a respeito 👍

Em paralelo, vejo também que é uma camada que dá para colocar por cima depois, e no estágio atual do projeto, podemos mudar qualquer interface pública que quisermos 🤝

from tabnews.com.br.

rhandrade avatar rhandrade commented on August 28, 2024

@filipedeschamps Acredito que quando forem muitos erros poderíamos retornar um array contendo vários objetos erros, cada qual com o erro que aconteceu.

O Laravel tem uma proposta semelhante se não estou enganado, no qual temos um objeto errors, no qual cada propriedade é um campo que causou o erro e o valor é um array contendo com todos os erros de validação para aquele campo.

Sobre a OpenAPI eu entendi isso ai tbm.

from tabnews.com.br.

filipedeschamps avatar filipedeschamps commented on August 28, 2024

Show @rhandrade o custom error consegue esperar um array de erros e retornar no errors um array 👍

@brunofamiliar corretíssimo e valeu pelo toque! Fechando a issue 😍

from tabnews.com.br.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.