Nera.Client 1.0.0

dotnet add package Nera.Client --version 1.0.0
                    
NuGet\Install-Package Nera.Client -Version 1.0.0
                    
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="Nera.Client" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nera.Client" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Nera.Client" />
                    
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 Nera.Client --version 1.0.0
                    
#r "nuget: Nera.Client, 1.0.0"
                    
#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 Nera.Client@1.0.0
                    
#: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=Nera.Client&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Nera.Client&version=1.0.0
                    
Install as a Cake Tool

Nera.Client

Unified Client SDK for the entire Nera platform services.
Provides typed HTTP clients, gRPC clients for IAM and Quota services, Options-based configuration, and resilient communication.


Table of Contents


Overview

Nera.Client is the common client library that acts as a bridge between services in the Nera platform. Instead of each project writing its own HTTP/gRPC client to call other services, everyone uses Nera.Client to get:

  • Typed HTTP clients for REST services with full request/response models
  • gRPC IAM clients for User, Token, Session, Organization, and AuditLog services
  • Quota Service clients (HTTP + gRPC) with fail-open, caching decorator, and well-known resource constants
  • ✅ Endpoint, API version, and timeout configuration via the Options Pattern
  • ✅ Automatic resilience (retry, circuit breaker, timeout) via Microsoft.Extensions.Http.Resilience
  • IHttpClientFactory — managed connection pool, no socket exhaustion
  • ✅ Structured logging for every request
  • ✅ Consistent error handling with NeraResult<T> wrapper
  • ✅ IAM enums, constants, DTOs, and entity models ready to use

Project Structure

Nera.Client/
├── Abstractions/
│   └── BaseNeraClient.cs              # Base HTTP client with GET/POST/PUT/DELETE
├── Common/
│   ├── ApiResponse.cs                 # NeraResult<T> response envelope
│   ├── NeraClientException.cs         # Custom exception for client errors
│   └── NeraJsonDefaults.cs            # Shared JSON serializer options
├── Configuration/
│   ├── NeraClientOptions.cs           # Root options (timeout, API version, services)
│   ├── ServiceEndpointOptions.cs      # Per-service HTTP endpoint config
│   └── MenuServiceOptions.cs          # Menu-specific options
├── DependencyInjection/
│   ├── NeraClientBuilder.cs           # Fluent builder: AddMenuService(), AddAllIamServices()
│   └── ServiceCollectionExtensions.cs # AddNeraClient() extension
├── Services/
│   ├── Menu/                          # HTTP REST client
│   │   ├── IMenuServiceClient.cs
│   │   ├── MenuServiceClient.cs
│   │   └── Models/
│   └── IAM/                           # gRPC clients (merged from nera-iam-common)
│       ├── Protos/                    # 17 proto files (token, user, session, org, audit, etc.)
│       ├── Interfaces/                # ITokenGrpcClient, IUserGrpcClient, etc.
│       ├── Clients/                   # TokenGrpcClient, UserGrpcClient, etc.
│       ├── Configuration/             # IamServiceOptions
│       ├── Models/                    # BaseModels, EntityModels (UserInfo, OrgInfo, etc.)
│       ├── DTOs/                      # Contract DTOs for all IAM domains
│       ├── Enums/                     # UserStatus, RoleType, TokenType, etc.
│       ├── Constants/                 # IamConstants (ServiceNames, CacheKeys, ErrorCodes, etc.)
│       ├── Helpers/                   # GrpcResult / GrpcServiceResponse
│       ├── Caching/                   # IOrganizationCacheService + warmup
│       └── Extensions/                # OrganizationCacheExtensions
│   └── Quota/                         # Quota Service clients (merged from nera-quota-service)
│       ├── Protos/                    # quota_service.proto
│       ├── Clients/                   # QuotaHttpClient, QuotaGrpcClient, CachedQuotaClient
│       ├── Configuration/             # QuotaServiceOptions
│       ├── DTOs/                      # QuotaDtos (check, consume, release, usage, admin DTOs)
│       └── Constants/                 # WellKnownResourceTypes, WellKnownTenants
├── GlobalUsings.cs
├── Nera.Client.csproj
└── README.md

Installation

NuGet Package (once published)

dotnet add package Nera.Client

Project Reference (development)

dotnet add reference ../Nera.Client/Nera.Client.csproj

Quick Start

1. Add configuration to appsettings.json

{
  "NeraClient": {
    "DefaultTimeout": 30,
    "DefaultApiVersion": "v1",
    "Services": {
      "Menu": {
        "BaseUrl": "https://menu-service.nextera.io",
        "ApiVersion": "v1",
        "Timeout": 15
      }
    },
    "IAM": {
      "GrpcGatewayUrl": "http://localhost:8081"
    },
    "Quota": {
      "BaseUrl": "http://quota-service:8080",
      "GrpcUrl": "http://quota-service:5101",
      "TimeoutSeconds": 5,
      "FailOpen": true
    }
  }
}

2. Register in Program.cs

using Nera.Client.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

// Register Nera Client with Menu, IAM, and Quota services
builder.Services.AddNeraClient(builder.Configuration, client =>
{
    client.AddMenuService();
    client.AddAllIamServices();
    
    // Quota via HTTP (REST)
    client.AddQuotaService();
    
    // Or Quota via gRPC (high-performance)
    // client.AddQuotaGrpcService();
});

3. Inject and use (HTTP — Menu)

using Nera.Client.Services.Menu;

public class MyController : ControllerBase
{
    private readonly IMenuServiceClient _menuClient;

    public MyController(IMenuServiceClient menuClient)
    {
        _menuClient = menuClient;
    }

    [HttpGet("navigation")]
    public async Task<IActionResult> GetNavigation()
    {
        var result = await _menuClient.GetPublicMenuTreeAsync(
            project: "nera-admin",
            platform: "web");

        if (!result.Success)
            return StatusCode(result.StatusCode, result.Error);

        return Ok(result.Data);
    }
}

4. Inject and use (gRPC — IAM)

using Nera.Client.Services.IAM.Interfaces;

public class AuthService
{
    private readonly ITokenGrpcClient _tokenClient;
    private readonly IUserGrpcClient _userClient;

    public AuthService(ITokenGrpcClient tokenClient, IUserGrpcClient userClient)
    {
        _tokenClient = tokenClient;
        _userClient = userClient;
    }

    public async Task<TokenResponse> ValidateTokenAsync(string token)
    {
        return await _tokenClient.ValidateTokenAsync(token);
    }

    public async Task<UserResponse> GetUserAsync(string userId)
    {
        return await _userClient.GetUserAsync(userId);
    }
}

Configuration

Options Pattern

Nera.Client uses the .NET Options Pattern for all configuration. All options can be bound from IConfiguration or overridden in code.

Options Structure
Class Section Description
NeraClientOptions NeraClient Root config — default timeout, default API version
ServiceEndpointOptions NeraClient:Services:{Name} Per-service — BaseUrl, ApiVersion, Timeout, ApiKey, Headers
MenuServiceOptions NeraClient:Services:Menu Menu-specific — extends ServiceEndpointOptions with DefaultProject, DefaultPlatform
IamServiceOptions NeraClient:IAM IAM gRPC — GrpcGatewayUrl (or ENV_GRPC_GATEWAY_URL env var)
QuotaServiceOptions NeraClient:Quota Quota — BaseUrl, GrpcUrl, TimeoutSeconds, FailOpen, EnableCaching, CacheDurationSeconds
Overriding Options in Code
// Option 1: Inline at registration
builder.Services.AddNeraClient(builder.Configuration, client =>
{
    client.AddMenuService(options =>
    {
        options.BaseUrl = "https://menu.internal.nextera.io";
        options.DefaultProject = "nera-admin";
        options.DefaultPlatform = "web";
        options.Timeout = 10;
    });
});

// Option 2: PostConfigure
builder.Services.PostConfigure<MenuServiceOptions>(options =>
{
    options.DefaultProject = "my-project";
});

appsettings.json

{
  "NeraClient": {
    "DefaultTimeout": 30,
    "DefaultApiVersion": "v1",
    "Services": {
      "Menu": {
        "BaseUrl": "https://menu-service.nextera.io",
        "ApiVersion": "v1",
        "Timeout": 15,
        "DefaultProject": "nera-admin",
        "DefaultPlatform": "web",
        "ApiKeyHeader": "X-Api-Key",
        "ApiKey": "your-api-key-here",
        "Headers": {
          "X-Custom-Header": "value"
        }
      }
    },
    "IAM": {
      "GrpcGatewayUrl": "http://localhost:8081"
    },
    "Quota": {
      "BaseUrl": "http://quota-service:8080",
      "GrpcUrl": "http://quota-service:5101",
      "TimeoutSeconds": 5,
      "FailOpen": true,
      "EnableCaching": false,
      "CacheDurationSeconds": 30
    }
  }
}

Environment Variables

Configuration can be overridden via environment variables (standard .NET convention):

# HTTP service overrides
export NeraClient__DefaultTimeout=60
export NeraClient__Services__Menu__BaseUrl=https://menu.staging.nextera.io
export NeraClient__Services__Menu__ApiVersion=v2

# IAM gRPC gateway override
export ENV_GRPC_GATEWAY_URL=http://iam-gateway:8081
# Or via .NET config convention:
export NeraClient__IAM__GrpcGatewayUrl=http://iam-gateway:8081

# Quota service overrides
export ENV_QUOTA_BASE_URL=http://quota-service:8080
export ENV_QUOTA_GRPC_URL=http://quota-service:5101
# Or via .NET config convention:
export NeraClient__Quota__BaseUrl=http://quota-service:8080
export NeraClient__Quota__GrpcUrl=http://quota-service:5101

Per-Environment (appsettings.{Environment}.json)

// appsettings.Development.json
{
  "NeraClient": {
    "Services": {
      "Menu": {
        "BaseUrl": "https://localhost:57472"
      }
    }
  }
}

// appsettings.Production.json
{
  "NeraClient": {
    "Services": {
      "Menu": {
        "BaseUrl": "https://menu-service.nextera.io"
      }
    }
  }
}

Service Clients

IMenuServiceClient provides typed methods for all Menu Service endpoints.

Admin Endpoints (require authorization)
Method Endpoint Description
CreateMenuItemAsync POST /api/v1/menus Create a new menu item
GetMenuItemsAsync GET /api/v1/menus Get paginated, filterable list
GetMenuItemByIdAsync GET /api/v1/menus/{id} Get item detail by ID
GetMenuItemByCodeAsync GET /api/v1/menus/code/{code} Get item by hierarchical code
UpdateMenuItemAsync PUT /api/v1/menus/{id} Update item (optimistic locking)
DeleteMenuItemAsync DELETE /api/v1/menus/{id} Delete item and its descendants
GetMenuTreeAsync GET /api/v1/menus/tree Get full menu tree (admin view)
GetMyMenuTreeAsync GET /api/v1/menus/me Tree filtered by current user's IAM roles
ToggleActiveAsync POST /api/v1/menus/{id}/toggle-active Toggle active/inactive
MoveMenuItemAsync POST /api/v1/menus/{id}/move Move item to new parent/position
BulkReorderAsync PUT /api/v1/menus/reorder Reorder multiple items at once
BulkUpdateAsync PUT /api/v1/menus/bulk-update Bulk activate/deactivate items
Public Endpoints (anonymous, no auth required)
Method Endpoint Description
GetPublicMenuTreeAsync GET /api/v1/public/menus Public menu tree (active items only)
Usage examples
// Inject IMenuServiceClient
private readonly IMenuServiceClient _menuClient;

// 1. Get the public menu tree (localised to Vietnamese)
var publicMenu = await _menuClient.GetPublicMenuTreeAsync(
    project: "nera-admin", 
    platform: "web");

// 2. Get the menu for the current user (filtered by IAM roles)
var myMenu = await _menuClient.GetMyMenuTreeAsync(project: "nera-admin");

// 3. Create a new menu item
var createResult = await _menuClient.CreateMenuItemAsync(new CreateMenuItemRequest
{
    Label = "Dashboard",
    Url = "/dashboard",
    Icon = "dashboard",
    Active = true,
    Project = "nera-admin",
    Platform = "web",
    DisplayOrder = 1
});

if (createResult.IsSuccess)
{
    var newItem = createResult.Data;
    Console.WriteLine($"Created: {newItem!.Id} - {newItem.Code}");
}

// 4. Paginate and filter
var items = await _menuClient.GetMenuItemsAsync(new GetMenuItemsRequest
{
    Page = 1,
    PageSize = 10,
    Active = true,
    SearchTerm = "dashboard"
});

// 5. Update a menu item (optimistic concurrency)
var updateResult = await _menuClient.UpdateMenuItemAsync(itemId, new UpdateMenuItemRequest
{
    Label = "Updated Dashboard",
    Url = "/dashboard/v2",
    Version = currentVersion,  // Must match server version
    Active = true
});

// 6. Bulk operations
var reorderResult = await _menuClient.BulkReorderAsync(new BulkReorderMenuItemsRequest
{
    Items = new List<ReorderItem>
    {
        new() { Id = item1Id, DisplayOrder = 1 },
        new() { Id = item2Id, DisplayOrder = 2 },
        new() { Id = item3Id, DisplayOrder = 3 }
    }
});
Response Handling

All methods return a NeraResult<T> that mirrors the Nera API envelope ({ status, message, data, _metadata, error }):

var result = await _menuClient.GetMenuItemByIdAsync(id);

if (result.IsSuccess)
{
    // result.Data contains the response payload
    var item = result.Data!;
    Console.WriteLine($"Menu: {item.Label}");

    // Pagination info (for list endpoints) is in the metadata
    var pagination = result.Metadata?.Pagination;
}
else
{
    // result.Error.Code  — application error code (e.g. "MENU_NOT_FOUND")
    // result.Error.Message — localised error message (per X-Language header)
    // result.Message — top-level status message
    Console.WriteLine($"[{result.Error?.Code}] {result.Error?.Message}");
}

IAM Services (gRPC)

The IAM gRPC clients (merged from nera-iam-common) provide typed access to all Identity & Access Management services via gRPC.

Available Clients
Interface Description Key Methods
IUserGrpcClient User management GetUser, GetUserByEmail, GetUserByUsername, ValidatePassword, CreateUser, UpdateUser, DeleteUser, GetUserRoles, GetUserPermissions
ITokenGrpcClient Token operations GenerateTokens, ValidateToken, RefreshToken, RevokeToken, GetTokenInfo
ISessionGrpcClient Session management CreateSession, GetSession, ValidateSession, GetUserSessions, UpdateActivity, ExtendSession, TerminateSession
IOrganizationGrpcClient Organization management GetOrganization, GetByDomain, GetBySubdomain, CreateOrganization, UpdateOrganization, DeleteOrganization, IsActive, GetAll, VerifyMembership, SecuritySettings
IAuditLogGrpcClient Audit logging LogAuthActivity, GetAuditLogById, GetAuditLogs
Registration Options
// Register ALL IAM clients at once
builder.Services.AddNeraClient(builder.Configuration, client =>
{
    client.AddAllIamServices();
});

// Or register individual clients
builder.Services.AddNeraClient(builder.Configuration, client =>
{
    client.AddIamUserService();
    client.AddIamTokenService();
    client.AddIamSessionService();
    // AddIamOrganizationService(), AddIamAuditLogService()
});

// Override gRPC gateway URL
builder.Services.AddNeraClient(builder.Configuration, client =>
{
    client.AddAllIamServices(options =>
    {
        options.GrpcGatewayUrl = "http://iam-gateway:8081";
    });
});

// Add Organization cache service (with optional warmup)
builder.Services.AddNeraClient(builder.Configuration, client =>
{
    client.AddAllIamServices();
    client.AddOrganizationCacheService(warmupOnStartup: true);
});
Configuration

The IAM gRPC gateway URL is resolved in this order:

  1. NeraClient:IAM:GrpcGatewayUrl from appsettings.json
  2. ENV_GRPC_GATEWAY_URL environment variable
  3. Default: http://localhost:8081
{
  "NeraClient": {
    "IAM": {
      "GrpcGatewayUrl": "http://localhost:8081"
    }
  }
}

Note: gRPC uses a separate port (8081) from HTTP (8080) to avoid conflicts.

Usage Examples
using Nera.Client.Services.IAM.Interfaces;

// Token validation
public class TokenValidator
{
    private readonly ITokenGrpcClient _tokenClient;

    public TokenValidator(ITokenGrpcClient tokenClient)
        => _tokenClient = tokenClient;

    public async Task<bool> IsValidAsync(string token)
    {
        var result = await _tokenClient.ValidateTokenAsync(token);
        return result.IsValid;
    }
}

// User lookup
public class UserLookup
{
    private readonly IUserGrpcClient _userClient;

    public UserLookup(IUserGrpcClient userClient)
        => _userClient = userClient;

    public async Task<UserResponse?> FindByEmailAsync(string email)
    {
        return await _userClient.GetUserByEmailAsync(email);
    }
}

// Organization domain resolution (with cache)
using Nera.Client.Services.IAM.Caching;

public class TenantResolver
{
    private readonly IOrganizationCacheService _cache;

    public TenantResolver(IOrganizationCacheService cache)
        => _cache = cache;

    public async Task<Guid?> ResolveOrgIdFromDomain(string domain)
    {
        return await _cache.GetOrgIdByDomainAsync(domain);
    }
}
IAM Models, DTOs & Enums

All IAM shared types are available under Nera.Client.Services.IAM.*:

Namespace Contents
Nera.Client.Services.IAM.Models UserInfo, OrganizationInfo, RoleInfo, PermissionInfo, TokenInfo, SessionInfo, MfaChallengeInfo, BaseResponse<T>, PaginatedResponse<T>, entity models
Nera.Client.Services.IAM.DTOs Contract DTOs for all domains: LoginRequestDto, GenerateTokensRequestDto, CreateUserRequestDto, CreateSessionRequestDto, GetAuditLogsRequestDto, etc.
Nera.Client.Services.IAM.Enums UserStatus, RoleType, PermissionLevel, OrganizationStatus, SessionStatus, MfaMethod, TokenType, AuthProviderType, etc.
Nera.Client.Services.IAM.Constants IamConstantsServiceNames, CacheKeys, ExpirationTimes, SystemRoles, SystemPermissions, Headers, ErrorCodes
Nera.Client.Services.IAM.Helpers GrpcResult / GrpcServiceResponse — factory helpers for gRPC responses

Quota Service (HTTP / gRPC)

The Quota Service client (merged from nera-quota-service/Quota.Client + Quota.Contracts) provides typed access to the Nera Quota Service for resource quota management.

Interface: IQuotaServiceClient
Method Description
CheckQuotaAsync Check if a quota allows the requested amount (read-only)
BatchCheckQuotaAsync Check multiple quotas in a single request
ConsumeQuotaAsync Consume quota (atomic check + increment)
ReleaseQuotaAsync Release previously consumed quota
GetUsageSummaryAsync Get usage summary for an organization
Two Transport Options
Client Class Transport Best For
QuotaHttpClient REST/HTTP External consumers, simple integrations
QuotaGrpcClient gRPC (HTTP/2) Internal microservices, high-perf low-latency
CachedQuotaClient Decorator Wraps either client with distributed caching
Registration
builder.Services.AddNeraClient(builder.Configuration, client =>
{
    // Option A: HTTP/REST transport
    client.AddQuotaService();

    // Option B: gRPC transport (high-performance)
    // client.AddQuotaGrpcService();

    // Both support inline options override:
    // client.AddQuotaService(options =>
    // {
    //     options.BaseUrl = "http://quota-service:8080";
    //     options.FailOpen = true;
    //     options.EnableCaching = true;
    //     options.CacheDurationSeconds = 60;
    // });
});

When EnableCaching = true, the client is automatically wrapped with CachedQuotaClient which caches CheckQuota and GetUsageSummary results via IDistributedCache.

Configuration

URL resolution order:

  • HTTP: NeraClient:Quota:BaseUrlENV_QUOTA_BASE_URLhttp://localhost:8080
  • gRPC: NeraClient:Quota:GrpcUrlENV_QUOTA_GRPC_URLhttp://localhost:5101
{
  "NeraClient": {
    "Quota": {
      "BaseUrl": "http://quota-service:8080",
      "GrpcUrl": "http://quota-service:5101",
      "TimeoutSeconds": 5,
      "FailOpen": true,
      "EnableCaching": false,
      "CacheDurationSeconds": 30
    }
  }
}
Usage Examples
using Nera.Client.Services.Quota;
using Nera.Client.Services.Quota.DTOs;
using Nera.Client.Services.Quota.Constants;

public class PhotoUploadService
{
    private readonly IQuotaServiceClient _quotaClient;

    public PhotoUploadService(IQuotaServiceClient quotaClient)
        => _quotaClient = quotaClient;

    public async Task<bool> CanUploadAsync(Guid orgId)
    {
        // Check if the org has quota remaining for monthly photos
        var result = await _quotaClient.CheckQuotaAsync(
            orgId, WellKnownResourceTypes.PhotosMonthly);
        return result.IsAllowed;
    }

    public async Task RecordUploadAsync(Guid orgId, int photoCount)
    {
        // Consume quota atomically
        var result = await _quotaClient.ConsumeQuotaAsync(new ConsumeQuotaRequest
        {
            OrgId = orgId,
            ResourceType = WellKnownResourceTypes.PhotosMonthly,
            Amount = photoCount,
            Source = "photo-upload-service"
        });

        if (!result.Success)
            throw new InvalidOperationException($"Quota exceeded: {result.ErrorMessage}");
    }

    public async Task RollbackUploadAsync(Guid orgId, int photoCount)
    {
        // Release quota on failure
        await _quotaClient.ReleaseQuotaAsync(new ReleaseQuotaRequest
        {
            OrgId = orgId,
            ResourceType = WellKnownResourceTypes.PhotosMonthly,
            Amount = photoCount,
            Source = "photo-upload-service"
        });
    }

    public async Task<UsageSummaryResponse> GetOrgUsageAsync(Guid orgId)
    {
        return await _quotaClient.GetUsageSummaryAsync(orgId);
    }
}
Fail-Open Behavior

When FailOpen = true (default) and the Quota Service is unreachable:

  • CheckQuotaAsync → returns IsAllowed = true (allows the request)
  • ConsumeQuotaAsync → returns Success = true
  • ReleaseQuotaAsync → silently logs the failure
  • GetUsageSummaryAsync → returns empty resources list

When FailOpen = false, all check/consume operations return failure when the service is down.

DTOs & Constants
Namespace Contents
Nera.Client.Services.Quota.DTOs QuotaCheckRequest/Response, BatchQuotaCheckRequest/Response, ConsumeQuotaRequest/Response, ReleaseQuotaRequest/Response, UsageSummaryResponse, ResourceUsageDto, plus admin DTOs (TenantDto, PlanDto, SubscriptionDto, etc.)
Nera.Client.Services.Quota.Constants WellKnownResourceTypes (api_requests_daily, storage_gb, photos_monthly, etc.) and WellKnownTenants (photoflow, photoqa)

Architecture

Resilience

Nera.Client uses Microsoft.Extensions.Http.Resilience (built on Polly) to automatically handle:

  • Retry — automatically retries transient failures (HTTP 408, 429, 5xx)
  • Circuit Breaker — opens the circuit when a service consistently fails
  • Timeout — configurable per-service timeout
  • Rate Limiter — concurrency limiter to avoid overwhelming downstream services

HttpClient Lifecycle

Uses the IHttpClientFactory pattern:

  • Connection pool is managed automatically
  • No socket exhaustion
  • Automatic DNS refresh
  • Each service client receives its own HttpClient instance via the typed client pattern

Error Handling

Request → HttpClient → HTTP Response
                              ├── 2xx → Deserialize NeraResult<T> envelope → IsSuccess = true
                              ├── 4xx/5xx → Deserialize NeraResult<T> (structured error) → IsSuccess = false
                              └── Network/timeout → NeraClientException
  • Any HTTP responseNeraResult<T> with the Nera envelope (status, message, data, _metadata, error)
  • Deserialization failureNeraClientException carrying the raw response body
  • Network / timeoutNeraClientException wrapping the inner exception

Extending (Adding a New Service)

To add a new service client (e.g. User Service), follow this pattern:

1. Options class

// Configuration/UserServiceOptions.cs
public class UserServiceOptions : ServiceEndpointOptions
{
    public const string ServiceName = "User";
    // Service-specific options here
}

2. Models (Request/Response)

// Services/User/Models/UserRequests.cs
// Services/User/Models/UserResponses.cs

3. Interface + Implementation

// Services/User/IUserServiceClient.cs
public interface IUserServiceClient
{
    Task<NeraResult<UserResponse>> GetUserByIdAsync(Guid id, CancellationToken ct = default);
    // ...
}

// Services/User/UserServiceClient.cs
public class UserServiceClient : BaseNeraClient, IUserServiceClient
{
    protected override string ServiceName => "UserService";
    // Implement using GetAsync<T>, PostAsync<TReq, TRes>, etc.
}

4. Register in the Builder

// Add to NeraClientBuilder.cs
public NeraClientBuilder AddUserService(Action<UserServiceOptions>? configure = null)
{
    // Same pattern as AddMenuService()
}

5. Usage

services.AddNeraClient(configuration, builder =>
{
    builder
        .AddMenuService()
        .AddUserService();
});

API Reference

NeraClientOptions

Property Type Default Description
DefaultTimeout int 30 Default request timeout (seconds)
DefaultApiVersion string "v1" Default API version
Services Dictionary<string, ServiceEndpointOptions> {} Per-service configuration

ServiceEndpointOptions

Property Type Default Description
BaseUrl string "" Base URL of the service
ApiVersion string? null API version override (falls back to default)
Timeout int? null Timeout override in seconds (falls back to default)
DefaultLanguage string? null BCP-47 tag sent as X-Language header (e.g. "en", "vi")
ApiKeyHeader string? null API key header name
ApiKey string? null API key value
Headers Dictionary<string, string> {} Additional default headers
Property Type Default Description
DefaultProject string? null Default project scope for menu queries
DefaultPlatform string? null Default platform scope for menu queries

IamServiceOptions

Property Type Default Description
GrpcGatewayUrl string "" gRPC gateway URL. Resolves via config → ENV_GRPC_GATEWAY_URLhttp://localhost:8081

QuotaServiceOptions

Property Type Default Description
BaseUrl string "" HTTP base URL. Resolves via config → ENV_QUOTA_BASE_URLhttp://localhost:8080
GrpcUrl string "" gRPC URL. Resolves via config → ENV_QUOTA_GRPC_URLhttp://localhost:5101
TimeoutSeconds int 5 Request timeout in seconds
FailOpen bool true Allow requests when Quota Service is unreachable
EnableCaching bool false Enable distributed caching for check/usage results
CacheDurationSeconds int 30 Cache TTL in seconds (when caching is enabled)

NeraResult<T>

Property Type Description
Status string "Success" or "Fail"
Message string Top-level status message (localised)
Data T? Response payload — present when IsSuccess
Metadata NeraMetadata? Trace id, processing time, pagination
Error NeraError? Structured error — present when Status == "Fail"
IsSuccess bool Convenience: Status == "Success"

NeraError

Property Type Description
Code string Application error code (e.g. "MENU_NOT_FOUND")
Message string Localised error description
ErrorDetails Dictionary<string,object>? Field-level validation detail map

NeraMetadata

Property Type Description
TraceId string? Distributed trace identifier
ProcessingTime long Server-side processing time (ms)
Timestamp DateTime Server UTC timestamp
Pagination NeraPagination? Pagination info on list endpoints

License

Internal — Nextera Platform

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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
1.0.0 121 3/8/2026
1.0.0-dev0.2 63 3/8/2026
1.0.0-dev0.1 60 3/8/2026