Immediate.Apis is a source generator for minimal APIs, for
Immediate.Handlers handlers. Simply add a [MapGet] to the
[Handler] class and an endpoint will automatically be added.
dotnet add package Immediate.Apis
Create a Handler and an endpoint by adding the following code:
[Handler][MapGet("/users")]publicstaticpartialclassGetUsersQuery{publicrecordQuery;privatestaticValueTask<IEnumerable<User>>HandleAsync(Query_,UsersServiceusersService,CancellationTokentoken){returnusersService.GetUsers();}}In your Program.cs, add a call to app.MapXxxEndpoints(), where Xxx is the application identifier.
By default, this is the short form of the assembly name. For example:
- For a project named
Web, it will beapp.MapWebEndpoints() - For a project named
Application.Web, it will beapp.MapApplicationWebEndpoints()
However, this name can be overridden using [assembly: ImmediateAssemblyIdentifier("SomeIdentifier")].
By default on POST, PUT, and PATCH requests Immediate.Apis will assume that your request class should be treated as a [FromBody]. Sometimes, however, this is not desired. For example imagine a PUT request that sits at a route /api/todos/{id} and updates a TODO with a given ID. We would want to get the id from the route and the properties to update from the body. To do so, we need to create the following request command class:
publicsealedrecordCommand{publicsealedrecordCommandBody{// props here;}[FromRoute]publicrequiredintId{get;init;}[FromBody]publicrequiredCommandBodyBody{get;init;}}...and modify the HandleAsync method to let Immediate.Apis know we want to treat the outer Command class as [AsParameters], like so:
privatestaticasyncValueTask<Results<NoContent,NotFound>>HandleAsync([AsParameters]Commandcommand,ExampleDbContextdbContext,CancellationTokenct){// ...}The [AllowAnonymous] and [Authorized("Policy")] attributes are supported and will be applied to the endpoint.
[Handler][MapGet("/users")][AllowAnonymous]publicstaticpartialclassGetUsersQuery{publicrecordQuery;privatestaticValueTask<IEnumerable<User>>HandleAsync(Query_,UsersServiceusersService,CancellationTokentoken){returnusersService.GetUsers();}}Additional customization of the endpoint registration can be done by adding a CustomizeEndpoint method.
[Handler][MapGet("/users")][Authorize(Policies.UserManagement)]publicstaticpartialclassGetUsersQuery{internalstaticvoidCustomizeGetFeaturesEndpoint(RouteHandlerBuilderendpoint)=>endpoint.Produces<IEnumerable<User>>(StatusCodes.Status200OK).ProducesValidationProblem().ProducesProblem(StatusCodes.Status500InternalServerError).WithTags(nameof(User));publicrecordQuery;privatestaticValueTask<IEnumerable<User>>HandleAsync(Query_,UsersServiceusersService,CancellationTokentoken){returnusersService.GetUsers();}}In some cases, you may wish to transform the result of the handler into a different type; for example, you may wish to return a Results<> type which will work with asp.net core to return various status codes.
You can transform the result of your handler into a different type by adding a TransformResult method, like so:
[Handler][MapGet("/users")][Authorize(Policies.UserManagement)]publicstaticpartialclassGetUsersQuery{internalstaticResults<Ok<IEnumerable<User>>,NotFound>TransformResult(IEnumerable<User>result){returnTypedResults.Ok(result);}publicrecordQuery;privatestaticValueTask<IEnumerable<User>>HandleAsync(Query_,UsersServiceusersService,CancellationTokentoken){returnusersService.GetUsers();}}You can register your endpoints within a routee group by adding the MapGroup attribute to your handler. Additional
customization of the group can be done in the CustomizeGroup method.
[RouteGroup("api/users")]publicsealedpartialclassRoot{privatestaticvoidCustomizeGroup(RouteGroupBuildergroup){// additional configuration of `group`}}[Handler][MapGet("/")][MapGroup<Root>]publicstaticpartialclassGetUsersQuery{internalstaticResults<Ok<IEnumerable<User>>,NotFound>TransformResult(IEnumerable<User>result){returnTypedResults.Ok(result);}publicrecordQuery;privatestaticValueTask<IEnumerable<User>>HandleAsync(Query_,UsersServiceusersService,CancellationTokentoken){returnusersService.GetUsers();}}Then, register and customize the route group builder in your Program.cs like so:
app.MapApplicationUserManagementEndpoints("/users").RequireAuthorization(Policies.UserManagement);Endpoints decorated with this attribute will no longer be mapped by the MapApplicationEndpoints() method.
Assigns string tags to the registration. When MapXxxEndpoints is called with tag arguments, only registrations that share at
least one tag (or registrations with no tags) are included. Tags can be provided on [MapXxx()] attribute or on the [RouteGroup]
attribute.
[Handler][MapGet("/",Tags=["Users"])][RouteGroup("UserManagement")]publicstaticpartialclassGetUsersQuery{internalstaticResults<Ok<IEnumerable<User>>,NotFound>TransformResult(IEnumerable<User>result){returnTypedResults.Ok(result);}publicrecordQuery;privatestaticValueTask<IEnumerable<User>>HandleAsync(Query_,UsersServiceusersService,CancellationTokentoken){returnusersService.GetUsers();}}