A context with a library group of its own in the front end but a single large file on the server is only half cut. This lesson carries the split through to the API: a group of endpoints per context, a contract per group, a client per contract. On top of that comes the question of a layer that assembles data from several contexts (backend for frontend, BFF). K2 teaches the .NET development of the API (2.3, 2.12); the idea of the contract from W9 0203 is assumed.
State of the checks. Run in a throwaway project outside the repository: an ASP.NET Core 10 project (SDK 10.0.400,
Microsoft.AspNetCore.OpenApi10.0.15) with twoMapGroupgroups and two documents,dotnet build -m:1(exit 0, 0 warnings), starting the API andcurlof the documents;ng-openapi-gen1.1.0 for both documents in the Nx workspace from 0202 (exit 0),tsc --noEmitover both data-access libraries (first exit 2, after the fix exit 0),nx run-many -t lintover 13 projects (exit 0); a BFF route that calls the API throughHttpClientagainst itself (output below). Not run: the renamecompanytofirmafrom exercise 1, sign-in, tokens, scopes and any authorization, a BFF as a service of its own, Azure, a browser, an application against the API. Read in the text: the Learn pages "Backends for Frontends Pattern" and "Use Domain Analysis to Model Microservices" and the article on angulararchitects.io. The Learn page on OpenAPI in ASP.NET Core was not read: forAddOpenApiandWithGroupName, this states what ran for us (open: what the page promises).
One group per context
In 0201 and 0202, contacts, appointments and tenders are separate library groups. The server of the Kladde is one application (K4 4.3.6: a modular monolith), and there a context corresponds to one group of endpoints with a prefix and a name. The article on angulararchitects.io notes that front-end cuts often mirror those of the server; if the two cut differently, a BFF can translate, and the teams lose autonomy.
A cut that is the same on both sides saves this translation. This is what the contacts group looks like (Contacts/ContactsApi.cs, shortened to the essentials; the sample data are fixed):
public static IEndpointRouteBuilder MapContactsApi(this IEndpointRouteBuilder app)
{
var group = app.MapGroup("/api/contacts")
.WithGroupName("contacts")
.WithTags("contacts");
group.MapGet("/", (int page = 1, int size = 20) => /* ContactsPage */)
.WithName("ListContacts");
group.MapGet("/{id:int}", (int id) => /* ContactSummary */)
.WithName("GetContact");
return app;
}
The appointments group (Appointments/AppointmentsApi.cs) has the same structure with "/api/appointments" and the group name appointments. Each group lives in a folder of its own with types of its own: ContactSummary and ContactsPage in the one, AppointmentResponse in the other. No type is shared between the groups, just as the appointments in 0201 know no contacts. Program.cs:
builder.Services.AddOpenApi("contacts");
builder.Services.AddOpenApi("appointments");
var app = builder.Build();
app.MapOpenApi();
app.MapContactsApi();
app.MapAppointmentsApi();
AddOpenApi("contacts") creates a document with that name, MapOpenApi() serves each one under /openapi/<name>.json. That an endpoint ends up in its document is controlled in our case by WithGroupName: it ends up in the document of the same name. K2 2.3.10 introduces AddOpenApi and MapOpenApi.