### Example: Program.cs with ImmediateAssemblyIdentifier Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/CONFIGURATION.md Demonstrates applying the ImmediateAssemblyIdentifier attribute and using the generated endpoint mapping methods in a typical ASP.NET Core application setup. ```csharp // Program.cs [assembly: ImmediateAssemblyIdentifier("Web")] var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); // Now use the generated method app.MapWebEndpoints(); var userGroup = app.MapWebUserManagementEndpoints("/api/users"); userGroup.RequireAuthorization(); app.Run(); ``` -------------------------------- ### MapXxxEndpoints Examples Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Examples of mapping endpoints for assemblies named 'Web' and 'Application.Web'. ```csharp // For assembly named "Web" app.MapWebEndpoints(); // For assembly named "Application.Web" app.MapApplicationWebEndpoints(); ``` -------------------------------- ### MapGetAttribute Usage Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Shows how to use the MapGetAttribute to register a handler for GET requests on a single route. ```csharp [Handler] [MapGet("/users")] public static partial class GetUsers { public record Query; private static ValueTask> HandleAsync( Query _, CancellationToken token) { return GetUsersAsync(); } } ``` -------------------------------- ### MapXxxYyyEndpoints Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Example of mapping endpoints for user management with authorization and tags. ```csharp app.MapApplicationUserManagementEndpoints("/api/users") .RequireAuthorization(Policies.Admin) .WithTags("User Management"); ``` -------------------------------- ### Runtime Dependency Injection Setup Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/CONFIGURATION.md Register handler dependencies using ASP.NET Core's built-in DI container in your Program.cs file. This example shows scoped, singleton, and transient registrations. ```csharp // Program.cs var builder = WebApplication.CreateBuilder(args); // Register handler dependencies builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddTransient(); var app = builder.Build(); // Register all endpoints app.MapApplicationWebEndpoints(); app.Run(); ``` -------------------------------- ### MapMethodAttribute Usage Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Demonstrates how to use the MapMethodAttribute to register a handler for GET requests on multiple routes. ```csharp [Handler] [MapMethod("GET", "/api/users", "/api/users/{id}")] public static partial class GetUsersHandler { public record Query; private static ValueTask> HandleAsync( Query _, CancellationToken token) { return ValueTask.FromResult(GetUsers()); } } ``` -------------------------------- ### Define an API Handler with Immediate.Handlers Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Integrate API endpoints by marking classes with the `[Handler]` attribute from `Immediate.Handlers.Shared`. This example demonstrates defining a GET endpoint for fetching users, including request definition, handler method, and dependency injection. ```csharp using Immediate.Apis.Shared; using Immediate.Handlers.Shared; [Handler] [MapGet("/users")] public static partial class GetUsers { public record Query; private static ValueTask> HandleAsync( Query query, UserService service, CancellationToken token) { return service.GetAllUsersAsync(token); } } ``` -------------------------------- ### Add Immediate.Apis Package Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Installs the Immediate.Apis package and its dependency Immediate.Handlers into your .NET project. ```bash dotnet add package Immediate.Apis ``` -------------------------------- ### Create a User Handler with GET Endpoint Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Defines a handler for fetching users with a GET request mapped to '/users'. Requires UserService and User record. ```csharp using Immediate.Apis.Shared; using Immediate.Handlers.Shared; namespace MyApp.Features.Users; [Handler] [MapGet("/users")] public static partial class GetUsers { public record Query; private static async ValueTask> HandleAsync( Query _, UserService service, CancellationToken token) { return await service.GetAllAsync(token); } } public record User(int Id, string Name, string Email); ``` -------------------------------- ### Dependency Injection Setup Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Configures common services, including database context, scoped services, infrastructure components, authentication, and authorization policies for a web application. ```csharp var builder = WebApplication.CreateBuilder(args); // Database builder.Services.AddDbContext(); // Services builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped, CreateUserCommandValidator>(); // Infrastructure builder.Services.AddLogging(); builder.Services.AddCors(); builder.Services.AddAuthentication("Bearer") .AddJwtBearer(); builder.Services.AddAuthorization(options => { options.AddPolicy("Admin", policy => policy.RequireRole("Administrator")); options.AddPolicy("User", policy => policy.RequireRole("User", "Administrator")); }); var app = builder.Build(); // Middleware app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); // Map endpoints app.MapApplicationWebEndpoints(); app.Run(); ``` -------------------------------- ### GET Request Binding with AsParameters Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/CONFIGURATION.md Demonstrates default binding for GET requests where parameters are sourced from route and query. Uses [AsParameters] to combine route and query parameters. ```csharp [Handler] [MapGet("/users/{id:int}")] public static partial class GetUser { public record Query { [FromRoute] public required int Id { get; init; } [FromQuery] public int PageSize { get; init; } } private static ValueTask HandleAsync( [AsParameters] Query query, UserService service, CancellationToken token) { return service.GetUserAsync(query.Id, token); } } ``` -------------------------------- ### Handler Parameter Injection Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/CONFIGURATION.md Demonstrates how handler parameters like UserService and ILogger are automatically resolved from the DI container when using Immediate.Apis. ```csharp [Handler] [MapGet("/users")] public static partial class GetUsers { private static ValueTask> HandleAsync( Query query, UserService userService, // Resolved from DI ILogger logger, // Resolved from DI CancellationToken token) { logger.LogInformation("Getting users"); return userService.GetAllAsync(token); } public record Query; } ``` -------------------------------- ### Minimal GET Endpoint Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Defines a minimal GET endpoint using Immediate.Apis. Requires the `Immediate.Apis.Shared` and `Immediate.Handlers.Shared` namespaces. The endpoint maps to `/users` and handles queries to retrieve all users via a `UserService`. ```csharp using Immediate.Apis.Shared; using Immediate.Handlers.Shared; [Handler] [MapGet("/users")] public static partial class GetUsers { public record Query; private static async ValueTask> HandleAsync( Query _, UserService service, CancellationToken token) { return await service.GetAllUsersAsync(token); } } ``` ```csharp var builder = WebApplication.CreateBuilder(args); builder.Services.AddScoped(); var app = builder.Build(); app.MapApplicationWebEndpoints(); app.Run(); ``` -------------------------------- ### Setup OpenAPI/Swagger Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Configures Swagger generation, including API information, security definitions (Bearer token), and security requirements. This enables interactive API documentation. ```csharp builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1", Description = "API documentation" }); options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Name = "Authorization", Type = SecuritySchemeType.Http, Scheme = "bearer", BearerFormat = "JWT" }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); }); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.MapApplicationWebEndpoints(); app.Run(); ``` -------------------------------- ### AuthorizeAttribute Usage (General) Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Example of an API endpoint that requires authorization. Requires the 'Handler' and 'MapGet' attributes. ```csharp [Handler] [MapGet("/users")] [Authorize] public static partial class GetUsers { public record Query; private static ValueTask> HandleAsync( Query _, CancellationToken token) { return GetUsersAsync(); } } ``` -------------------------------- ### Setup Swagger Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Configures Swagger/OpenAPI support for the application, including defining API information, security schemes (Bearer token), and enabling Swagger UI in development environments. ```APIDOC ## Setup Swagger ### Description Configures Swagger/OpenAPI support for the application, including defining API information, security schemes (Bearer token), and enabling Swagger UI in development environments. ### Code Example ```csharp builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1", Description = "API documentation" }); options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Name = "Authorization", Type = SecuritySchemeType.Http, Scheme = "bearer", BearerFormat = "JWT" }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } }); }); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.MapApplicationWebEndpoints(); app.Run(); ``` ``` -------------------------------- ### Test User Endpoint with curl Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Example of how to test the /users endpoint using curl after the application is running. ```bash curl https://localhost:7000/users ``` -------------------------------- ### MapPostAttribute Usage Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Demonstrates using the MapPostAttribute to register a handler for POST requests, including a command object for request data. ```csharp [Handler] [MapPost("/users")] public static partial class CreateUser { public record Command { public required string Name { get; init; } public required string Email { get; init; } } private static async ValueTask HandleAsync( Command cmd, UserService service, CancellationToken token) { return await service.CreateUserAsync(cmd.Name, cmd.Email, token); } } ``` -------------------------------- ### Both AllowAnonymous and Authorize (IAPI0003) - Invalid Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/ERRORS.md Shows a handler with both [AllowAnonymous] and [Authorize] attributes, which are contradictory and cause the IAPI0003 error. ```csharp [Handler] [MapGet("/data")] [AllowAnonymous] [Authorize] // ERROR: Conflicts with AllowAnonymous public static partial class GetData { public record Query; private static ValueTask HandleAsync( Query _, CancellationToken token) { return ValueTask.FromResult("data"); } } ``` -------------------------------- ### Missing Handler Attribute (IAPI0001) - Invalid Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/ERRORS.md Demonstrates a class decorated with an HTTP method attribute but missing the required [Handler] attribute. This is an invalid configuration. ```csharp using Immediate.Handlers.Shared; using Immediate.Apis.Shared; [Handler] [MapGet("/users")] public static partial class GetUsers { public record Query; private static ValueTask> HandleAsync( Query _, CancellationToken token) { return GetUsersAsync(); } } ``` -------------------------------- ### Setup CORS Policy Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Configures a CORS policy named 'AllowWeb' to allow requests from specified origins with any method, header, and credentials. ```APIDOC ## Setup CORS Policy ### Description Configures a CORS policy named 'AllowWeb' to allow requests from specified origins with any method, header, and credentials. ### Code Example ```csharp var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors(options => { options.AddPolicy("AllowWeb", policy => policy .WithOrigins("https://example.com", "https://app.example.com") .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials() ); }); var app = builder.Build(); app.UseCors("AllowWeb"); app.MapApplicationWebEndpoints(); app.Run(); ``` ``` -------------------------------- ### Get User by ID (GET) Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Retrieves a specific user by their integer ID. This handler is configured to produce a UserResponse on success (200 OK) and a problem detail for not found (404 Not Found). ```csharp [Handler] [MapGet("/users/{id:int}")] [AllowAnonymous] public static partial class GetUserById { internal static void CustomizeEndpoint(RouteHandlerBuilder endpoint) { endpoint .WithDescription("Get a specific user by ID") .Produces(StatusCodes.Status200OK) .ProducesProblem(StatusCodes.Status404NotFound); } public record Query { [FromRoute] public required int Id { get; init; } } private static async ValueTask HandleAsync( [AsParameters] Query query, UserService service, CancellationToken token) { var user = await service.GetUserAsync(query.Id, token); return new UserResponse(user); } } ``` ```http GET /users/42 ``` ```json { "id": 42, "name": "John Doe", "email": "john@example.com" } ``` -------------------------------- ### Handler Structure Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INDEX.md This snippet shows the basic structure of a handler in Immediate.APIs. It includes required attributes like [Handler] and [MapGet], optional attributes for authorization and grouping, and the definition of the request type and handler method. ```csharp [Handler] // Required: From Immediate.Handlers [MapGet("/endpoint")] // Required: HTTP method [Authorize("PolicyName")] // Optional: Authorization [RouteGroup("GroupName")] // Optional: Grouping public static partial class FeatureName { internal static void CustomizeEndpoint(RouteHandlerBuilder endpoint) { } // Optional internal static Results, ...> TransformResult(T result) { } // Optional public record Query { } // Request type private static ValueTask HandleAsync( Query request, IDependency dep, CancellationToken token) { } // Handler method } ``` -------------------------------- ### Get Product by ID Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Retrieves detailed information about a specific product using its unique identifier. ```APIDOC ## GET /products/{id:int} ### Description Retrieves detailed information about a specific product using its unique identifier. ### Method GET ### Endpoint /products/{id:int} ### Parameters #### Path Parameters - **id** (int) - Required - The unique product identifier ### Response #### Success Response (200) - **ProductResponse** - Details of the product #### Error Response - **404** - Product not found ``` -------------------------------- ### MapPutAttribute Usage Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Demonstrates how to use the MapPutAttribute to define an HTTP PUT endpoint for updating a user. It includes command record for request data and a handler method. ```csharp [Handler] [MapPut("/users/{id:int}")] public static partial class UpdateUser { public record Command { [FromRoute] public required int Id { get; init; } [FromBody] public required string Name { get; init; } } private static async ValueTask HandleAsync( [AsParameters] Command cmd, UserService service, CancellationToken token) { return await service.UpdateUserAsync(cmd.Id, cmd.Name, token); } } ``` -------------------------------- ### Create User Endpoint Handler Source: https://github.com/immediateplatform/immediate.apis/blob/main/readme.md Defines a handler for a GET request to /users that retrieves a list of users. ```csharp [Handler] [MapGet("/users")] public static partial class GetUsersQuery { public record Query; private static ValueTask> HandleAsync( Query _, UsersService usersService, CancellationToken token) { return usersService.GetUsers(); } } ``` -------------------------------- ### Handler Return Types Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/TYPES.md Examples of supported handler return types, including simple values, multiple status codes, no content, and typed results. ```csharp // Simple value private static ValueTask HandleAsync(...) ``` ```csharp // Multiple status codes internal static Results, NotFound> TransformResult(User user) ``` ```csharp // No content private static ValueTask HandleAsync(...) ``` ```csharp // Typed results internal static Results>, Unauthorized> TransformResult(List users) ``` -------------------------------- ### Handler Method Signature Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/CONFIGURATION.md Defines the signature for an asynchronous handler method, illustrating required and optional parameters like the request, dependencies, and cancellation token. ```csharp private static async ValueTask HandleAsync( TRequest request, // Required: request/command [AsParameters] TRequest request, // Alternative: composite parameters IDependency service, // Optional: injected dependency CancellationToken token // Optional: cancellation token ) ``` -------------------------------- ### Customize Endpoint with RouteHandlerBuilder Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md This example demonstrates customizing an endpoint using RouteHandlerBuilder, applying descriptions, OpenAPI metadata, specific response types, error codes, and tags. This is useful for fine-grained control over API behavior and documentation. ```csharp [Handler] [MapGet("/users/{id:int}")] public static partial class GetUserById { internal static void CustomizeEndpoint(RouteHandlerBuilder endpoint) => endpoint .WithDescription("Retrieves a user by ID") .WithOpenApi() .Produces(StatusCodes.Status200OK) .ProducesProblem(StatusCodes.Status404NotFound) .WithTags("Users"); public record Query { [FromRoute] public required int Id { get; init; } } private static async ValueTask HandleAsync( [AsParameters] Query query, UserService service, CancellationToken token) { return await service.GetUserAsync(query.Id, token); } } ``` -------------------------------- ### MapPatchAttribute Usage Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Demonstrates how to use the MapPatchAttribute to define an HTTP PATCH endpoint for partial user updates. It includes a command record for request data and a handler method. ```csharp [Handler] [MapPatch("/users/{id:int}")] public static partial class PatchUser { public record Command { [FromRoute] public required int Id { get; init; } public string? Name { get; init; } } private static async ValueTask HandleAsync( [AsParameters] Command cmd, UserService service, CancellationToken token) { await service.PartialUpdateAsync(cmd.Id, cmd.Name, token); } } ``` -------------------------------- ### Environment-Specific Endpoint Configuration Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/CONFIGURATION.md Utilize ASP.NET Core configuration patterns for environment-specific endpoint setup, such as enabling Swagger in development or HTTPS redirection in production. ```csharp var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.MapSwagger(); } app.MapApplicationWebEndpoints(); if (app.Environment.IsProduction()) { app.UseHttpsRedirection(); app.UseHsts(); } app.Run(); ``` -------------------------------- ### MapDeleteAttribute Usage Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Demonstrates how to use the MapDeleteAttribute to define an HTTP DELETE endpoint for removing a user. It includes a command record for request data and a handler method. ```csharp [Handler] [MapDelete("/users/{id:int}")] public static partial class DeleteUser { public record Command { [FromRoute] public required int Id { get; init; } } private static async ValueTask HandleAsync( [AsParameters] Command cmd, UserService service, CancellationToken token) { return await service.DeleteUserAsync(cmd.Id, token); } } ``` -------------------------------- ### Map Custom HTTP Method Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Use `MapMethod` to define custom HTTP methods like OPTIONS for specific routes. This example also shows how to customize endpoint descriptions and names. ```csharp [Handler] [MapMethod("OPTIONS", "/api/schema")] [AllowAnonymous] public static partial class GetApiSchema { internal static void CustomizeEndpoint(RouteHandlerBuilder endpoint) { endpoint .WithDescription("CORS preflight and schema information") .WithName("ApiSchema"); } public record Query; private static ValueTask HandleAsync( Query _, SchemaService service, CancellationToken token) { return service.GetSchemaAsync(token); } } ``` -------------------------------- ### Transform Result for User Creation Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md This example shows how to transform a handler's result for user creation, returning either a Created response with the user data or a BadRequest with an error message. This allows for specific handling of success and failure scenarios in API responses. ```csharp [Handler] [MapPost("/users")] public static partial class CreateUser { internal static Results, BadRequest> TransformResult(User user) { if (user?.Id == 0) return TypedResults.BadRequest("User creation failed"); return TypedResults.Created($"/users/{user.Id}", user); } public record Command { public required string Name { get; init; } public required string Email { get; init; } } private static async ValueTask HandleAsync( Command cmd, UserService service, CancellationToken token) { return await service.CreateUserAsync(cmd, token); } } ``` -------------------------------- ### AuthorizeAttribute Usage (Specific Policy) Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Example of an API endpoint that requires a specific authorization policy ('AdminPolicy'). Requires the 'Handler' and 'MapDelete' attributes. ```csharp [Handler] [MapDelete("/users/{id:int}")] [Authorize("AdminPolicy")] public static partial class DeleteUser { public record Command { [FromRoute] public required int Id { get; init; } } private static async ValueTask HandleAsync( [AsParameters] Command cmd, UserService service, CancellationToken token) { await service.DeleteAsync(cmd.Id, token); } } ``` -------------------------------- ### Document Endpoint with Customizations Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Defines and documents a GET endpoint for retrieving a user by ID. It specifies the HTTP method, route, authorization, response types, and provides a description and tags for Swagger. ```csharp [Handler] [MapGet("/users/{id:int}")] [AllowAnonymous] public static partial class GetUserById { internal static void CustomizeEndpoint(RouteHandlerBuilder endpoint) { endpoint .WithName("GetUserById") .WithOpenApi() .WithDescription("Retrieves a user by their ID") .Produces(StatusCodes.Status200OK) .ProducesProblem(StatusCodes.Status404NotFound) .WithTags("Users"); } public record Query { [FromRoute] public required int Id { get; init; } } private static async ValueTask HandleAsync( [AsParameters] Query query, UserService service, CancellationToken token) { return await service.GetByIdAsync(query.Id, token); } } ``` -------------------------------- ### Register Services and Map Endpoints in Program.cs Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Sets up the application services, including UserService and routing, and maps all generated endpoints. ```csharp var builder = WebApplication.CreateBuilder(args); // Add services builder.Services.AddScoped(); builder.Services.AddRouting(); var app = builder.Build(); // Map all endpoints app.MapMyAppWebEndpoints(); app.Run(); ``` -------------------------------- ### Resolve Duplicate Endpoint Definitions Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/ERRORS.md When multiple handlers register the same HTTP method and route, an error occurs. This example shows how to resolve this by using distinct routes, different HTTP methods, or multiple routes on a single handler. ```csharp [Handler] [MapGet("/users")] public static partial class GetUsersV1 { public record Query; private static ValueTask> HandleAsync(Query _, CancellationToken token) { return GetUsersAsync(); } } [Handler] [MapGet("/users")] // ERROR: Duplicate route public static partial class GetUsersV2 { public record Query; private static ValueTask> HandleAsync(Query _, CancellationToken token) { return GetUsersAsync(); } } ``` ```csharp // Option 1: Different routes [Handler] [MapGet("/users/v1")] public static partial class GetUsersV1 { } [Handler] [MapGet("/users/v2")] public static partial class GetUsersV2 { } // Option 2: Different HTTP methods [Handler] [MapGet("/users")] public static partial class GetUsers { } [Handler] [MapPost("/users")] public static partial class CreateUser { } // Option 3: Multiple routes, avoid conflicts [Handler] [MapGet("/users", "/api/users")] public static partial class GetUsers { } ``` -------------------------------- ### HTTP Method Attributes Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/CONFIGURATION.md Use these attributes to define the HTTP method and route for a handler. Multiple routes can be specified, and routes can include constraints or default values. Supported methods include GET, POST, PUT, PATCH, DELETE, and custom methods. ```csharp [MapGet("/path")] // Single route [MapGet("/path1", "/path2")] // Multiple routes [MapGet("/users/{id:int}")] // Route with constraint [MapGet("/users/{name=default}")] // Route with default [MapPost("/users")] // POST single route [MapPut("/users/{id:int}")] // PUT with parameter [MapMethod("OPTIONS", "/metadata")] // Custom HTTP method ``` -------------------------------- ### Query Handler Method Signature Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/TYPES.md Defines the signature pattern for a Query handler, typically used for GET requests. The request object must be the first parameter, followed by dependencies and an optional CancellationToken. ```csharp public record Query; private static async ValueTask HandleAsync( Query request, TDependency dependency, CancellationToken token) ``` -------------------------------- ### Build, Test, Publish, and Dockerize Application Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Provides bash commands for building, testing, publishing, and containerizing the application using Docker. ```bash # Build dotnet build -c Release # Test dotnet test # Publish dotnet publish -c Release # Docker docker build -t myapi:latest . docker run -p 80:8080 myapi:latest ``` -------------------------------- ### Project File Configuration (.NET SDK) Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/CONFIGURATION.md Configure your .NET SDK-style project file to include Immediate.Apis and Immediate.Handlers. Ensure the target framework is .NET 8.0 or later. ```xml net8.0 enable enable ``` -------------------------------- ### Build and Run ASP.NET Core Application Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Commands to build the project and run the application locally. ```bash dotnet build dotnet run ``` -------------------------------- ### MapGetAttribute for GET Endpoint Registration Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/TYPES.md Mark handler classes with this attribute to register GET endpoints. It inherits from MapMethodAttribute and accepts route templates. ```csharp public sealed class MapGetAttribute : MapMethodAttribute { public MapGetAttribute([StringSyntax("Route")] params string[] routes) public MapGetAttribute(string route) } ``` -------------------------------- ### GET /users Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Retrieves a list of users. Requires authorization. ```APIDOC ## GET /users ### Description Retrieves a list of users. Requires authorization. ### Method GET ### Endpoint /users ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Request Example ```json { "example": "request body" } ``` ### Response #### Success Response (200) - `IEnumerable` (type) - Description #### Response Example ```json { "example": "response body" } ``` ``` -------------------------------- ### GET /public-data Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Allows anonymous access to public data. ```APIDOC ## GET /public-data ### Description Allows anonymous access to public data. ### Method GET ### Endpoint /public-data ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Request Example ```json { "example": "request body" } ``` ### Response #### Success Response (200) - `PublicData` (type) - Description #### Response Example ```json { "example": "response body" } ``` ``` -------------------------------- ### Get User By ID Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Retrieves a specific user by their unique identifier. ```APIDOC ## GET /users/{id:int} ### Description Retrieves a specific user by their unique identifier. ### Method GET ### Endpoint /users/{id:int} ### Parameters #### Path Parameters - **id** (integer) - Required - The unique identifier of the user. ### Response #### Success Response (200 OK) - **id** (integer) - The unique identifier of the user. - **name** (string) - The name of the user. - **email** (string) - The email address of the user. #### Response Example { "id": 42, "name": "John Doe", "email": "john@example.com" } ``` -------------------------------- ### Streaming Response - GET /data/stream Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Streams data in chunks using an asynchronous enumerable. ```APIDOC ## GET /data/stream ### Description Stream data in chunks ### Method GET ### Endpoint /data/stream ### Parameters #### Query Parameters - **_** (Query) - Required - Represents the query parameters for the request. ### Request Example ```json { "example": "" } ``` ### Response #### Success Response (200) - **DataChunk** (DataChunk) - Description of the data chunk returned in the stream. ``` -------------------------------- ### ImmediateApisGenerator Class Implementation Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/SOURCE-GENERATOR.md This snippet shows the core implementation of the `ImmediateApisGenerator`, detailing its initialization pipeline for processing handler classes and generating API registration code. ```csharp using Immediate.Handlers.Shared; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace Immediate.Apis.Generators; [Generator] public sealed partial class ImmediateApisGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { // 1. Find all [Handler] classes with HTTP method attributes var methods = context.SyntaxProvider .ForAttributeWithMetadataName( "Immediate.Handlers.Shared.HandlerAttribute", predicate: (node, _) => node is TypeDeclarationSyntax, transform: TransformMethod ) .WhereNotNull() .WithTrackingName("Handlers"); // 2. Extract assembly identifier var assemblyName = context.CompilationProvider .Select((cp, _) => cp.GetAssemblyIdentifier()) .WithTrackingName("AssemblyName"); // 3. Generate per-method route files var perMethodTemplate = Utility.GetTemplate("Route"); context.RegisterSourceOutput( methods.Combine(assemblyName), (spc, m) => RenderMethod(spc, m.Left!, m.Right, perMethodTemplate) ); // 4. Group methods by route group var allGroups = methods .Collect() .SelectMany( (g, _) => g .GroupBy( m => m.RouteGroupName, (k, g) => new RouteGroup { Name = k, Methods = g.ToEquatableReadOnlyList() }, StringComparer.Ordinal ) ) .Where(x => x.Name is null || RouteGroupUtility.IsValidRouteGroupName(x.Name)) .WithTrackingName("GroupedMethods"); // 5. Generate route group registration files var allMethodsTemplate = Utility.GetTemplate("Routes"); context.RegisterSourceOutput( allGroups.Combine(assemblyName), (spc, m) => RenderRouteGroup(spc, m.Left, m.Right, allMethodsTemplate) ); } } ``` -------------------------------- ### Get Route Group from Attribute Data Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/SOURCE-GENERATOR.md Extracts the route group from attribute data. ```csharp public string? GetRouteGroup() ``` -------------------------------- ### Create User (POST) Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Handles the creation of a new user. It maps to a POST request on the /users endpoint. Ensure the User ID is not 0 to confirm successful creation. ```csharp [Handler] [MapPost("/users")] [AllowAnonymous] public static partial class CreateUser { internal static Results, BadRequest> TransformResult(User user) { if (user?.Id == 0) return TypedResults.BadRequest("User creation failed"); return TypedResults.Created($"/users/{user.Id}", new UserResponse(user)); } public record Command { public required string Name { get; init; } public required string Email { get; init; } } private static async ValueTask HandleAsync( Command cmd, UserService service, CancellationToken token) { return await service.CreateUserAsync(cmd.Name, cmd.Email, token); } } ``` ```http POST /users Content-Type: application/json { "name": "John Doe", "email": "john@example.com" } ``` ```http Location: /users/42 Content-Type: application/json { "id": 42, "name": "John Doe", "email": "john@example.com" } ``` -------------------------------- ### Get HTTP Method from Attribute Data Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/SOURCE-GENERATOR.md Extracts the HTTP method from attribute data. ```csharp public string? GetHttpMethod() ``` -------------------------------- ### Recommended Project Structure Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Illustrates a typical layered architecture for a C# application, separating concerns into Features, Services, Models, and Data layers. ```text MyApp/ ├── Features/ │ ├── Users/ │ │ ├── GetUsers.cs │ │ ├── GetUserById.cs │ │ ├── CreateUser.cs │ │ ├── UpdateUser.cs │ │ └── DeleteUser.cs │ ├── Products/ │ │ ├── GetProducts.cs │ │ ├── GetProductById.cs │ │ └── CreateProduct.cs │ └── Admin/ │ │ ├── GetAnalytics.cs │ │ └── ManageUsers.cs ├── Services/ │ ├── UserService.cs │ ├── ProductService.cs │ └── AnalyticsService.cs ├── Models/ │ ├── User.cs │ ├── Product.cs │ └── CreateUserCommand.cs ├── Data/ │ └── AppDbContext.cs ├── Program.cs └── appsettings.json ``` -------------------------------- ### AllowAnonymousAttribute Usage Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Example of an API endpoint that allows anonymous access. Requires the 'Handler' and 'MapGet' attributes. ```csharp [Handler] [MapGet("/public-data")] [AllowAnonymous] public static partial class GetPublicData { public record Query; private static ValueTask HandleAsync( Query _, CancellationToken token) { return GetPublicDataAsync(); } } ``` -------------------------------- ### Unit Test API Handler Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Demonstrates how to unit test API handlers using a mocking framework. Arrange the service dependencies, act by calling the handler, and assert the results. ```csharp [TestFixture] public class GetUserTests { [Test] public async Task GetUser_WithValidId_ReturnsUser() { // Arrange var service = new Mock(); service.Setup(s => s.GetUserAsync(42, It.IsAny())) .ReturnsAsync(new User { Id = 42, Name = "John" }); // Act var result = await GetUserById.HandleAsync( new GetUserById.Query { Id = 42 }, service.Object, CancellationToken.None ); // Assert Assert.That(result.Id, Is.EqualTo(42)); Assert.That(result.Name, Is.EqualTo("John")); } } ``` -------------------------------- ### Integrate OpenAPI/Swagger with Minimal APIs Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md This snippet demonstrates how to configure OpenAPI/Swagger documentation for a Minimal API endpoint using attributes and the WithOpenApi() method. It specifies response types, status codes, and tags for better API discoverability. ```csharp [Handler] [MapGet("/products/{id:int}")] [AllowAnonymous] public static partial class GetProduct { /// Get a product by ID /// Retrieves detailed information about a specific product /// Product found /// Product not found internal static void CustomizeEndpoint(RouteHandlerBuilder endpoint) { endpoint .WithName("GetProduct") .WithOpenApi() .WithDescription("Retrieves a product by its ID") .Produces(StatusCodes.Status200OK) .ProducesProblem(StatusCodes.Status404NotFound) .WithTags("Products"); } public record Query { /// The unique product identifier [FromRoute] public required int Id { get; init; } } private static async ValueTask HandleAsync( [AsParameters] Query query, ProductService service, CancellationToken token) { return await service.GetProductAsync(query.Id, token); } } ``` -------------------------------- ### Get Map Method Method from Attribute Data Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/SOURCE-GENERATOR.md Extracts the map method method from attribute data. ```csharp public string? GetMapMethodMethod() ``` -------------------------------- ### Get Map Method Name from Attribute Data Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/SOURCE-GENERATOR.md Extracts the map method name from attribute data. ```csharp public string GetMapMethodName() ``` -------------------------------- ### Create User Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Creates a new user with the provided name and email. ```APIDOC ## POST /users ### Description Creates a new user with the provided name and email. ### Method POST ### Endpoint /users ### Request Body - **name** (string) - Required - The name of the user. - **email** (string) - Required - The email address of the user. ### Request Example { "name": "John Doe", "email": "john@example.com" } ### Response #### Success Response (201 Created) - **id** (integer) - The unique identifier of the created user. - **name** (string) - The name of the user. - **email** (string) - The email address of the user. #### Response Example { "id": 42, "name": "John Doe", "email": "john@example.com" } ``` -------------------------------- ### Get User by ID Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Retrieves a specific user by their integer ID. This endpoint is part of the Users route group. ```APIDOC ## GET /{id:int} ### Description Retrieves a specific user by their integer ID. This endpoint is part of the Users route group. ### Method GET ### Endpoint /api/users/{id:int} ### Parameters #### Path Parameters - **id** (int) - Required - The unique identifier of the user. #### Query Parameters (No query parameters documented) #### Request Body (No request body documented) ### Response #### Success Response (200) (No response fields documented) #### Response Example (No response example provided) ``` -------------------------------- ### Docker Configuration for .NET Application Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Defines a Dockerfile for building and publishing a .NET application, preparing it for deployment. ```dockerfile FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY . . RUN dotnet restore RUN dotnet publish -c Release -o /app/publish FROM mcr.microsoft.com/dotnet/aspnet:8.0 WORKDIR /app COPY --from=build /app/publish . ENTRYPOINT ["dotnet", "MyApp.dll"] ``` -------------------------------- ### Treat Command Class as AsParameters Source: https://github.com/immediateplatform/immediate.apis/blob/main/readme.md Instruct Immediate.Apis to treat the outer `Command` class as `[AsParameters]` in the `HandleAsync` method. This allows binding parameters from different sources like route and body. ```csharp private static async ValueTask> HandleAsync( [AsParameters] Command command, ExampleDbContext dbContext, CancellationToken ct ) { // ... } ``` -------------------------------- ### MapGetAttribute Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/TYPES.md Attribute to mark handler classes for GET endpoint registration. It is accepted by classes decorated with the `[Handler]` attribute. ```APIDOC ## MapGetAttribute ### Description Attribute to mark handler classes for GET endpoint registration. It is accepted by classes decorated with the `[Handler]` attribute. ### Attribute Signature ```csharp public sealed class MapGetAttribute : MapMethodAttribute { public MapGetAttribute([StringSyntax("Route")] params string[] routes) public MapGetAttribute(string route) } ``` ### Inherits from `MapMethodAttribute` ### Uses - Mark handler classes for GET endpoint registration. - Accepted by classes decorated with `[Handler]`. ### Scope Public API ``` -------------------------------- ### List Admin Users Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Retrieves a list of all admin users. This endpoint is accessible via a GET request to the root of the admin API. ```APIDOC ## GET /api/admin/ ### Description Retrieves a list of all admin users. ### Method GET ### Endpoint /api/admin/ ``` -------------------------------- ### Get Data by ID with Error Handling Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md Retrieves data by its ID, demonstrating a pattern for handling success, not found, and internal server errors. ```APIDOC ## GET /data/{id:int} ### Description Retrieves data by its ID, demonstrating a pattern for handling success, not found, and internal server errors. ### Method GET ### Endpoint /data/{id:int} ### Parameters #### Path Parameters - **id** (int) - Required - The unique identifier for the data ### Response #### Success Response (200) - **DataResponse** - The requested data #### Error Response - **404** - Data not found - **500** - Internal Server Error ``` -------------------------------- ### Configure CORS Policy Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/INTEGRATION.md Sets up a CORS policy named 'AllowWeb' allowing requests from specified origins with any method, header, and credentials. This is typically done during application startup. ```csharp var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors(options => { options.AddPolicy("AllowWeb", policy => policy .WithOrigins("https://example.com", "https://app.example.com") .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials() ); }); var app = builder.Build(); app.UseCors("AllowWeb"); app.MapApplicationWebEndpoints(); app.Run(); ``` -------------------------------- ### MapGetAttribute Definition Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/API-REFERENCE.md Defines the attribute for marking handler classes for HTTP GET endpoint registration. Supports single or multiple route patterns. ```csharp public sealed class MapGetAttribute : MapMethodAttribute { public MapGetAttribute(params string[] routes) public MapGetAttribute(string route) } ``` -------------------------------- ### File Organization Structure Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/README.md This snippet shows the directory structure for the Immediate.Apis project, outlining the purpose of each markdown file. ```markdown ├── INDEX.md ← Start here ├── API-REFERENCE.md ← Public API documentation ├── TYPES.md ← Type reference ├── CONFIGURATION.md ← Configuration options ├── USAGE-PATTERNS.md ← Real-world examples ├── INTEGRATION.md ← Setup guide ├── SOURCE-GENERATOR.md ← Generator internals ├── ERRORS.md ← Error diagnostics └── README.md ← This file ``` -------------------------------- ### PUT/PATCH Request Binding with Mixed Sources Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/CONFIGURATION.md Shows how to handle PUT/PATCH requests with mixed binding sources (route and request body) using [AsParameters]. Requires explicit [AsParameters] to combine different binding sources. ```csharp [Handler] [MapPut("/users/{id:int}")] public static partial class UpdateUser { public record Command { [FromRoute] public required int Id { get; init; } [FromBody] public required UpdateData Data { get; init; } } private static ValueTask HandleAsync( [AsParameters] Command cmd, UserService service, CancellationToken token) { return service.UpdateAsync(cmd.Id, cmd.Data, token); } } ``` -------------------------------- ### Invalid Route Group Names Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/ERRORS.md Demonstrates route group names that violate C# identifier rules, such as containing hyphens, starting with digits, or being empty. ```csharp [Handler] [MapGet("/")] [RouteGroup("user-management")] // ERROR: Hyphen not allowed public static partial class GetUsers { } [Handler] [MapPost("/")] [RouteGroup("123Users")] // ERROR: Starts with digit public static partial class CreateUser { } [Handler] [MapPut("/")] [RouteGroup("")] // ERROR: Empty string public static partial class UpdateUser { } ``` -------------------------------- ### Invalid Authorize Attribute Parameter (IAPI0002) - Invalid Example Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/ERRORS.md Illustrates an invalid use of the [Authorize] attribute where the parameter is not a string constant. This triggers the IAPI0002 error. ```csharp [Handler] [MapGet("/admin")] [Authorize(123)] // ERROR: Parameter must be a string public static partial class GetAdminData { public record Query; private static ValueTask HandleAsync( Query _, CancellationToken token) { return ValueTask.FromResult("admin data"); } } ``` -------------------------------- ### Perform Batch User Creation with Authorization Source: https://github.com/immediateplatform/immediate.apis/blob/main/_autodocs/USAGE-PATTERNS.md This C# snippet shows how to implement a batch user creation endpoint using a POST request, restricted to administrators. It processes a list of user data, returning success with counts or a bad request containing validation errors. ```csharp [Handler] [MapPost("/users/bulk-create")] [Authorize("Admin")] public static partial class BulkCreateUsers { internal static Results, BadRequest> TransformResult( BulkCreateResult result) { if (result.Errors.Count > 0) return TypedResults.BadRequest(result.Errors.ToArray()); return TypedResults.Ok(new BulkCreateResponse(result.Created, result.Total)); } public record Command { public required IEnumerable Users { get; init; } } public record CreateUserData { public required string Name { get; init; } public required string Email { get; init; } } private static async ValueTask HandleAsync( Command cmd, UserService service, ILogger logger, CancellationToken token) { logger.LogInformation("Bulk creating {Count} users", cmd.Users.Count()); return await service.BulkCreateUsersAsync(cmd.Users, token); } } ```