1. Configuration Settings

Configuration Settings

Customizing Functionality

There are several areas you can customize/override the default functionality of the library. All configuration settings must be specified during app startup with the UseFastEndpoints() call.

Specify JSON Serializer Options

The settings for the default json serializer which is System.Text.Json can be set like so:

app.UseFastEndpoints(x =>
{
    x.SerializerOptions = options =>
    {
        options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; // set null for pascal case
    };
});

Global Route Prefix

You can have a specified string automatically prepended to all route names in your app instead of repeating it in each and every route config method by specifying the prefix at app startup.

Program.cs
app.UseFastEndpoints(c =>
{
    c.RoutingOptions = o => o.Prefix = "api";
});

For example, the following route config methods would result in the below endpoint routes:

Get("client/update"); -> "/api/client/update"
Put("inventory/delete"); -> "/api/inventory/delete"
Post("sales/recent-list"); -> "/api/sales/recent-list"

If needed, you can override or disable the global prefix from within individual endpoints like so:

public override void Configure()
{
    Post("user/create");
    RoutePrefixOverride("mobile");
}

In order to disable the global prefix, simply pass in a string.Empty to the RoutePrefixOverride() method.

Filtering Endpoint Registration

If you'd like to prevent some of the endpoints in your project to be not auto registered during startup, you have the option to supply a filtering function which will be run against each discovered endpoint.

If your function returns true, that particular endpoint will be registered. If the function returns false that endpoint will be ignored and not registered.

app.UseFastEndpoints(c =>
{
    c.EndpointRegistrationFilter = ep =>
    {
        if (ep.Verbs.Contains("GET") && ep.Routes.Contains("/api/mobile/test"))
        {
            return false; // don't register this endpoint
        }
        return true;
    };
});

It is also possible to set a Tag for an endpoint and use that tag to filter out endpoints according to tags during registration as shown below:

public override void Configure()
{
    Get("client/update");
    Tags("Deprecated", "ToBeDeleted"); // has no relationship with Swagger tags
}

app.UseFastEndpoints(c =>
{
    c.EndpointRegistrationFilter = ep =>
    {
        if (ep.Tags.Contains("Deprecated") is true)
        {
            return false; // don't register this endpoint
        }
        return true;
    };
});

Global Endpoint Options

You can have a set of common options applied to each endpoint by specifying an action for the GlobalEndpointOptions property of the configuration.

The action you set here will be executed for each endpoint during startup. you can inspect the EndpointDefinition argument to check what the current endpoint is, if needed.

Options to be applied to endpoints are performed on the RouteHandlerBuilder argument. The action you specify here is executed before Options() and Description() of each individual endpoint during registration.

Whatever you do here may get overridden or compounded by what you do in the Configure() method of each endpoint.

app.UseFastEndpoints(c =>
{
    c.GlobalEndpointOptions = (endpoint, builder) =>
    {
        if (endpoint.Routes[0].StartsWith("/api/admin") is true)
        {
            builder
              .RequireHost("admin.domain.com")
              .Produces<ErrorResponse>(400, "application/problem+json");
        }
    };
});

Customizing Error Responses

If the default error response is not to your liking, you can specify a function to produce the exact error response you need. Whatever object you return from that function will be serialized to json and sent to the client whenever there needs to be an error response sent downstream. The function will be supplied a collection of validation failures as well as an http status code you can use to construct your own error response object like so:

app.UseFastEndpoints(c =>
{
    c.ErrorResponseBuilder = (failures, status) =>
    {
        var list = new List<KeyValuePair<string, string>>();

        foreach (var err in failures)
        {
            list.Add(new(err.PropertyName, err.ErrorMessage));
        }

        return list;
    };
    c.ErrorResponseStatusCode = StatusCodes.Status422UnprocessableEntity;
});

Custom De-Serialization Of JSON

If you'd like to take control of how request bodies are deserialized, simply provide a function like the following. The function is supplied with the incoming HTTP request object, the type of the DTO to be created, JSON Serializer context, and a Cancellation Token.

Deserialize the object how ever you want and return it from the function. Do note that this function will be used to deserialize all incoming requests with a JSON body where applicable.

Input parameters:

HttpRequest: the http request object
Type: the type of the request dto
JsonSerializerContext?: nullable json serializer context
CancellationToken: a cancellation token
config.RequestDeserializer = async (req, tDto, jCtx, ct) =>
{
    using var reader = new StreamReader(req.Body);
    return Newtonsoft.Json.JsonConvert.DeserializeObject(await reader.ReadToEndAsync(), tDto);
};

Custom Response DTO Serialization

The response serialization process can be overridden by specifying a function that returns a Task object. You should set the content-type on the HTTP response object and write directly to the response body stream. Do note that this function will be used to serialize all outgoing responses where a JSON body is required. It is currently not possible to specify a serialization function per endpoint.

The parameters supplied to the function are as follows:

HttpResponse: the http response object
object: the response dto to be serialized
string: the response content-type
JsonserializerContext?: nullable json serializer context
CancellationToken: a cancellation token
config.ResponseSerializer = (rsp, dto, cType, jCtx, ct) =>
{
    rsp.ContentType = cType;
    return rsp.WriteAsync(Newtonsoft.Json.JsonConvert.SerializeObject(dto), ct);
};

Source Generator Based Startup

Reflection based assembly scanning is used by default to discover endpoints, validators, summaries and event handlers.

If your application has many hundreds of these types and it's running in a serverless environment, you may be able to get about a 20% startup speed boost by utilizing our experimental source generator.

To enable the source generator, simply install the FastEndpoints.Generator package from Nuget.

Installation

terminal
dotnet add package FastEndpoints.Generator

Usage

Program.cs
builder.Services.AddFastEndpoints(o =>
{
    o.SourceGeneratorDiscoveredTypes = DiscoveredTypes.All;
});

If source generation is not working, make sure you have .NET Compiler Platform SDK installed in your environment. see here for more info.


© FastEndpoints 2022