1. Get Started

Get Started

Follow the steps below to create your first endpoint that will handle an HTTP POST request and send a response back to the client.

Create Project & Install Package

terminal
  dotnet new web -n MyWebApp
  cd MyWebApp
  dotnet add package FastEndpoints

Prepare Startup

Replace the contents of Program.cs file with the following:

Program.cs
global using FastEndpoints;

var builder = WebApplication.CreateBuilder();
builder.Services.AddFastEndpoints();

var app = builder.Build();
app.UseAuthorization();
app.UseFastEndpoints();
app.Run();

Add A Request DTO

Create a file called MyRequest.cs and add the following:

MyRequest.cs
public class MyRequest
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

Add A Response DTO

Create a file called MyResponse.cs and add the following:

MyResponse.cs
public class MyResponse
{
    public string FullName { get; set; }
    public bool IsOver18 { get; set; }
}

Add An Endpoint Class

Create a file called MyEndpoint.cs and add the following:

MyEndpoint.cs
public class MyEndpoint : Endpoint<MyRequest>
{
    public override void Configure()
    {
        Post("/api/user/create");
        AllowAnonymous();
    }

    public override async Task HandleAsync(MyRequest req, CancellationToken ct)
    {
        var response = new MyResponse()
        {
            FullName = req.FirstName + " " + req.LastName,
            IsOver18 = req.Age > 18
        };

        await SendAsync(response);
    }
}

Now run your app and send a POST request to the /api/user/create endpoint using a REST client such as Postman or Insomnia with the following request body:

json
{
	"FirstName": "marlon",
	"LastName": "brando",
	"Age": 40
}

You should then get a response back such as this:

{
	"FullName": "marlon brando",
	"IsOver18": true
}

That's all there's to it.

You simply configure how the endpoint should be listening to incoming requests from clients in the Configure() section calling methods such as Get(), Post(), AllowAnonymous(), etc. Then you override the HandleAsync() method in order to specify your handling logic.

In this example, the request DTO is automatically populated from the JSON body of your HTTP request and passed in to the handler. After processing, the SendAsync() method is called with a new response DTO to be sent to the requesting client.

Endpoint Types

There are 4 different endpoint base types you can inherit from.

  1. Endpoint<TRequest> - Use this type if there's only a request DTO. You can however send any object to the client that can be serialized as a response with this generic overload.

  2. Endpoint<TRequest,TResponse> - Use this type if you have both request and response DTOs. The benefit of this generic overload is that you get strongly-typed access to properties of the DTO when doing integration testing and validations.

  3. EndpointWithoutRequest - Use this type if there's no request nor response DTO. You can send any serializable object as a response here also.

  4. EndpointWithoutRequest<TResponse> - Use this type if there's no request DTO but there is a response DTO.

It is also possible to define endpoints with EmptyRequest and EmptyResponse if needed like so:

public class MyEndpoint : Endpoint<EmptyRequest,EmptyResponse> { }

Sending Responses

There are multiple response sending methods you can use. It is also possible to simply populate the Response property of the endpoint and get a 200 OK response with the value of the Response property serialized in the body automatically. for ex:

Response DTO:

public class MyResponse
{
    public string FullName { get; set; }
    public int Age { get; set; }
}

Endpoint:

public class MyEndpoint : EndpointWithoutRequest<MyResponse>
{
    public override void Configure()
    {
        Get("/api/person");
        AllowAnonymous();
    }

    public override async Task HandleAsync(CancellationToken ct)
    {
        var person = await dbContext.GetFirstPersonAsync();

        Response.FullName = person.FullName;
        Response.Age = person.Age;
    }
}

Assigning a new instance to the Response property also has the same effect:

public override Task HandleAsync(CancellationToken ct)
{
    Response = new()
    {
        FullName = "john doe",
        Age = 124
    };
    return Task.CompletedTask;
}

Configuring Using Attributes

Instead of overriding the Configure() method, endpoint classes can be annotated with the following attributes:

  • [Http{VERB}]
  • [AllowAnonymous]
  • [Authorize]

Advanced usage however does require overriding Configure().

WARNING

You can only use one of these strategies. An exception will be thrown if you use both or none at all.

[HttpPost("/my-endpoint")]
[Authorize(Roles = "Admin,Manager")]
public class UpdateAddress : Endpoint<MyRequest, MyResponse>
{
    public override async Task HandleAsync(MyRequest req, CancellationToken ct)
    {
        await SendAsync(new MyResponse { });
    }
}

Cancellation Token

The HandleAsync method of the endpoint is supplied a CancellationToken which you can pass down to your own async methods within the handler that requires a token.

The Send*Async methods of the endpoint also optionally accepts a CancellationToken. i.e. you can either pass down the same token supplied to the HandleAsync method or you may create/use a different token with these response sending methods depending on your requirement.

However, do note that it is not required to supply a CancellationToken to the Send*Async methods, and there's no real need to dirty up your code like the following:

  await SendAsync(response, cancellation: ct);

Because if you do not supply the token to the Send*Async methods, the library automatically supplies the same token that is supplied to the HandleAsync method internally, and your code can remain cleaner.

The analyzer hint/warning can be turned off by adding the following to your csproj file:

  <NoWarn>CA2016</NoWarn>

© FastEndpoints 2022