Minimal API routing issue

131 Views Asked by At

I'm creating a minimal Web API.

I have defined two routes:

app.MapGet("/reports/{id:Guid}", GetReportById);
app.MapPost("/reports", CreateReport);

with corresponding delegate handlers:

public static async Task<Results<Ok<ActivityReport>, NotFound, BadRequest<string>>> GetReportById(
    [AsParameters] ActivityReportingServices services,
    Guid id)
{
    if (id == Guid.Empty)
    {
        return TypedResults.BadRequest("Id is not valid.");
    }

    var activityReport = await services.Context.ActivityReports.SingleOrDefaultAsync(report => report.Id == id);

    if (activityReport == null)
    {
        return TypedResults.NotFound();
    }

    return TypedResults.Ok(activityReport);
}

and

public static async Task<CreatedAtRoute<ActivityReport>> CreateReport(
    [AsParameters] ActivityReportingServices services,
    ActivityReportForCreateDTO activityReport)
{
        
    var report = new ActivityReport() { Clients = activityReport.Clients };

    services.Context.ActivityReports.Add(report);
    await services.Context.SaveChangesAsync();

      
    return TypedResults.CreatedAtRoute(report, "/reports/{report.Id}");
}

The Id member of the ActivityReport class is a Guid.

My issue is that when the CreateReport method tries to return TypedResults.CreatedAtRoute(report, $"/reports/{report.Id}") I get a "System.InvalidOperationException: No route matches the supplied values" exception.

I have tried to change the "/reports/{id:Guid}" route to "/reports/{id}" and change the Id parameter in GetReportById to a string to try and work around this issue but to no avail.

What am I doing wrong here?

1

There are 1 best solutions below

0
On

TypedResults.CreatedAtRoute requires route name, so you need to do something like the following:

app.MapGet("/reports/{id:Guid}", GetReportById)
    .WithName("reportsById"); // add route name

static async Task<CreatedAtRoute<ActivityReport>> CreateReport( ActivityReportForCreateDTO activityReport)
{
    return TypedResults.CreatedAtRoute(report, 
        routeName: "reportsById", 
        routeValues: new {id = Guid.NewGuid()}); // use real Guid
}

Otherwise use the TypedResults.Created:

uri String
The URI at which the content has been created.

// use real Guid here:
return TypedResults.CreatedAtRoute(report, $"/reports/{Guid.NewGuid()}");