MitMediator.AutoApi
9.0.0-alfa-7
dotnet add package MitMediator.AutoApi --version 9.0.0-alfa-7
NuGet\Install-Package MitMediator.AutoApi -Version 9.0.0-alfa-7
<PackageReference Include="MitMediator.AutoApi" Version="9.0.0-alfa-7" />
<PackageVersion Include="MitMediator.AutoApi" Version="9.0.0-alfa-7" />
<PackageReference Include="MitMediator.AutoApi" />
paket add MitMediator.AutoApi --version 9.0.0-alfa-7
#r "nuget: MitMediator.AutoApi, 9.0.0-alfa-7"
#:package MitMediator.AutoApi@9.0.0-alfa-7
#addin nuget:?package=MitMediator.AutoApi&version=9.0.0-alfa-7&prerelease
#tool nuget:?package=MitMediator.AutoApi&version=9.0.0-alfa-7&prerelease
MitMediator.AutoApi
Minimal API registration and http client for MitMediator
- π Installation
- βοΈ How It Works
- π§ͺ Examples
- π οΈ Change default mapping
- π₯ Upload and download files
- π’ X-Total-Count Header
- π Location header
- π― Auto client HttpMediator
- π Samples
- π License
π Installation
1. Add package
# for ASP.NET API projects
dotnet add package MitMediator.AutoApi -v 9.0.0-alfa-7
# for application layer
dotnet add package MitMediator.AutoApi.Abstractions -v 9.0.0-alfa-7
# for client application (MAUI, Blazor, UWP, etc.)
dotnet add package MitMediator.AutoApi.HttpMediator -v 9.0.0-alfa-7
2. Use extension for IEndpointRouteBuilder
var builder = WebApplication.CreateBuilder(args);
// Register handlers and IMediator.
builder.Services.AddMitMediator();
var app = builder.Build();
// Automatically maps endpoints based on IRequest
app.UseAutoApi();
app.Run();
To use base path "api" and select assemblies to scan:
app.UseAutoApi("api", new []{typeof(GetQuery).Assembly});
3. Done! All public requests have endpoints
βοΈ How It Works
- Scans all loaded assemblies for
IRequest
types - Dynamically generates and registers endpoints for each match
- Maps routes using
MapPost
,MapGet
,MapPut
, andMapDelete
, internally callingIMediator.SendAsync
π§ Transformation Logic
HTTP Method is inferred from the leading verb in the type name:
Request name start with | HTTP Method |
---|---|
get |
GET |
load |
GET |
download |
GET |
fetch |
GET |
update |
PUT |
change |
PUT |
edit |
PUT |
modify |
PUT |
put |
PUT |
post |
POST |
import |
POST |
upload |
POST |
add |
POST (201 response) |
create |
POST (201 response) |
delete |
DELETE |
remove |
DELETE |
drop |
DELETE |
Resource Name (main tag) is derived from the first noun after the verb, and pluralized:
- Book β /books
- Author β /authors
Route suffix includes any remaining parts of the type name, converted to lowercase and kebab-case:
- Count β /count
- WithAuthor β /with-author
Custom suffix will be added as is
Suffixes Command
, Query
, and Request
are automatically removed from the end
Version prefix (v1, v2, etc.) is prepended to the route as part of the base path
Default version is
v1
π§ͺ Examples
Request name | Endpoint |
---|---|
GetBookCountQuery | GET /v1/books/count |
CreateBookCommand | POST /v1/book |
RemoveBookWithAuthorCommand | DELETE /v1/books/with-author |
UpdateAuthorBioRequest | PUT /v1/authors/bio |
GET
endpoint with query params
// Api URL: GET /v1/books?limit=1&offset=1&freeText=clara
public struct GetBooksQuery : IRequest<Book[]>
{
public int? Limit { get; init; }
public int? Offset { get; init; }
public string? FreeText { get; init; }
}
POST
endpoint with 201 response
// Api URL: POST /v1/books
public class CreateBookCommand : IRequest<Book>
{
public string Title { get; init; }
public int AuthorId { get; init; }
public string GenreName { get; init; }
}
If you need to use rout parameter, implement one of interfaces IKeyRequest<TKey>
, IKeyRequest<TKey1,TKey2>
, etc. (max 7 keys)
GET
endpoint with suffix and key in url
// URL: GET /v1/books/123/cover
public struct GetBookCoverQuery : IRequest<Book>, IKeyRequest<int>
{
internal int BookId { get; private set; }
public void SetKey(int key)
{
BookId = key;
}
public int GetKey() => BookId;
}
π οΈ Change default mapping
Use attributes for the request type to change default mapping
Supported attributes:
Attribute | Template | Result for GetBookRequest |
---|---|---|
TagAttribute |
[Tag("CustomTag")] |
GET v1/custom-tag |
VersionAttribute |
[Version("v2")] |
GET v2/books |
SuffixAttribute |
[Suffix("cover")] |
GET v1/books/cover |
PatternAttribute |
[Pattern("api/v3/books/{key1}/page/{key2}")] |
GET api/v3/books/{key1}/page/{key2} |
MethodAttribute |
[Method(MethodType.Post)] |
POST v1/books |
DescriptionAttribute |
[Description("My custom description")] |
See description (in xml doc or swagger) |
DisableAntiforgeryAttribute |
[DisableAntiforgery] |
Antiforgery protection has been disabled for the endpoint |
ResponseContentTypeAttribute |
[ResponseContentType("image/png")] |
Result will have selected content type |
IgnoreRequestAttribute |
[IgnoreRequest] |
Request will be ignored π« |
When [PatternAttribute]
is applied, it overrides the entire route. The base route, version attribute, and tag attribute will be ignored
Examples
GET
endpoint with custom tag and custom suffix
// URL: GET /v1/my-books/favorite?limit=1&offset=1&freeText=clara
[Tag("MyBooks")]
[Suffix("favorite")]
public struct GetBooksQuery : IRequest<Book[]>
{
public int? Limit { get; init; }
public int? Offset { get; init; }
public string? FreeText { get; init; }
}
GET
endpoint with version, custom tag, URL pattern and specified HTTP method
// Custom URL pattern overrides base route
// URL: DELETE /with-keys/{key1}/field/{key2}
[Tag("books")]
[Pattern("with-keys/{key1}/field/{key2}")]
[Version("v3")]
[Method(MethodType.Delete)]
public class DoSomeWithBookAndDeleteCommand : IRequest<Book[]>, IKeyRequest<int, Guid>
{
internal int BookId { get; private set; }
internal Guid GuidId { get; private set; }
public void SetKey1(int key)
{
BookId = key;
}
public int GetKey1() => BookId;
public void SetKey2(Guid key)
{
GuidId = key;
}
public Guid GetKey2() => GuidId;
}
GET
endpoint png file ("image/png")
// Api URL: GET /v1/books/123/Ρover
[ResponseContentType("image/png")]
public class GetBookCoverQuery: IRequest<byte[]>, IKeyRequest<int>
{
internal int BookId { get; private set; }
public void SetKey(int key)
{
BookId = key;
}
public int GetKey() => BookId;
}
π₯ Upload and download files
For requests implementing IRequest<byte[]>
/IRequest<Stream>
, or IRequest<FileResponse>
/
IRequest<FileStreamResponse>
, the response will use "application/octet-stream"
by default. To specify a download
file name, use the FileResponse
or FileStreamResponse
response.
Use [ResponseContentType("image/png")]
attribute for custom content type
When a request implements IFileRequest
or inherits from FileRequest
, it will be bound using [FromForm]
.
File parameters fron IFileRequest
will be automatically inferred via IFromFile
. Apply [DisableAntiforgery]
to skip
CSRF protection for file upload endpoints or non-browser clients
Examples
GET
endpoint text file ("application/octet-stream")
// Api URL: GET /v1/books/123/text
[DisableAntiforgery]
public class GetBookTextQuery: IRequest<byte[]>, IKeyRequest<int>
{
internal int BookId { get; private set; }
public void SetKey(int key)
{
BookId = key;
}
public int GetKey() => BookId;
}
POST
upload and download file with file name
// Api URL: POST /v1/documents/word
public class ImportDocumentWordCommand : FileRequest, IRequest<FileResponse>
{
}
π’ X-Total-Count Header
To include the X-Total-Count
header in the HTTP response, implement the ITotalCount
interface in your response type.
This is useful for paginated endpoints or any scenario where the client needs to know the total number of items
available.
public class GetBooksResponse : ITotalCount
{
public Book[] Items { get; init; }
private int _totalCount;
public int GetTotalCount() => _totalCount;
public void SetTotalCount(int totalCount)
{
_totalCount = totalCount;
}
}
When this interface is implemented, MitMediator.AutoApi will automatically include the X-Total-Count
header in the
response, reflecting the value returned by GetTotalCount()
π Location header
To insert the correct ID into the Location header of a 201 Created response, implement the IResourceKey
interface in
your response type:
// Api URL: POST /books
public class CreateBookCommand : IRequest<CreatedBookResponse>
{
public string Title { get; init; }
}
// Location Header: /books/{BookId}
public class CreatedBookResponse : IResourceKey
{
public int BookId { get; private set; }
public string Title { get; private set; }
public string GetResourceKey() => BookId.ToString();
}
If you do not implement the IResourceKey
interface, the Location header will default to the format /books/{key}
,
where {key}
is a placeholder string
π― Auto client HttpMediator
You can reuse your IRequest
types to seamlessly send HTTP requests to a server-side API using HttpMediator
HttpMediator
supports IClientPipelineBehavior<TRequest, TResponse>
for middleware-like extensibility, and
IHttpHeaderInjector<TRequest, TResponse>
for injecting custom headers per request
π§ Sample usage:
var mediator = new HttpMediator(serviceProvider, baseUrl: "https://api.example.com");
var response = await mediator.SendAsync<MyRequest, MyResponse>(new MyRequest(), cancellationToken);
π§ More
var baseApiUrl = "api";
var httpClientName = "baseHttpClient";
var serviceCollection = new ServiceCollection();
serviceCollection.AddHttpClient(httpClientName, client => { client.BaseAddress = new Uri("https://localhost:7127/"); });
serviceCollection.AddScoped(typeof(IHttpHeaderInjector<,>), typeof(AuthorizationHeaderInjection<,>));
serviceCollection.AddScoped<IClientMediator, HttpMediator>(c => new HttpMediator(c, baseApiUrl, httpClientName));
var provider = serviceCollection.BuildServiceProvider();
var httpMediator = provider.GetRequiredService<IClientMediator>();
var query = new GetBookQuery();
query.SetKey(12);
var data = await httpMediator.SendAsync<GetBookQuery, Book>(query, CancellationToken.None);
public class AuthorizationHeaderInjection<TRequest, TResponse> : IHttpHeaderInjector<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
public ValueTask<(string, string)?> GetHeadersAsync(CancellationToken cancellationToken)
{
var result = ("Authorization", "Bearer token");
return ValueTask.FromResult<(string, string)?>(result);
}
}
π See samples
π MIT License
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- Microsoft.AspNetCore.OpenApi (>= 9.0.0)
- MitMediator.AutoApi.Abstractions (>= 9.0.0-alfa-7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
9.0.0-alfa-7 | 88 | 9/4/2025 |
9.0.0-alfa-7
Fix multi keys requests