Desenvolvendo APIs

APIs são a fronteira HTTP de um serviço Lino. Elas expõem casos de uso da camada de aplicação sem misturar preocupações de transporte com regras de domínio. Este capítulo explica como o Lino gera Minimal APIs, contratos de request/response, typed clients, metadados OpenAPI e registro automático de endpoints por source generators.


O endpoint gerado deve permanecer fino: recebe dados HTTP, monta um command ou query, envia para a Application layer por ISender e converte o resultado para uma resposta tipada. Validação, regras de negócio, persistência, transações e autorização de domínio continuam em commands, queries, handlers, validators, repositories e Unit of Work.

Minimal APIs no Lino

O Lino adota ASP.NET Core Minimal APIs como padrão para geração de endpoints, porque elas mantêm o código direto, explícito e performático sem quebrar as fronteiras da Clean Architecture.

Em projetos Lino atuais, endpoints gerados são classes de Minimal API que implementam IEndpoint. Cada endpoint expõe um método estático MapEndpoint(IEndpointRouteBuilder app) e um método handler que usa ISender para despachar o command ou query gerado para a camada de Application.

Peças principais geradas

  • *Endpoint.cs: mapeia método HTTP, rota, metadados, autorização, tenant requirement, rate limiting e versão.
  • *Request.cs: representa entrada vinda de body, query string, route parameters ou form data.
  • *Extensions.cs: converte request para command/query e converte o resultado da aplicação para response HTTP.
  • *Response.cs: define o contrato fortemente tipado retornado pelo endpoint e pelos typed clients.

Recursos integrados

O Lino usa TypedResults e Results<...> para que respostas de sucesso e erro fiquem explícitas no código e apareçam corretamente no OpenAPI. Falhas vindas da Application layer são convertidas para ProblemDetails por result.MapToProblemDetails().

  • WithTags: agrupa endpoints por módulo, entidade ou feature no OpenAPI e no Scalar.
  • WithName: define um operationId consistente quando aplicável.
  • WithSummary: descreve claramente o propósito do endpoint.
  • Produces(statusCode, schema): especifica status codes e contratos de resposta.
  • MapToApiVersion(1, 0): associa o endpoint à versão da API.
  • RequirePermission, RequireAuthorization, AllowAnonymous e RequireTenant: aplicam segurança conforme as opções do projeto.
  • Rate limiting em nível de grupo ou endpoint, usando políticas autenticadas ou anônimas conforme a configuração.

Requests e Responses

Por padrão, o Lino usa records para requests e responses. Eles são concisos, imutáveis por padrão e funcionam bem como contratos explícitos entre API, typed clients e consumidores externos.

  • Requests recebidos via endpoint são transformados em Commands ou Queries.
  • Resultados de Commands ou Queries são convertidos em Responses.
  • Entities de domínio não devem ser expostas diretamente como contrato HTTP.
public record CreatePersonRequest(string Name, int Age);
public record CreatePersonResponse(Guid Id, string Name, int Age);

Criando novas APIs

Crie APIs pela CLI quando o modelo de domínio e o caso de uso já estiverem claros o suficiente para serem expostos por HTTP. APIs conectam commands e queries à camada de apresentação por Minimal APIs, contracts, responses tipadas e metadata de documentação.

lino api new
lino api new --name <ApiName> --service <ServiceName> --module <ModuleName> --entity <EntityName>
lino api list --service <ServiceName> --module <ModuleName> --entity <EntityName>

O assistente interativo solicitará:

  • Serviço: serviço no qual a API será criada.
  • Módulo: módulo do serviço, quando aplicável.
  • Entidade ou enumeração: elemento do domínio associado ao endpoint.
  • Nome da API: normalmente alinhado ao verbo da operação, como CreatePerson.
  • Tipo de operação: GET, POST, PUT, PATCH, DELETE, upload, download ou endpoint de opções.
  • Rota: padrão de rota, como /people/{id:guid}.
  • Propriedades: campos de request e response que realmente devem cruzar a fronteira HTTP.

O que o wizard pode configurar

  • GET: resultado único, lista, lista paginada e cenários de opções/select.
  • POST: criação e ações de negócio, incluindo command type e propriedades selecionadas.
  • PUT e PATCH: atualização completa ou parcial.
  • DELETE: remoção mapeada para delete commands.
  • Upload: endpoints com IFormFile e DisableAntiforgery() quando necessário.
  • Download: endpoints retornando FileStreamHttpResult; projetos autenticados podem gerar endpoint de token para acesso seguro a arquivos.
  • Enumerações: endpoints que expõem opções válidas por query e response geradas.

Fluxo recomendado

  1. Crie ou revise a entidade, commands e queries que representam o caso de uso.
  2. Execute lino api new e selecione serviço, módulo e entidade corretos.
  3. Escolha o tipo de operação pelo caso de uso, não apenas pelo verbo HTTP desejado.
  4. Defina rota estável, usando constraints como {id:int} ou {id:guid} quando apropriado.
  5. Selecione apenas propriedades que devem cruzar a fronteira HTTP.
  6. Defina autorização, permissão, tenant requirement, rate limiting e status codes esperados.
  7. Rode build e inspecione Scalar/OpenAPI para confirmar rota, summary, versão, segurança e respostas produzidas.

Exemplo: CreatePerson

Ao criar uma API POST chamada CreatePerson, associada à entidade Person, o CLI gera endpoint, contracts de request/response, extensions de mapeamento, metadados OpenAPI e integração com o command correspondente.

<ProjectName>/
└── src/
    └── Services/
        └── <ServiceName>/
            └── Api/
                └── Endpoints/
                    └── People/
                        └── CreatePerson/
                            ├── CreatePersonEndpoint.cs
                            ├── CreatePersonExtensions.cs
                            ├── CreatePersonRequest.cs
                            └── CreatePersonResponse.cs

Contracts e typed clients

Quando o projeto possui Web App Blazor, o Lino também gera artefatos para consumo tipado das APIs: contratos compartilhados, interface do client e implementação HTTP. Isso permite que o Blazor consuma endpoints de forma simples, consistente e com tipagem forte.

<ProjectName>/
└── src/
    └── Services/
        └── <ServiceName>/
            ├── Api.Contracts/
            │   └── Features/
            │       └── People/
            │           ├── CreatePerson/
            │           │   ├── CreatePersonRequest.cs
            │           │   └── CreatePersonResponse.cs
            │           └── IPersonApiClient.cs
            └── Api.Client/
                └── Features/
                    └── PersonApiClient.cs

A interface do client é registrada para dependency injection, e a implementação usa HttpClientProvider com helpers HTTP da Tolitech para chamar a API gerada de forma fortemente tipada.

Checklist antes de publicar

  • Use GET para leitura, POST para criação/ações, PUT/PATCH para alteração e DELETE para remoção quando fizer sentido.
  • Não exponha entidades de domínio diretamente como contrato externo.
  • Documente erros de validação, conflito, não encontrado e acesso negado.
  • Use api list para evitar rotas duplicadas ou endpoints concorrentes para o mesmo caso de uso.

Registro de Endpoints com Source Generators

O Lino evita arquivos grandes de mapeamento manual usando source generators. Em vez de listar endpoints um a um em Program.cs, o registro é produzido durante a compilação.

Classes de endpoint geradas implementam IEndpoint de Tolitech.MinimalApis.Generators.Abstractions. O grupo de endpoints chama MapEndpointsGenerated(), produzido por Tolitech.MinimalApis.Generators, e novos endpoints passam a ser registrados por código gerado.

Por que isso importa

  • Menos wiring manual: desenvolvedores não precisam lembrar de mapear cada endpoint manualmente.
  • Consistência em tempo de compilação: endpoints seguem a mesma estrutura e são descobertos por código gerado.
  • Startup mais limpo: Program.cs delega setup para configuração de serviços, middleware e extension methods.
  • Compatibilidade AOT: reduz dependência de reflection em runtime.
  • OpenAPI consistente: tags, summaries, status codes e versão são gerados junto ao endpoint.
  • Alinhamento arquitetural: HTTP fica na API, orquestração passa por MediatR, e contratos podem ser compartilhados com clients.

Fluxo em runtime

  1. Program.cs constrói a aplicação e chama a extension de endpoints do serviço ou módulo.
  2. A extension cria o API version set e o endpoint group, aplica autorização/rate limiting e chama MapEndpointsGenerated().
  3. O mapper gerado chama o método MapEndpoint de cada endpoint.
  4. Cada endpoint mapeia rota, metadata OpenAPI, permissão, tenant requirement e handler.
  5. O handler recebe entrada HTTP, converte para command/query, envia por MediatR e retorna um typed result.

Definições de erro

Definições de erro padronizam falhas conhecidas de domínio e aplicação. Elas ajudam APIs, handlers, logs e frontend a tratar problemas previsíveis sem depender de mensagens soltas, strings duplicadas ou decisões ad hoc em cada endpoint.

lino error-definition new --name <ErrorDefinitionName> --service <ServiceName> --module <ModuleName> --entity <EntityName>
lino error-definition list --service <ServiceName> --module <ModuleName> --entity <EntityName>

Em APIs geradas, falhas esperadas retornadas por commands e queries devem ser convertidas para ProblemDetails com status code, código de erro e mensagem segura. O servidor pode registrar logs técnicos detalhados, mas a resposta HTTP deve permanecer consistente, segura e localizável.

StatusUso típicoExemplo
400 Bad RequestEntrada inválida ou erro de validação.Campo obrigatório ausente, formato inválido, regra de request quebrada.
401 UnauthorizedUsuário não autenticado.Token ausente, expirado ou inválido.
403 ForbiddenUsuário autenticado sem permissão.Permissão exigida por RequirePermission não concedida.
404 Not FoundRecurso inexistente ou fora do escopo permitido.ProductNotFound, entidade de outro tenant ou identificador desconhecido.
409 ConflictConflito de estado ou regra de unicidade.Registro duplicado, transição inválida, version conflict.

Boas práticas

  • Crie error definitions para falhas esperadas e reutilizáveis.
  • Evite retornar exceções técnicas ou detalhes de infraestrutura ao cliente.
  • Mantenha códigos de erro estáveis para que frontend, typed clients e testes possam reagir com segurança.
  • Documente no OpenAPI os status codes que o endpoint pode produzir.
  • Use logs no servidor para detalhes diagnósticos e mensagens seguras no response público.
Ocorreu um erro não tratado. Recarregar 🗙