Fake Handlers
With SmithyGenerateFakes enabled, codegen emits a Fake{Service}Handler
implementing the full service handler interface. A working server without
writing a handler:
<PropertyGroup> <SmithyGenerateFakes>true</SmithyGenerateFakes></PropertyGroup>var builder = WebApplication.CreateBuilder(args);builder.Services.AddWeatherServiceHandler<FakeWeatherServiceHandler>();
var app = builder.Build();app.MapWeatherService();app.Run();Every operation responds on every protocol the service declares. Input
validation still runs in front of the fake: invalid requests are rejected
with the same ValidationException responses a real handler gets.
Projects with an explicit smithy-build.json set "generateFakes": true on
the csharp-codegen plugin instead. The fake handler is generated with the
server surface (SmithyGenerateServer, on by default); the same setting also
generates a fake client
with the client surface.
Where the responses come from
Section titled “Where the responses come from”Responses are compiled into the generated code, so they are deterministic across calls, runs, and rebuilds of an unchanged model. For each operation:
-
@examplesinput matching. When the operation carries several@examplesentries, the incoming input is matched against the example inputs in model order and the first match decides the response. Matching is a subset comparison: members present in the example input must equal the incoming input, members absent from the example match anything, at every nesting level. A matched error example throws the modeled error, which the server serializes like any handler-thrown error. -
@examplesoutput. When no example input matches (or the operation has a single example), the fake returns the output of the first non-error example. Optional members absent from the example are omitted. -
Synthesized placeholders. Without an example, strings echo the member name (
"name","nextToken"), numbers are0, enums and unions take their first variant, lists and maps contain a single entry, and timestamps are a fixed instant.@lengthand@rangeminimums are honored;@httpResponseCodemembers are200. Recursive shapes terminate by omitting the recursive optional member or emitting an empty collection.
@examples([ { title: "Get Zurich" input: { cityId: "zrh" } output: { name: "Zurich", coordinates: { latitude: 47.3769, longitude: 8.5417 } } } { title: "Get Geneva" input: { cityId: "gva" } output: { name: "Geneva", coordinates: { latitude: 46.2044, longitude: 6.1432 } } } { title: "Get unknown city" input: { cityId: "xxx" } error: { shapeId: "example.weather#NoSuchCity" content: { message: "no city with ID xxx" } } }])operation GetCity { // ...}// GET /cities/zrh: from the matched example{"name":"Zurich","coordinates":{"latitude":47.3769,"longitude":8.5417}}
// GET /cities/gva: from the matched example{"name":"Geneva","coordinates":{"latitude":46.2044,"longitude":6.1432}}
// GET /cities/xxx: the matched error example, served as a modeled error// (404, X-Amzn-Errortype: NoSuchCity){"message":"no city with ID xxx"}
// GET /cities/brn: no match, first non-error example{"name":"Zurich","coordinates":{"latitude":47.3769,"longitude":8.5417}}
// GET /cities: no example, synthesized{"nextToken":"nextToken","items":[{"cityId":"cityId","name":"name"}]}Operations without an example produce a codegen warning naming the operation.
Replacing fakes one operation at a time
Section titled “Replacing fakes one operation at a time”Per-operation registration. Add{Service}Handler registers the handler
under every per-operation interface, and the last registration wins:
builder.Services.AddWeatherServiceHandler<FakeWeatherServiceHandler>();builder.Services.AddSingleton<IGetCityHandler, GetCityHandler>();builder.Services.AddSingleton<IListCitiesHandler, ListCitiesHandler>();Subclassing. The fake’s operation methods are virtual:
internal sealed class WeatherHandler : FakeWeatherServiceHandler{ public override Task<GetCityOutput> GetCityAsync( GetCityInput input, CancellationToken cancellationToken = default ) => /* real implementation */;}
builder.Services.AddWeatherServiceHandler<WeatherHandler>();Event-stream outputs are served as a short finite stream (the example’s events, or a single synthesized event); streaming blob outputs return an in-memory stream.