Search
K
  1. Misc Conveniences

Misc Conveniences

Endpoint Options

In addition to the convenient methods you can use in the endpoint configuration to setup your endpoints (mentioned in previous pages), you can use the Options() method to customize aspects of endpoint registration/setup like so:

MyEndpoint.cs
Options(b => b.RequireCors(x => x.AllowAnyOrigin())
              .RequireHost("domain.com")
              .ProducesProblem(404));

Multiple Verbs & Routes

A single endpoint can be made to listen to more than one type of http verb and on multiple routes like below. This is sometimes useful when your endpoint handler code is almost the same with a minor variation across different routes/verbs. Instead of creating multiple endpoint classes, you can use this strategy to handle multiple use-cases with a single piece of handler logic.

MyEndpoint.cs
public override void Configure()
{
    Verbs(Http.POST, Http.PUT, Http.Patch);
    Routes("/api/user/create", "/api/user/save");
}
WARNING

The above registers 6 endpoints in the routing system even though they all use the same handler logic.

Shorthand Route Configuration

Instead of the Verbs() and Routes() combo, you can use the shorthand versions that combines them when configuring your endpoints like so:

  • Get()
  • Post()
  • Put()
  • Patch()
  • Delete()
MyEndpoint.cs
public override void Configure()
{
    Get("/api/customer/{CustomerID}");
}

The above is equivalent to using both Verbs() and Routes(). Do note that you can't configure multiple verbs with the shorthand version. You can however setup multiple route patterns with the shorthand methods.

Strongly Typed Route Parameters

In cases where the route parameters are bound to the the request DTO, it is possible to tie the parameter names to the properties of the DTO. Simply prefix the parameters in the route template with an @ sign and provide a new expression with the bound properties in the correct order as shown below:

Get("/customer/{@cid}/invoice/{@inv}", x => new { x.CustomerId, x.InvoiceId });

In the above example, the resulting route would be /customer/{CustomerId}/invoice/{InvoiceId}

Endpoint Properties

The following properties are available to all endpoint classes.

  • BaseURL (string) The base URL of the current request in the form of https://hostname:port/ (includes trailing slash). if your server is behind a proxy/gateway, use the forwarded headers middleware to get the correct address.

  • Config (IConfiguration) Gives access to current configuration of the web app

  • Env (IWebHostEnvironment) Gives access to the current web hosting environment

  • Files (IFormFileCollection) Exposes the uploaded file collection in case of multipart/form-data uploads.

  • Form (IFormCollection) Exposes the form data in case of application/x-www-form-urlencoded or multipart/form-data uploads.

  • HttpContext (HttpContext) Gives access to the current HTTP context of the request.

  • HttpMethod (Http enum value) The http method of the current request as an enum value.

  • Logger (ILogger) The default logger for the current endpoint type

  • Response (TResponse) Exposes a blank response DTO for the current endpoint before the endpoint handler is executed or represents the populated response DTO after a response has been sent to the client.

  • User (ClaimsPrincipal) The current claims principal associated with the current request.

  • ValidationFailed (bool) Indicates the current validation status

  • ValidationFailures (List<ValidationFailure>) The list of validation failures for the current execution context.

Send Methods

The following response sending methods are available for use from within endpoint handlers:

  • SendAsync() Sends a given response dto or any object that can be serialized as JSON down to the requesting client.

  • SendCreatedAtAsync() Sends a 201 created response with a Location header containing where the resource can be retrieved from. See note about using with custom endpoint names.

  • SendStringAsync() Sends a given string to the client in the response body.

  • SendOkAsync() Sends a 200 ok response without any body.

  • SendNoContentAsync() Sends a 204 no content response.

  • SendRedirectAsync() Sends a 30X moved response with a location header containing the URL to redirect to.

  • SendErrorsAsync() Sends a 400 error response with the current list of validation errors describing the validation failures.

  • SendNotFoundAsync() Sends a 404 not found response.

  • SendUnauthorizedAsync() Sends a 401 unauthorized response.

  • SendForbiddenAsync() Sends a 403 forbidden response.

  • SendBytesAsync() Sends a byte array to the client.

  • SendFileAsync() Sends a file to the client.

  • SendStreamAsync() Sends the contents of a stream to the client.

  • SendEventStreamAsync() Sends a "server-sent-events" data stream to the client.

  • SendResultAsync() Sends any IResult instance produced by the Results or TypedResults static classes in Minimal APIs.

If the provided response sending methods are not sufficient, you can easily create your own as extension methods targeting the IEndpoint interface like so:

public static class EndpointExtensions
{
    public static Task SendCode(this IEndpoint ep, int statusCode, CancellationToken ct = default)
    {
        ep.HttpContext.MarkResponseStart(); //don't forget to always do this
        ep.HttpContext.Response.StatusCode = statusCode;
        return ep.HttpContext.Response.StartAsync(ct);
    }
}

Which you'd then be able to call from your endpoint handler like so:

public override async Task HandleAsync(Request r, CancellationToken ct)
{
    await this.SendStatusCode(219);
}

Attribute Driven Response Headers

If your JSON responses have accompanying response headers, you can make them part of the response DTO itself while marking them with an attribute. When the DTO is serialized to the response stream, the decorated properties are ignored by STJ and the values of those properties are added to the response as headers.

sealed class MyResponse
{
    public int UserId { get; set; }

    [ToHeader("x-session-id")]
    public string SessionId { get; set; }
}

sealed class UserEndpoint : EndpointWithoutRequest<MyResponse>
{
    ...

    public override Task HandleAsync(CancellationToken c)
        => SendAsync(
            new()
            {
                UserId = 12345,
                SessionId = "xyzxyzxyzxyzxyzxyzxyz"
            });
}

The above results in the following Http response:

HTTP/1.1 200 OK
Content-Type: application/json
x-session-id: xyzxyzxyzxyzxyzxyzxyz

{
  "userId": 12345
}

LIMITATIONS:

  • Only works on .NET 8 and newer.
  • Only works with the built-in serializer (STJ).
  • Only works with Send*Async() methods that accept a response DTO.
  • Not compatible with IResult (Results/TypedResults) response types.

Hook Methods

The following 5 hook methods allow you to do something before and after DTO validation as well as handler execution.

  • OnBeforeValidate() override this method if you'd like to do something to the request dto before it gets validated.

  • OnAfterValidate() override this method if you'd like to do something to the request dto after it gets validated.

  • OnValidationFailed() override this method if you'd like to do something when validation fails.

  • OnBeforeHandle() override this method if you'd like to do something to the request dto before the handler is executed.

  • OnAfterHandle() override this method if you'd like to do something after the handler is executed.


© FastEndpoints 2024