Jarvis.WebApi
3.0.1.3
dotnet add package Jarvis.WebApi --version 3.0.1.3
NuGet\Install-Package Jarvis.WebApi -Version 3.0.1.3
<PackageReference Include="Jarvis.WebApi" Version="3.0.1.3" />
<PackageVersion Include="Jarvis.WebApi" Version="3.0.1.3" />
<PackageReference Include="Jarvis.WebApi" />
paket add Jarvis.WebApi --version 3.0.1.3
#r "nuget: Jarvis.WebApi, 3.0.1.3"
#:package Jarvis.WebApi@3.0.1.3
#addin nuget:?package=Jarvis.WebApi&version=3.0.1.3
#tool nuget:?package=Jarvis.WebApi&version=3.0.1.3
Jarvis.WebApi
Biblioteca de componentes para APIs Web em ASP.NET Core: respostas padronizadas, autenticação JWT, documentação OpenAPI, tratamento de erros e proteção por API key.
Instalação
Requer .NET 10.
dotnet add package Jarvis.WebApi
Registre os serviços no Program.cs:
builder.Services.AddControllers().ConfigureJarvisWebApi();
builder.Services.AddJarvisWebApi("sua-chave-secreta");
Respostas
ActionResultResponse
Resultado de action que serializa um JsonResponse no corpo e define o status code correspondente. Todos os métodos são estáticos.
[HttpGet("{id}")]
public IActionResult Obter(Guid id)
{
var cliente = _service.Obter(id);
if (cliente.IsNull())
{
return ActionResultResponse.Error("Cliente não encontrado.");
}
return ActionResultResponse.Success(cliente);
}
| Método | Status | Descrição |
|---|---|---|
Success |
200 | Sucesso, com item e/ou mensagem |
OK |
200 | Alias de Success(object, string) |
Created |
201 | Recurso criado |
Error |
400 | Erro, com mensagem e lista de JsonError |
BadRequest |
400 | Alias de Error |
NotAuthenticated |
401 | Usuário não autenticado |
Blocked |
403 | Acesso bloqueado |
NotAuthorized |
403 | Usuário sem permissão |
Download de Arquivos
Sobrecargas para Stream e byte[]. A extensão é acrescentada ao nome quando ausente.
return ActionResultResponse.Excel(planilha, "clientes"); // vira clientes.xlsx
return ActionResultResponse.Pdf(bytes, "relatorio.pdf");
return ActionResultResponse.Zip(stream, "backup");
| Método | Content Type | Extensão |
|---|---|---|
Excel |
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
.xlsx |
Pdf |
application/pdf |
.pdf |
Zip |
application/zip |
.zip |
Configuração
ConfigureJarvisWebApi
Padroniza o comportamento da API. Disponível para IServiceCollection e IMvcBuilder.
builder.Services.AddControllers().ConfigureJarvisWebApi();
Aplica:
- Erros de validação de modelo retornam
JsonResponseem vez doProblemDetailspadrão - JSON serializado em camelCase, indentado, omitindo propriedades nulas
AddJarvisWebApi
Registra a autenticação JWT Bearer e o JarvisITokenService como Scoped. Disponível para IServiceCollection, IMvcBuilder e AuthenticationBuilder.
Forma curta — apenas a chave, expiração de 30 dias:
builder.Services.AddJarvisWebApi("sua-chave-secreta");
Forma completa:
builder.Services.AddJarvisWebApi(options =>
{
options.SigningKey = "sua-chave-secreta";
options.Issuer = "https://api.exemplo.com";
options.Audience = "https://app.exemplo.com";
options.Expires = TimeSpan.FromHours(8);
options.ExpiresRefresh = TimeSpan.FromDays(7);
options.ValidateIssuer = true;
options.ValidateAudience = true;
options.ValidateLifetime = true;
});
As opções vêm de JarvisJwtOptions (Jarvis.Toolkit). RequireHttpsMetadata e SaveToken já são habilitados.
Para customizar a extração do token ou o tratamento de falha, passe JwtBearerEvents:
builder.Services.AddJarvisWebApi("sua-chave-secreta", new JwtBearerEvents()
{
OnAuthenticationFailed = context =>
{
JarvisLog.Error(context.Exception.Message);
return Task.CompletedTask;
}
});
Token
JarvisITokenService
Serviço de emissão e validação de tokens JWT, resolvido por injeção de dependência.
public class AuthController(JarvisITokenService tokenService) : ControllerBase
{
[HttpPost("login")]
public IActionResult Login(LoginRequest request)
{
var user = _service.Autenticar(request.Login.Trim().ToLower(), request.Senha.Trim());
if (user.IsNull())
{
return ActionResultResponse.NotAuthenticated("Credenciais inválidas.");
}
return ActionResultResponse.Success(tokenService.TokenResponse(user));
}
}
| Método | Retorno | Descrição |
|---|---|---|
TokenResponse |
TokenResponse |
Token, refresh token e datas de expiração |
Token |
string |
Apenas o token de acesso |
JarvisAuthenticationUser |
JarvisAuthenticationUser |
Valida o token e reconstrói o usuário |
ClaimsPrincipal |
ClaimsPrincipal |
Valida o token e devolve o principal |
IsValid |
Task<bool> |
Verifica validade sem lançar exceção |
JarvisAuthenticationUser, ClaimsPrincipal e IsValid têm sobrecargas para string e TokenResponse.
Sem refreshToken informado, ele é derivado do hash SHA1 do token de acesso.
ClaimsPrincipal(string)lançaArgumentExceptionquando o token não é um JWT ou não foi assinado com HMAC-SHA256, eSecurityTokenExceptionquando a validação falha. UseIsValidquando não quiser tratar exceções — mas note que ele não confere o algoritmo de assinatura.
Claims do Usuário
Propriedades de extensão sobre ClaimsPrincipal que devolvem as claims do Jarvis já convertidas para Guid ou bool.
var idUsuario = User.IdUsuario;
var idEmpresa = User.IdEmpresa;
if (User.IsMaster)
{
// ...
}
| Propriedade | Tipo | Claim de origem |
|---|---|---|
IdUsuario |
Guid |
Id |
IdCliente |
Guid |
ClientId |
IdAdmin |
Guid |
AdminId |
IdMaster |
Guid |
MasterId |
IdEmpresa |
Guid |
EnterpriseId |
IdOrganizacao |
Guid |
OrganizationId |
IdReferencia |
Guid |
ReferenceId |
IsMaster |
bool |
Master |
Claim ausente ou com valor inválido resulta em Guid.Empty (ou false no IsMaster), não em exceção.
OpenAPI
AddJarvisOpenApi
Gera o documento OpenAPI com metadados e esquemas de segurança. Disponível para IServiceCollection, IMvcBuilder e AuthenticationBuilder.
builder.Services.AddJarvisOpenApi(options =>
{
options.Info = new OpenApiInfo()
{
Title = "API Clientes | v1",
Version = "1.0.0"
};
options.UseJwt = true;
options.UseApiKey = true;
options.ApiKeyName = "X-Auth-Token";
});
| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
Info |
OpenApiInfo |
API \| v1, 1.0.0 |
Título, versão e contato do documento |
Servers |
IList<OpenApiServer> |
null |
Servidores listados; nulo mantém os autodetectados |
UseJwt |
bool |
false |
Adiciona o esquema JWT Bearer |
UseApiKey |
bool |
false |
Adiciona o esquema de API key |
ApiKeyName |
string |
X-Auth-Token |
Nome do cabeçalho exibido na documentação |
ApiKeyValue |
string |
null |
Não usado na geração do documento |
Os esquemas habilitados são referenciados em todas as operações do documento — não há como marcar um endpoint como público na documentação por essas opções.
Tratamento de Erros
Duas abordagens, escolha uma.
UseJarvisGlobalException
Baseado em IExceptionHandler. Requer registro no container.
builder.Services.AddJarvisGlobalException();
var app = builder.Build();
app.UseJarvisGlobalException();
Devolve status 500 com a mensagem da exceção no corpo.
UseJarvisErrorMiddleware
Middleware direto, sem registro prévio, com mensagem fixa e callback de log.
app.UseJarvisErrorMiddleware("Erro interno. Tente novamente.", exception => JarvisLog.Error(exception.Message));
| Parâmetro | Tipo | Descrição |
|---|---|---|
message |
string |
Mensagem devolvida ao cliente; omitida, expõe a da exceção |
onError |
Action<Exception> |
Callback executado a cada exceção capturada |
Prefira esta opção em produção:
UseJarvisGlobalExceptionsempre expõe a mensagem original da exceção ao cliente, o que pode vazar detalhes internos.
API Key
Formas de exigir uma chave em um cabeçalho. Ausência ou divergência retorna 401 com JsonResponse de erro.
ApiAuthorizeAttribute
Para controllers MVC. Aplicável a classe ou método.
[ApiAuthorize("minha-chave")]
public class WebhookController : ControllerBase { }
[ApiAuthorize("minha-chave", "X-Custom-Header")]
public IActionResult Receber() { }
AddApiKeyFilter
Para Minimal APIs. Aplicável a endpoint ou grupo.
app.MapGet("/clientes", Listar).AddApiKeyFilter("minha-chave");
app.MapGroup("/webhook").AddApiKeyFilter("minha-chave", "X-Custom-Header");
O cabeçalho padrão nos dois casos é X-Auth-Token.
ApiAuthorizeAttribute<T>
Para chave validada por regra própria (ex.: consulta no banco). Ausência do cabeçalho ou regra com erro retorna 401.
public class MinhaChaveRule(IMeuServico servico) : JarvisIApiKeyAuthorization
{
public async Task<ModelResponse> AuthorizeAsync(string key, AuthorizationFilterContext filterContext)
{
var chave = await servico.BuscarChaveAsync(key);
if (chave.IsNull())
{
return ModelResponse.Error("Invalid token");
}
return ModelResponse.Success();
}
}
[ApiAuthorize<MinhaChaveRule>]
public class IntegracaoController : ControllerBase { }
[ApiAuthorize<MinhaChaveRule>("ApiKey")]
public IActionResult Receber() { }
A regra é criada a cada requisição, com as dependências do DI. Se ela definir filterContext.Result (ex.: resposta própria), ele é mantido.
Usuário Autenticado e Permissão
Para controllers MVC. Aplicável a classe ou método.
// Só exige usuário autenticado (401 se não estiver)
[UserAuthorize]
public class PerfilController : ControllerBase { }
// Autenticado + regra de permissão (403 com a mensagem da regra se falhar)
[UserAuthorize<MinhaRegra>]
public class EmpresaController : ControllerBase { }
A regra implementa JarvisIUserAuthorization e recebe dependências pelo construtor. É criada a cada requisição; não precisa registrar no DI.
public class MinhaRegra(IMeuServico servico) : JarvisIUserAuthorization
{
public async Task<ModelResponse> AuthorizeAsync(ClaimsPrincipal user, AuthorizationFilterContext filterContext)
{
var permitido = await servico.PodeAcessarAsync(user.IdUsuario);
if (!permitido)
{
return ModelResponse.Error("Acesso negado.");
}
return ModelResponse.Success();
}
}
Regra com argumentos
Argumentos do atributo são repassados ao construtor da regra, junto com as dependências do DI.
public class PermissaoRule(IMeuServico servico, MinhaPermissao permissao) : JarvisIUserAuthorization
{
public async Task<ModelResponse> AuthorizeAsync(ClaimsPrincipal user, AuthorizationFilterContext filterContext)
{
if (user.IsMaster)
{
return ModelResponse.Success();
}
return await servico.VerificarPermissaoAsync(user.IdUsuario, permissao);
}
}
[UserAuthorize<PermissaoRule>(MinhaPermissao.Editar)]
public IActionResult Editar() { }
Lista de permissões
Vários valores do mesmo tipo são agrupados em array quando o construtor da regra recebe E[] (ou params E[]).
public class PermissoesRule(IMeuServico servico, MinhaPermissao[] permissoes) : JarvisIUserAuthorization
{
public async Task<ModelResponse> AuthorizeAsync(ClaimsPrincipal user, AuthorizationFilterContext filterContext)
{
return await servico.VerificarAlgumaPermissaoAsync(user.IdUsuario, permissoes);
}
}
[UserAuthorize<PermissoesRule>(MinhaPermissao.Ver, MinhaPermissao.Editar, MinhaPermissao.Excluir)]
public IActionResult Gerenciar() { }
Os argumentos não são checados na compilação. Tipo incompatível com o construtor da regra gera exceção na requisição.
Se a regra definir filterContext.Result (ex.: resposta própria), ele é mantido. Exceção lançada pela regra segue para o Tratamento de Erros.
Migrando do filtro próprio
Antes, cada projeto tinha um UserAuthorizeAttribute com TypeFilterAttribute e um UserAuthorizeFilter:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class UserAuthorizeAttribute : TypeFilterAttribute
{
public UserAuthorizeAttribute(MinhaPermissao permissao) : base(typeof(UserAuthorizeFilter))
{
Arguments = [permissao];
}
}
public class UserAuthorizeFilter(IMeuServico servico, MinhaPermissao permissao) : IAsyncAuthorizationFilter
{
public async Task OnAuthorizationAsync(AuthorizationFilterContext filterContext)
{
try
{
if (!filterContext.HttpContext.User.IsAuthenticated())
{
filterContext.Result = ActionResultResponse.NotAuthenticated("Usuário não autenticado.");
}
else if (!filterContext.HttpContext.User.IsMaster)
{
var verificarPermissao = await servico.VerificarPermissaoAsync(filterContext.HttpContext.User.IdUsuario, permissao);
if (verificarPermissao.IsError)
{
filterContext.Result = ActionResultResponse.Error(verificarPermissao.Message);
}
}
}
catch (Exception e)
{
filterContext.Result = ActionResultResponse.Error(e.Message);
}
}
}
Depois, só a regra fica no projeto:
public class PermissaoRule(IMeuServico servico, MinhaPermissao permissao) : JarvisIUserAuthorization
{
public async Task<ModelResponse> AuthorizeAsync(ClaimsPrincipal user, AuthorizationFilterContext filterContext)
{
if (user.IsMaster)
{
return ModelResponse.Success();
}
return await servico.VerificarPermissaoAsync(user.IdUsuario, permissao);
}
}
Passos:
- Mova o trecho que valida a permissão para uma classe que implementa
JarvisIUserAuthorization. Os parâmetros do construtor do filtro (serviços do DI e argumentos do atributo) vão para o construtor da regra. - Retorne o
ModelResponseda validação em vez de definirfilterContext.Result. - Remova a checagem de autenticação, o
try/catche o.Result(useawait). O atributo já faz isso. - Apague
UserAuthorizeAttributeeUserAuthorizeFilterdo projeto. - Troque o uso nos controllers:
| Antes | Depois |
|---|---|
[UserAuthorize] (só autenticação) |
[UserAuthorize] |
[UserAuthorize(MinhaPermissao.Editar)] |
[UserAuthorize<PermissaoRule>(MinhaPermissao.Editar)] |
[UserAuthorize(MinhaPermissao.Ver, MinhaPermissao.Editar)] |
[UserAuthorize<PermissoesRule>(MinhaPermissao.Ver, MinhaPermissao.Editar)] |
[MasterAuthorize], [EmpresaAuthorize] etc. |
[UserAuthorize<MasterRule>], [UserAuthorize<EmpresaRule>] |
[ApiKeyAuthorize] com chave validada no banco |
[ApiAuthorize<MinhaChaveRule>] ou [ApiAuthorize<MinhaChaveRule>("ApiKey")] |
Comportamentos que mudam:
| Situação | Antes | Depois |
|---|---|---|
| Sem permissão | 400 (Error) |
403 (NotAuthorized) |
| Exceção na validação | 400 com e.Message |
Segue para o Tratamento de Erros |
| Usuário não autenticado | 401, mas sem return a BLL ainda rodava |
401 e a regra não roda |
Validação síncrona (.Result) |
Bloqueava a thread | async |
O corpo continua sendo
JsonResponsecomisSuccess: falseemessage. Front que lê o corpo (comoServiceGetAsyncdo Jarvis.Toolkit) não muda. Front que testastatus === 400para erro de permissão precisa aceitar403.
HTTPS Obrigatório
Exige que a requisição chegue por HTTPS. Aplicável a classe ou método.
[RequireHttpsScheme]
public class PagamentoController : ControllerBase { }
Requisição em HTTP retorna 400 com a mensagem HTTPS is required.
Atrás de proxy reverso,
Request.IsHttpsreflete a conexão até o proxy, não a do cliente. ConfigureAddJarvisIpClienteeUseJarvisIpClientepara que oX-Forwarded-Protoseja considerado.
Log de Performance
Mede o tempo de execução de cada action e grava via JarvisLog.Debug.
builder.Services.AddControllers().AddJarvisActionFilters();
Saída:
Action ClientesController.Listar (Api) executed in 42 ms
Extensions
ModelState
// Resposta de erro completa
return ActionResultResponse.Error("Modelo inválido.", ModelState.Errors());
// Ou o JsonResponse direto
var response = ModelState.Errors("Verifique os campos.");
Errors() achata as mensagens de validação em List<JsonError>. O Title de cada erro recebe o nome da propriedade sem o prefixo do objeto — a chave cliente.Nome vira Nome.
Com
ConfigureJarvisWebApiregistrado, essa conversão já acontece automaticamente nas respostas de validação.
Respostas do Toolkit
return _service.Listar(filtro).ToOkResponse(); // PaginationResponse<T> ou GenericList<T>
return _service.Salvar(model).ToOkResponse(); // ModelResponse → 200 ou 400
return _service.Criar(model).ToCreatedResponse(); // ModelResponse → 201 ou 400
Nas sobrecargas de ModelResponse, IsSuccess define o status: sucesso vira 200 ou 201, falha vira 400 com a mensagem da resposta.
HttpContext
var ip = HttpContext.GetIpAddress();
var device = HttpContext.GetDevice();
var token = HttpContext.GetHeader("X-Auth-Token");
var pagina = HttpContext.GetQueryParameter("pagina");
var query = HttpContext.GetQueryString();
| Método | Retorno | Descrição |
|---|---|---|
GetIpAddress |
string |
IP do cliente, com IPv4 mapeado normalizado |
GetDevice |
string |
Cabeçalho User-Agent, já com Trim() |
GetHeader |
string |
Valor de um cabeçalho |
GetQueryParameter |
string |
Valor de um parâmetro da query string |
GetQueryString |
string |
Query string completa, incluindo o ? |
GetIpAddress normaliza endereços IPv4 recebidos em formato mapeado (::ffff:189.10.20.30) para IPv4 puro. IPv6 real é mantido intacto, então a coluna de IP no banco precisa comportar 45 caracteres.
GetDevice, GetHeader, GetQueryParameter e GetQueryString devolvem string vazia quando o dado não existe. GetIpAddress devolve null quando não há endereço remoto na conexão.
IP Real Atrás de Proxy Reverso
Com IIS/ARR, Docker Swarm ou nginx na frente, GetIpAddress devolve o IP do proxy, não o do cliente. Para obter o IP real, registre o processamento dos cabeçalhos encaminhados:
builder.Services.AddJarvisIpCliente();
var app = builder.Build();
app.UseJarvisIpCliente(); // primeira linha do pipeline, antes de auth e HTTPS redirect
Isso configura X-Forwarded-For e X-Forwarded-Proto com ForwardLimit = 1 (um único proxy na frente). Sem parâmetro, aceita cabeçalhos vindos das faixas privadas 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 e loopback.
Informando os proxies explicitamente, somente esses endereços são aceitos:
builder.Services.AddJarvisIpCliente("192.168.1.50");
Segurança: confiar em faixas inteiras permite que qualquer host daquela rede forje o cabeçalho
X-Forwarded-Fore se passe por outro IP — num cluster Swarm, isso inclui qualquer container. Se o IP for usado para bloqueio, rate limit ou auditoria, passe o endereço do proxy explicitamente.
Notas de infraestrutura:
- O IIS/ARR envia
X-Forwarded-Forpor padrão, mas não oX-Forwarded-Proto— este exige uma regra de rewrite definindo a server variableHTTP_X_FORWARDED_PROTO. Sem ela,UseHttpsRedirectionpode entrar em loop. - No Docker Swarm, o ingress faz SNAT e altera apenas o IP de origem (L3); o cabeçalho
X-Forwarded-Forpassa intacto. Como o gateway do ingress fica em10.0.0.0/8, o modo padrão de publicação funciona. Publicar commode: hostsó é necessário para obter o IP real sem depender de cabeçalho. - Se um dia entrar outro proxy na frente (Cloudflare, nginx), o
ForwardLimitprecisa subir para 2.
Rate Limit
Controle de requisições por política nomeada, particionado por IP do cliente e caminho da requisição.
builder.Services.AddJarvisRateLimit(options =>
{
options.Message = "Muitas tentativas em pouco tempo. Aguarde alguns minutos e tente de novo.";
options.AddPolicy("auth", 5, TimeSpan.FromMinutes(1), HttpMethods.Post);
options.AddPolicy("cupom", 10, TimeSpan.FromMinutes(1));
});
var app = builder.Build();
app.UseJarvisRateLimit(); // depois de UseRouting, antes de MapControllers
Aplicando a política no controller ou na action:
[ApiController]
[Route("[controller]")]
public class AuthController : ControllerBase
{
[HttpPost("login")]
[EnableRateLimiting("auth")]
public async Task<IActionResult> Login(LoginRequest request) { }
[HttpGet("status")]
[DisableRateLimiting]
public IActionResult Status() { }
}
Com uma política só, dá para registrar direto:
builder.Services.AddJarvisRateLimit("auth", 5, TimeSpan.FromMinutes(1), HttpMethods.Post);
Opções
| Propriedade | Padrão | Descrição |
|---|---|---|
Message |
"Muitas tentativas…" | Mensagem devolvida no corpo da resposta bloqueada |
StatusCode |
429 |
Status code da resposta bloqueada |
OnRejected |
null |
Substitui a resposta padrão; quando definido, Message e StatusCode deixam de ser aplicados |
Policies |
vazio | Políticas registradas |
Política
| Propriedade | Padrão | Descrição |
|---|---|---|
Name |
— | Nome usado em [EnableRateLimiting] |
PermitLimit |
5 |
Requisições permitidas por janela |
Window |
1 min |
Duração da janela |
QueueLimit |
0 |
Requisições que aguardam na fila em vez de serem rejeitadas |
SegmentsPerWindow |
0 |
Acima de 1, troca janela fixa por janela deslizante |
Methods |
null |
Métodos HTTP limitados. Nulo ou vazio limita todos |
IncludePath |
true |
Inclui o caminho na chave — cada rota tem sua própria contagem |
IncludeUser |
false |
Inclui o usuário autenticado na chave; anônimos continuam contados por IP |
Configuração detalhada:
builder.Services.AddJarvisRateLimit(options =>
{
options.AddPolicy("api", policy =>
{
policy.PermitLimit = 100;
policy.Window = TimeSpan.FromMinutes(1);
policy.SegmentsPerWindow = 6; // janela deslizante de 10 em 10 segundos
policy.IncludePath = false; // uma contagem por IP, valendo para toda a API
policy.IncludeUser = true;
});
});
Resposta bloqueada
Status 429, cabeçalho Retry-After em segundos e corpo no formato JsonResponse:
{
"isSuccess": false,
"message": "Muitas tentativas em pouco tempo. Aguarde alguns minutos e tente de novo."
}
Para outro formato, defina OnRejected:
options.OnRejected = async (context, token) =>
{
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
await context.HttpContext.Response.WriteAsync("Calma aí.", token);
};
Contagem em memória: o limite vale por instância da aplicação. Com várias réplicas (Docker Swarm, web farm), o limite efetivo é multiplicado pelo número de réplicas. Para limite compartilhado, use um limitador distribuído (Redis).
A chave de partição usa
GetIpAddress(). Atrás de proxy reverso,UseJarvisIpCliente()precisa vir antes no pipeline — sem isso todas as requisições caem na mesma partição, a do IP do proxy.
Exemplo Completo
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddJarvisIpCliente();
builder.Services.AddJarvisGlobalException();
builder.Services.AddJarvisRateLimit(options =>
{
options.AddPolicy("auth", 5, TimeSpan.FromMinutes(1), HttpMethods.Post);
});
builder.Services.AddControllers()
.ConfigureJarvisWebApi()
.AddJarvisActionFilters()
.AddJarvisWebApi(options =>
{
options.SigningKey = builder.Configuration["Jwt:Key"];
options.Expires = TimeSpan.FromHours(8);
options.ValidateLifetime = true;
})
.AddJarvisOpenApi(options =>
{
options.Info = new OpenApiInfo() { Title = "API Clientes | v1", Version = "1.0.0" };
options.UseJwt = true;
});
var app = builder.Build();
app.UseJarvisIpCliente();
app.UseJarvisErrorMiddleware("Erro interno.", exception => JarvisLog.Error(exception.Message));
app.UseJarvisRateLimit();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Dependências
- Jarvis.Toolkit —
JsonResponse,JsonError,TokenResponse,JarvisJwtOptions,JarvisAuthenticationUser,ModelResponse,PaginationResponse<T>,GenericList<T>,JarvisLog Microsoft.AspNetCore.Authentication.JwtBearerMicrosoft.AspNetCore.OpenApi
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Jarvis.Toolkit (>= 1.2.2.6)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.13)
- Microsoft.AspNetCore.OpenApi (>= 10.0.13)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.1.3 | 50 | 10/18/2026 |
| 3.0.1.2 | 54 | 10/17/2026 |
| 3.0.1.1 | 54 | 10/17/2026 |
| 3.0.1 | 155 | 8/2/2026 |
| 3.0.0.9 | 141 | 8/1/2026 |
| 3.0.0.8 | 173 | 5/19/2026 |
| 3.0.0.7 | 301 | 3/18/2026 |
| 3.0.0.6 | 310 | 3/17/2026 |
| 3.0.0.5 | 291 | 3/13/2026 |
| 3.0.0.4 | 329 | 2/3/2026 |
| 3.0.0.3 | 336 | 1/28/2026 |
| 3.0.0.2 | 466 | 11/28/2025 |
| 3.0.0.1 | 478 | 11/25/2025 |
| 3.0.0 | 570 | 11/13/2025 |
| 2.0.2.9 | 559 | 8/27/2025 |
| 2.0.2.8 | 541 | 8/27/2025 |
| 2.0.2.7 | 605 | 4/18/2025 |
| 2.0.2.6 | 463 | 3/21/2025 |
| 2.0.2.5 | 490 | 3/21/2025 |
| 2.0.2.4 | 484 | 2/13/2025 |