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,AllowAnonymouseRequireTenant: 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
IFormFileeDisableAntiforgery()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
- Crie ou revise a entidade, commands e queries que representam o caso de uso.
- Execute
lino api newe selecione serviço, módulo e entidade corretos. - Escolha o tipo de operação pelo caso de uso, não apenas pelo verbo HTTP desejado.
- Defina rota estável, usando constraints como
{id:int}ou{id:guid}quando apropriado. - Selecione apenas propriedades que devem cruzar a fronteira HTTP.
- Defina autorização, permissão, tenant requirement, rate limiting e status codes esperados.
- 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
GETpara leitura,POSTpara criação/ações,PUT/PATCHpara alteração eDELETEpara 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 listpara 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.csdelega 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
Program.csconstrói a aplicação e chama a extension de endpoints do serviço ou módulo.- A extension cria o API version set e o endpoint group, aplica autorização/rate limiting e chama
MapEndpointsGenerated(). - O mapper gerado chama o método
MapEndpointde cada endpoint. - Cada endpoint mapeia rota, metadata OpenAPI, permissão, tenant requirement e handler.
- 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.
| Status | Uso típico | Exemplo |
|---|---|---|
| 400 Bad Request | Entrada inválida ou erro de validação. | Campo obrigatório ausente, formato inválido, regra de request quebrada. |
| 401 Unauthorized | Usuário não autenticado. | Token ausente, expirado ou inválido. |
| 403 Forbidden | Usuário autenticado sem permissão. | Permissão exigida por RequirePermission não concedida. |
| 404 Not Found | Recurso inexistente ou fora do escopo permitido. | ProductNotFound, entidade de outro tenant ou identificador desconhecido. |
| 409 Conflict | Conflito 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.
