Skip to content

Attributes reference

Every attribute Immediate.Apis defines or recognises, with its exact shape and effect.

4 min read

Immediate.Apis defines its attributes in the Immediate.Apis.Shared namespace. It also recognises a handful of attributes from ASP.NET Core and from Immediate.Handlers.

AttributeTargetEffect
[MapGet]classRegisters a GET endpoint
[MapPost]classRegisters a POST endpoint
[MapPut]classRegisters a PUT endpoint
[MapPatch]classRegisters a PATCH endpoint
[MapDelete]classRegisters a DELETE endpoint
[MapMethod]classRegisters an endpoint for an arbitrary HTTP verb
[RouteGroup]classDeclares a route group
[MapGroup<T>]classAttaches an endpoint to route group T
[Handler]classRequired; from Immediate.Handlers
[Authorize]classApplies RequireAuthorization()
[AllowAnonymous]classApplies AllowAnonymous()
[AsParameters], [FromXxx]parameter or propertyControls request binding

MapMethodAttribute

The base type of all the verb attributes, and usable directly for verbs that have no dedicated attribute.

public class MapMethodAttribute : Attribute
{
	public MapMethodAttribute(string method, [StringSyntax("Route")] params string[] routes);

	public string[] Routes { get; }
	public string Method { get; }
	public string[]? Tags { get; init; }
}
  • method — the HTTP verb, emitted verbatim into MapMethods(app, route, ["HEAD"], …).
  • routes — one or more route templates. One endpoint registration is generated per route.
  • Tags — optional registration tags; see Tagged registration.
[Handler]
[MapMethod("HEAD", "/api/health", "/health", Tags = ["Public"])]
public static partial class HeadHealth
{
	// ...
}

The verb attributes

MapGetAttribute, MapPostAttribute, MapPutAttribute, MapPatchAttribute and MapDeleteAttribute are sealed subclasses of MapMethodAttribute that supply the verb for you:

public sealed class MapGetAttribute(
	[StringSyntax("Route")] params string[] routes
) : MapMethodAttribute("GET", routes)
{
	public MapGetAttribute(string route) : this([route]) { }
}

They inherit Routes, Method and Tags. Each also has a single-string constructor, so [MapGet("/users")] works on language versions without collection expressions.

[MapGet("/users")]
[MapGet("/api/users", "/v1/users")]
[MapGet("/users", Tags = ["Public", "Admin"])]

[AttributeUsage(AttributeTargets.Class)] — endpoints are declared on the handler class, never on the Handle method. The generator reads the first Map attribute it finds, so only one per class is meaningful.

RouteGroupAttribute

[AttributeUsage(AttributeTargets.Class)]
public sealed class RouteGroupAttribute([StringSyntax("route")] string route) : Attribute
{
	public string Route { get; }
	public string[]? Tags { get; init; }
}
  • route — a single route prefix. Unlike the Map attributes, this is not a params array.
  • Tags — filters the entire group, including its endpoints and child groups.

The class must be partial; the generator adds a MapGroup method to it. A [RouteGroup] class nested inside another [RouteGroup] class becomes a child group. See Route groups.

MapGroupAttribute<T>

[AttributeUsage(AttributeTargets.Class)]
public sealed class MapGroupAttribute<T> : Attribute;

Attaches the endpoint to route group T. T must carry [RouteGroup] or IAPI0013 is reported and no endpoint is generated. Name the innermost group when groups are nested:

[Handler]
[MapGet("")]
[MapGroup<Api.V1.Users>]
public static partial class GetUsers
{
	// ...
}

An endpoint carrying [MapGroup<T>] is not registered by MapXxxEndpoints() directly — only through its group.

Recognised ASP.NET Core attributes

[Authorize] and [AllowAnonymous]

From Microsoft.AspNetCore.Authorization, applied to the handler class.

FormGenerated
[Authorize]RequireAuthorization()
[Authorize("Policy")]RequireAuthorization("Policy")
[Authorize(Policy = "Policy")]RequireAuthorization("Policy")
[AllowAnonymous]AllowAnonymous()

Any other named argument, such as Roles or AuthenticationSchemes, is IAPI0002. If both attributes are present, [AllowAnonymous] wins and IAPI0003 warns. See Authorization.

Binding attributes

[AsParameters] (from Microsoft.AspNetCore.Http) and [FromBody], [FromForm], [FromHeader], [FromQuery] and [FromRoute] (from Microsoft.AspNetCore.Mvc) are read in two positions:

  • On the request parameter of Handle/HandleAsync, where they override the inference entirely.
  • On a property of the request type, where any of the [FromXxx] five causes the request to bind as [AsParameters].

[FromServices] and [FromKeyedServices] are not part of this set — handler dependencies are resolved by Immediate.Handlers, not by the endpoint. See Binding request data.

Metadata attributes on the handle method

Any attribute on Handle/HandleAsync[ProducesResponseType<T>], [Produces], [Tags], [EndpointSummary], your own — is copied verbatim onto the generated minimal-API delegate, constructor and named arguments included. See Customizing endpoints.

Recognised methods

These are not attributes, but the generator looks for them by name and shape on your class:

MethodRequired shape
CustomizeEndpointinternal/private static void, taking RouteHandlerBuilder or IEndpointConventionBuilder
TransformResultinternal static, non-void, taking the handler’s response type — or no parameters for a bare ValueTask handler
CustomizeGroupprivate static void, taking RouteGroupBuilder

A method with the right name and the wrong shape is ignored and reported: IAPI0004, IAPI0005 and IAPI0011 respectively.