Skip to content

Repository files navigation

Immediate.Apis

NuGetGitHub releaseGitHub licenseGitHub issuesGitHub issues-closedGitHub ActionsCoverage Status

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.

Examples

Installing Immediate.Apis

dotnet add package Immediate.Apis

Using Immediate.Apis

Creating an Endpoint

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();}}

Registering the endpoints

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 be app.MapWebEndpoints()
  • For a project named Application.Web, it will be app.MapApplicationWebEndpoints()

However, this name can be overridden using [assembly: ImmediateAssemblyIdentifier("SomeIdentifier")].

Customizing the endpoints

AsParameters

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){// ...}

Authorization

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 Endpoint Registration

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();}}

Transforming the handler result into a different type

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();}}

Group endpoints into a common route group

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.

Tags

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();}}

About

Source Generated registrations connecting Immediate.Handlers and minimal APIs

Topics

Resources

Stars

41 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages