Desarrollo de API

Las APIs son el límite HTTP de un servicio Lino. Exponen casos de uso de la capa de aplicación sin mezclar preocupaciones de transporte con reglas de dominio. Este capítulo explica cómo Lino genera Minimal APIs, contratos de solicitud/respuesta, typed clients, metadatos OpenAPI y registro automático de endpoints por parte de los source generators.


El endpoint generado debe mantenerse delgado: recibe datos HTTP, ensambla un comando o consulta, lo envía a la capa de aplicación a través de ISender y convierte el resultado en una respuesta tipada. La validación, las reglas de negocio, la persistencia, las transacciones y la autorización de dominio continúan en comandos, consultas, manejadores, validadores, repositorios y Unit of Work.

Minimal APIs en Lino

Lino adopta el núcleo ASP.NET Minimal APIs como estándar para generar endpoints, porque mantienen el código directo, explícito y funcional sin romper los límites de Clean Architecture.

En los proyectos actuales Lino, los endpoints generados son clases de Minimal API que implementan IEndpoint. Cada endpoint expone un método estático MapEndpoint(IEndpointRouteBuilder app) y un método handler que utiliza ISender para enviar el comando o consulta generado a la capa de Aplicación.

Partes principales generadas

  • *Endpoint.cs: mapea el método HTTP, ruta, metadatos, autorización, tenant requirement, rate limiting y versión.
  • *Request.cs: representa la entrada proveniente del cuerpo, cadena de consulta, parámetros de ruta o datos del formulario.
  • *Extensions.cs: convierte la request en command/query y convierte el resultado de la aplicación en respuesta HTTP.
  • *Response.cs: define el contrato fuertemente tipado devuelto por el endpoint y los typed clients.

Funciones integradas

Lino usa TypedResults y Results<...> para que las respuestas de éxito y error sean explícitas en el código y aparezcan correctamente en OpenAPI. Las fallas provenientes de la capa de Aplicación se convierten en ProblemDetails mediante result.MapToProblemDetails().

  • WithTags: Agrupa endpoints por módulo, entidad o característica en OpenAPI y Scalar.
  • WithName: establece un ID de operación coherente cuando corresponda.
  • WithSummary: describe claramente el propósito del endpoint.
  • Produces(statusCode, schema): especifica códigos de estado y contratos de respuesta.
  • MapToApiVersion(1, 0): asocia el endpoint con la versión API.
  • RequirePermission, RequireAuthorization, AllowAnonymous y RequireTenant: aplicar seguridad según las opciones del proyecto.
  • Limitación de velocidad a nivel de grupo o endpoint, utilizando políticas autenticadas o anónimas según la configuración.

Solicitudes y respuestas

Por defecto, Lino usa records para requests y responses. Son concisos, inmutables por defecto y funcionan bien como contratos explícitos entre API, typed clients y consumidores externos.

  • Las solicitudes recibidas a través del endpoint se transforman en Commands o Queries.
  • Los resultados de los commands o queries se convierten en respuestas.
  • Las entidades de dominio no deben exponerse directamente como contrato HTTP.
public record CreatePersonRequest(string Name, int Age);
public record CreatePersonResponse(Guid Id, string Name, int Age);

Creando nuevos API

Cree API mediante CLI cuando el modelo de dominio y el caso de uso ya sean lo suficientemente claros como para ser expuestos por HTTP. Las APIs conectan comandos y consultas a la capa de presentación a través de Minimal APIs, contratos, respuestas tipadas y metadatos de documentación.

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

El asistente interactivo le preguntará:

  • Servicio: servicio en el que se creará API.
  • Módulo: módulo de servicio, cuando corresponda.
  • Entidad o enumeración: elemento de dominio asociado con el endpoint.
  • Nombre de API: normalmente alineado con el verbo de la operación, como CreatePerson.
  • Tipo de operación: GET, POST, PUT, PATCH, DELETE, carga, descarga o opciones de endpoint.
  • Ruta: patrón de ruta, como /people/{id:guid}.
  • Propiedades: campos de solicitud y respuesta que realmente deben cruzar el límite HTTP.

Qué puede configurar el asistente

  • CONSEGUIR: resultado único, lista, lista paginada y opciones/escenarios seleccionados.
  • CORREO: creación y acciones comerciales, incluido el tipo de comando y las propiedades seleccionadas.
  • PONER y PARCHE: actualización completa o parcial.
  • BORRAR: eliminación asignada para eliminar comandos.
  • Subir: endpoints con IFormFile y DisableAntiforgery() cuando sea necesario.
  • Descargar: endpoints que retornan FileStreamHttpResult; los proyectos autenticados pueden generar un endpoint de token para un acceso seguro a los archivos.
  • Enumeraciones: endpoints que exponen opciones válidas por consulta y respuesta generadas.

Flujo recomendado

  1. Cree o revise la entidad, los comandos y las consultas que representan el caso de uso.
  2. Correr lino api new y seleccione el servicio, módulo y entidad correctos.
  3. Elija el tipo de operación por caso de uso, no solo por el verbo HTTP deseado.
  4. Defina una ruta estable, utilizando restricciones como {id:int} o {id:guid} cuando sea apropiado.
  5. Seleccione solo las propiedades que deben cruzar el límite HTTP.
  6. Defina autorización, permiso, requisitos de inquilino, limitación de tarifas y códigos de estado esperado.
  7. Ejecute la compilación e inspeccione Scalar/OpenAPI para confirmar la ruta, el resumen, la versión, la seguridad y las respuestas producidas.

Ejemplo: crear persona

Al crear un API POST llamar CreatePerson, asociado a la entidad Person, CLI genera endpoints, contratos de solicitud/respuesta, extensiones de mapeo, metadatos OpenAPI e integración con el comando correspondiente.

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

Contratos y typed clients

Cuando el proyecto tiene una Web App Blazor, Lino también genera artefactos para el consumo tipificado de API: contratos compartidos, interfaz de cliente e implementación de HTTP. Esto permite a Blazor consumir endpoints de una manera simple, consistente y fuertemente tipada.

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

La interfaz del cliente está registrada para la inyección de dependencia y la implementación utiliza HttpClientProvider con los ayudantes HTTP de Tolitech para llamar al API generado de forma inflexible.

Lista de verificación antes de publicar

  • Usar GET para leer, POST para creación/acciones, PUT/PATCH por el cambio y DELETE para su eliminación cuando tenga sentido.
  • No exponga entidades de dominio directamente como un contrato externo.
  • Errores de validación de documentos, conflictos, no encontrados y acceso denegado.
  • Usar api list para evitar rutas duplicadas o endpoints competitivos para el mismo caso de uso.

Registro de terminales con source generators

Lino evita mapear manualmente archivos grandes usando source generators. En lugar de enumerar los endpoints uno por uno en Program.cs, el registro se genera durante la compilación.

Implementación de clases de endpoint generadas IEndpoint de Tolitech.MinimalApis.Generators.Abstractions. Las llamadas del grupo de terminales MapEndpointsGenerated(), producido por Tolitech.MinimalApis.Generatorsy los nuevos endpoints se registran mediante el código generado.

¿Por qué esto importa?

  • Menos wiring manual: Los desarrolladores no necesitan recordar asignar cada endpoint manualmente.
  • Coherencia en tiempo de compilación: los endpoints siguen la misma estructura y se descubren mediante el código generado.
  • Inicio más limpio: Program.cs delega la configuración para configurar servicios, middleware y métodos de extensión.
  • Compatibilidad AOT: reduce la dependencia de la reflexión en tiempo de ejecución.
  • OpenAPI consistente: las etiquetas, resúmenes, códigos de estado y versión se generan en el endpoint.
  • Alineación arquitectónica: HTTP está en API, la orquestación pasa por MediatR y los contratos se pueden compartir con los clientes.

Flujo en tiempo de ejecución

  1. Program.cs construye la aplicación y llama a la extensión desde los endpoints del servicio o módulo.
  2. La extensión crea el conjunto de versiones API y el grupo de terminales, aplica autorización/rate limiting y llamadas MapEndpointsGenerated().
  3. El asignador generado llama al método. MapEndpoint de cada endpoint.
  4. Cada endpoint asigna la ruta, los metadatos OpenAPI, el permiso, los requisitos del inquilino y el controlador.
  5. El controlador recibe la entrada HTTP, la convierte en comando/consulta, la envía a MediatR y devuelve un resultado escrito.

Definiciones de errores

Las definiciones de errores estandarizan los fallos conocidos de dominios y aplicaciones. Ayudan a las APIs, handlers, registros y interfaces a manejar problemas predecibles sin depender de mensajes perdidos, cadenas duplicadas o decisiones ad hoc en cada endpoint.

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

En las APIs generados, los fallos esperados devueltos por comandos y consultas se deben convertir a ProblemDetails con código de estado, código de error y mensaje seguro. El servidor puede registrar logs técnicos detallados, pero la respuesta HTTP debe permanecer consistente, segura y localizable.

EstadoUso típicoEjemplo
400 Solicitud incorrectaEntrada no válida o error de validación.Falta un campo obligatorio, formato no válido, regla de solicitud incumplida.
401 No autorizadoUsuario no autenticado.Token faltante, caducado o no válido.
403 ProhibidoUsuario autenticado sin permiso.Permiso requerido por RequirePermission no concedido.
404 no encontradoRecurso inexistente o fuera del alcance permitido.ProductNotFound, entidad de otro inquilino o identificador desconocido.
409 ConflictoConflicto de estados o regla de unicidad.Registro duplicado, transición no válida, conflicto de versiones.

Buenas practicas

  • Cree definiciones de errores para fallas esperadas y reutilizables.
  • Evite devolver excepciones técnicas o detalles de infraestructura al cliente.
  • Mantenga códigos de error estables para que la interfaz, los typed clients y las pruebas puedan reaccionar de forma segura.
  • Documente en OpenAPI los códigos de estado que puede producir el endpoint.
  • Utilice logs del servidor para obtener detalles de diagnóstico y mensajes seguros en la respuesta pública.
Se ha producido un error no controlado. Recargar 🗙