Jarvis.WebApi 3.0.0.9

There is a newer version of this package available.
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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Jarvis.WebApi" Version="3.0.0.9" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Jarvis.WebApi" Version="3.0.0.9" />
                    
Directory.Packages.props
<PackageReference Include="Jarvis.WebApi" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Jarvis.WebApi --version 3.0.0.9
                    
#r "nuget: Jarvis.WebApi, 3.0.0.9"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Jarvis.WebApi@3.0.0.9
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Jarvis.WebApi&version=3.0.0.9
                    
Install as a Cake Addin
#tool nuget:?package=Jarvis.WebApi&version=3.0.0.9
                    
Install as a Cake Tool

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 JsonResponse em vez do ProblemDetails padrã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ça ArgumentException quando o token não é um JWT ou não foi assinado com HMAC-SHA256, e SecurityTokenException quando a validação falha. Use IsValid quando 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: UseJarvisGlobalException sempre 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.IsHttps reflete a conexão até o proxy, não a do cliente. Configure AddJarvisIpCliente e UseJarvisIpCliente para que o X-Forwarded-Proto seja 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 ConfigureJarvisWebApi registrado, 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-For e 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-For por padrão, mas não o X-Forwarded-Proto — este exige uma regra de rewrite definindo a server variable HTTP_X_FORWARDED_PROTO. Sem ela, UseHttpsRedirection pode entrar em loop.
  • No Docker Swarm, o ingress faz SNAT e altera apenas o IP de origem (L3); o cabeçalho X-Forwarded-For passa intacto. Como o gateway do ingress fica em 10.0.0.0/8, o modo padrão de publicação funciona. Publicar com mode: host só é necessário para obter o IP real sem depender de cabeçalho.
  • Se um dia entrar outro proxy na frente (Cloudflare, nginx), o ForwardLimit precisa 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.ToolkitJsonResponse, JsonError, TokenResponse, JarvisJwtOptions, JarvisAuthenticationUser, ModelResponse, PaginationResponse<T>, GenericList<T>, JarvisLog
  • Microsoft.AspNetCore.Authentication.JwtBearer
  • Microsoft.AspNetCore.OpenApi
Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
Loading failed