Jarvis.WebApi
3.0.0.9
See the version list below for details.
dotnet add package Jarvis.WebApi --version 3.0.0.9
NuGet\Install-Package Jarvis.WebApi -Version 3.0.0.9
<PackageReference Include="Jarvis.WebApi" Version="3.0.0.9" />
<PackageVersion Include="Jarvis.WebApi" Version="3.0.0.9" />
<PackageReference Include="Jarvis.WebApi" />
paket add Jarvis.WebApi --version 3.0.0.9
#r "nuget: Jarvis.WebApi, 3.0.0.9"
#:package Jarvis.WebApi@3.0.0.9
#addin nuget:?package=Jarvis.WebApi&version=3.0.0.9
#tool nuget:?package=Jarvis.WebApi&version=3.0.0.9
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.
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 |
IdReferencia |
Guid |
ReferenceId |
IsMaster |
bool |
Master |
Claim ausente ou com valor inválido resulta em Guid.Empty, 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
Duas 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.
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.
Exemplo Completo
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddJarvisIpCliente();
builder.Services.AddJarvisGlobalException();
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.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.2)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.10)
- Microsoft.AspNetCore.OpenApi (>= 10.0.10)
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 | 40 | 8/2/2026 |
| 3.0.0.9 | 46 | 8/1/2026 |
| 3.0.0.8 | 149 | 5/19/2026 |
| 3.0.0.7 | 280 | 3/18/2026 |
| 3.0.0.6 | 289 | 3/17/2026 |
| 3.0.0.5 | 270 | 3/13/2026 |
| 3.0.0.4 | 308 | 2/3/2026 |
| 3.0.0.3 | 316 | 1/28/2026 |
| 3.0.0.2 | 446 | 11/28/2025 |
| 3.0.0.1 | 457 | 11/25/2025 |
| 3.0.0 | 553 | 11/13/2025 |
| 2.0.2.9 | 542 | 8/27/2025 |
| 2.0.2.8 | 524 | 8/27/2025 |
| 2.0.2.7 | 584 | 4/18/2025 |
| 2.0.2.6 | 441 | 3/21/2025 |
| 2.0.2.5 | 472 | 3/21/2025 |
| 2.0.2.4 | 466 | 2/13/2025 |
| 2.0.2.3 | 467 | 11/15/2024 |
| 2.0.2.2 | 463 | 11/12/2024 |
| 2.0.2.1 | 459 | 10/30/2024 |