# Getting Started with StellaOps Router This guide walks you through building your first microservice with the StellaOps Router framework. ## Prerequisites - .NET 10 SDK - Docker (optional, for containerized deployment) ## Step 1: Create the Microservice Project ```bash mkdir MyService cd MyService dotnet new console -n MyService cd MyService ``` Add the required packages: ```bash dotnet add package StellaOps.Microservice dotnet add package StellaOps.Router.Transport.InMemory ``` ## Step 2: Define Your Data Models Create `Models/OrderModels.cs`: ```csharp namespace MyService.Models; public sealed class CreateOrderRequest { public required string CustomerId { get; init; } public required decimal Amount { get; init; } public string? Description { get; init; } } public sealed class CreateOrderResponse { public required string OrderId { get; init; } public DateTimeOffset CreatedAt { get; init; } public string Status { get; init; } = "created"; } public sealed class Order { public required string OrderId { get; init; } public required string CustomerId { get; init; } public required decimal Amount { get; init; } public string? Description { get; init; } public DateTimeOffset CreatedAt { get; init; } } ``` ## Step 3: Create Endpoints Create `Endpoints/CreateOrderEndpoint.cs`: ```csharp using MyService.Models; using StellaOps.Microservice; namespace MyService.Endpoints; /// /// Creates a new order. /// [StellaEndpoint("POST", "/orders", TimeoutSeconds = 30)] public sealed class CreateOrderEndpoint : IStellaEndpoint { private readonly ILogger _logger; public CreateOrderEndpoint(ILogger logger) { _logger = logger; } public Task HandleAsync( CreateOrderRequest request, CancellationToken cancellationToken) { var orderId = $"ORD-{Guid.NewGuid():N}"[..16]; _logger.LogInformation( "Created order {OrderId} for customer {CustomerId}, amount: {Amount}", orderId, request.CustomerId, request.Amount); return Task.FromResult(new CreateOrderResponse { OrderId = orderId, CreatedAt = DateTimeOffset.UtcNow }); } } ``` Create `Endpoints/GetOrderEndpoint.cs`: ```csharp using MyService.Models; using StellaOps.Microservice; namespace MyService.Endpoints; /// /// Retrieves an order by ID. /// [StellaEndpoint("GET", "/orders/{id}", TimeoutSeconds = 10)] public sealed class GetOrderEndpoint : IRawStellaEndpoint { private readonly ILogger _logger; public GetOrderEndpoint(ILogger logger) { _logger = logger; } public Task HandleAsync( RawRequestContext context, CancellationToken cancellationToken) { var orderId = context.PathParameters["id"]; _logger.LogInformation("Fetching order {OrderId}", orderId); // In a real app, you'd look up the order from a database var order = new Order { OrderId = orderId, CustomerId = "CUST-001", Amount = 99.99m, Description = "Sample order", CreatedAt = DateTimeOffset.UtcNow.AddHours(-1) }; var json = System.Text.Json.JsonSerializer.Serialize(order); var body = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json)); var headers = new HeaderCollection(); headers.Set("Content-Type", "application/json"); return Task.FromResult(new RawResponse { StatusCode = 200, Headers = headers, Body = body }); } } ``` ## Step 4: Configure the Service Update `Program.cs`: ```csharp using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using MyService.Endpoints; using StellaOps.Microservice; using StellaOps.Router.Common.Enums; using StellaOps.Router.Transport.InMemory; var builder = Host.CreateApplicationBuilder(args); // Configure logging builder.Logging.AddConsole(); builder.Logging.SetMinimumLevel(LogLevel.Debug); // Configure the microservice builder.Services.AddStellaMicroservice(options => { options.ServiceName = "order-service"; options.Version = "1.0.0"; options.Region = "local"; options.InstanceId = $"order-{Environment.MachineName}"; // Connect to gateway (use InMemory for development) options.Routers = [ new RouterEndpointConfig { Host = "localhost", Port = 5100, TransportType = TransportType.InMemory } ]; }); // Register transport builder.Services.AddInMemoryTransport(); // Register endpoint handlers builder.Services.AddScoped(); builder.Services.AddScoped(); var host = builder.Build(); Console.WriteLine("Order Service starting..."); Console.WriteLine("Endpoints:"); Console.WriteLine(" POST /orders"); Console.WriteLine(" GET /orders/{id}"); await host.RunAsync(); ``` ## Step 5: Create the Gateway Create a separate project for the gateway: ```bash cd .. dotnet new web -n MyGateway cd MyGateway dotnet add package StellaOps.Router.Gateway dotnet add package StellaOps.Router.Transport.InMemory ``` Update `Program.cs`: ```csharp using StellaOps.Router.Gateway; using StellaOps.Router.Gateway.Authorization; using StellaOps.Router.Gateway.DependencyInjection; using StellaOps.Router.Transport.InMemory; var builder = WebApplication.CreateBuilder(args); // Add gateway services builder.Services.AddRouterGateway(builder.Configuration); // Add InMemory transport for development builder.Services.AddInMemoryTransport(); // No-op authorization for demo (use real auth in production) builder.Services.AddNoOpAuthorityIntegration(); builder.Services.AddAuthentication(); // OpenAPI builder.Services.AddEndpointsApiExplorer(); var app = builder.Build(); // Middleware pipeline app.UseAuthentication(); app.UseClaimsAuthorization(); // OpenAPI endpoint (aggregates from all microservices) app.MapRouterOpenApi(); // Health check app.MapGet("/health", () => Results.Ok(new { status = "healthy" })); // Router gateway handles all other routes app.UseRouterGateway(); Console.WriteLine("Gateway starting on http://localhost:5000"); app.Run("http://localhost:5000"); ``` ## Step 6: Run the Services Open two terminals: **Terminal 1 - Gateway:** ```bash cd MyGateway dotnet run ``` **Terminal 2 - Microservice:** ```bash cd MyService dotnet run ``` ## Step 7: Test the API Create an order: ```bash curl -X POST http://localhost:5000/orders \ -H "Content-Type: application/json" \ -d '{"customerId": "CUST-001", "amount": 99.99}' ``` Response: ```json { "orderId": "ORD-abc123def456", "createdAt": "2024-01-15T10:30:00Z", "status": "created" } ``` Get an order: ```bash curl http://localhost:5000/orders/ORD-abc123def456 ``` ## Step 8: Add Validation (Optional) Add JSON Schema validation to your endpoints: ```csharp using StellaOps.Microservice; using StellaOps.Microservice.Validation; [StellaEndpoint("POST", "/orders", TimeoutSeconds = 30)] [ValidateSchema] // Enables JSON Schema validation public sealed class CreateOrderEndpoint : IStellaEndpoint { // ... } ``` The source generator will create a JSON Schema based on your request type's properties and validate incoming requests automatically. ## Step 9: Add Streaming Support (Optional) For large file uploads or real-time data: ```csharp [StellaEndpoint("POST", "/orders/{id}/documents", SupportsStreaming = true)] public sealed class UploadDocumentEndpoint : IRawStellaEndpoint { public async Task HandleAsync( RawRequestContext context, CancellationToken cancellationToken) { var orderId = context.PathParameters["id"]; var contentType = context.Headers["Content-Type"] ?? "application/octet-stream"; // Stream the body directly without buffering await using var bodyStream = context.Body; var totalBytes = 0L; var buffer = new byte[8192]; int bytesRead; while ((bytesRead = await bodyStream.ReadAsync(buffer, cancellationToken)) > 0) { totalBytes += bytesRead; // Process chunk... } var headers = new HeaderCollection(); headers.Set("Content-Type", "application/json"); var response = $$"""{"orderId":"{{orderId}}","bytesReceived":{{totalBytes}}}"""; return new RawResponse { StatusCode = 200, Headers = headers, Body = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(response)) }; } } ``` ## Next Steps - **Production Deployment**: Switch from InMemory to TCP or TLS transport - **Authentication**: Integrate with the Authority module for OAuth/OIDC - **Rate Limiting**: Configure rate limits in router.yaml - **Observability**: Add OpenTelemetry tracing - **Testing**: Write integration tests using the Router.Testing library See the [examples](../examples/) directory for complete working examples.