expose-a-use-case
Skill0 starsChanged 10 days agoMITView on GitHub
How to put an Application use case on a Lambda function - a [LambdaFunction] method on Handler that sends the request through Mediator with a cancellation token from the remaining time, request and response records, the Mapperly mapper, the source-generated serializer context, the generated CloudFormation template and tests. Use when adding or changing a function in this Lambda template.
4 other projects use a version of this.
Adopted by
Most recently taken up by
- LeanMeanCleanApps/CleanWebApitheir own version, first seen Nov 15, 2026
- LeanMeanCleanApps/CleanGraphQLApitheir own version, first seen Nov 15, 2026
- LeanMeanCleanApps/CleanMinimalApitheir own version, first seen Nov 15, 2026
- LeanMeanCleanApps/CleanModelContextProtocoltheir own version, first seen Nov 8, 2026
Other versions4 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 4
- LeanMeanCleanApps/CleanMinimalApi★ 400same name
- LeanMeanCleanApps/CleanGraphQLApi★ 13same name
- LeanMeanCleanApps/CleanWebApi★ 4same name
- LeanMeanCleanApps/CleanModelContextProtocol★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository40 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- add-a-use-caseSkill
- api-conventionsSkill
- branches-and-pull-requestsSkill
- cancellationSkill
- ci-for-your-solutionSkill
- ci-pipelineSkill
- clean-architecture-layersSkill
- configuration-and-environmentsSkill
- coverageSkill
- csharp-house-styleSkill
- data-access-ef-coreSkill
- database-migrationsSkill
- docker-and-composeSkill
- docs-and-voiceSkill
- errors-and-exceptionsSkill
- family-syncSkill
- health-checksSkill
- integration-testsSkill
- json-serializationSkill
- lambda-emulatorSkill
- mapping-with-mapperlySkill
- mediatorSkill
- optional-token-authSkill
- packages-and-dependenciesSkill
- pagingSkill
- presentation-integration-testsSkill
- releasesSkill
- sample-dataSkill
- security-findingsSkill
- serilogSkill
- telemetrySkill
- template-authoringSkill
- test-designSkill
- time-providerSkill
- unit-testsSkill
- validationSkill
- writing-a-skillSkill
- xml-docs-and-openapiSkill
The file
We split this skill into the rules it gives an agent
8 rules. 0 are common, 0 are distinctive, and 8 are very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 22
Add the use case first (add-a-use-case).
- Very specific: line 23
Add the request as a record in src/Presentation/LambdaFunction/Models/ with init properties, defaults where the Application request has …
- Very specific: line 24
Add or reuse a response record in the same folder, with a <param> tag for each value.
- Very specific: line 25
Add the method to Handler with [LambdaFunction(ResourceName = "<Method>", PackageType = LambdaPackageType.Image, MemorySize = 256, Timeout …
- Very specific: line 26
Add every new request and response type to LambdaFunctionJsonSerializerContext with [JsonSerializable(typeof(...))] (json-serialization).
- Very specific: line 27
Document the method: <summary> with what it returns and in what order, <param> for the request and the context, and <returns>.
- Very specific: line 28
Test it through the handler in tests/Presentation.Tests.Integration/HandlerTests.cs (presentation-integration-tests).
- Very specific: line 63
Use async void, or block with .Result or .Wait().
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Expose a use case (Lambda function)
The rule
Every function is a public method on Handler (src/Presentation/LambdaFunction/LambdaFunction.cs) with a [LambdaFunction] attribute and the signature Task<TResponse> Name(TRequest request, ILambdaContext context). Lambda Annotations generates a class for each one, such as Handler_GetMovies_Generated, and that class is what Lambda calls. It builds the services from Startup once per execution environment, creates the Handler as a singleton, and writes the function into src/Presentation/serverless.template when the project builds.
The Handler constructor creates or upgrades the database once. Each method wraps its body in the private Invoke helper, which opens the function's trace span and flushes the metrics when the invocation ends, and inside it maps its request to the Application request, sends it through the private Send helper and maps the result to a presentation model. Send opens a DI scope per invocation and cancels the work when the invocation's remaining time runs out.
A list that callers also want over HTTP gets a second method in the #region HTTP API block, named with an Http prefix (HttpGetMovies). It has [HttpApi(LambdaHttpMethod.Get, "/movies")] beside [LambdaFunction], takes its inputs as [FromQuery] parameters and returns IHttpResult. It builds the same request record and calls the direct method through the Http helper, which answers 200 with the result and 400 problem details for a ValidationException. The build adds the route to the stack's API Gateway HTTP API in serverless.template.
Functions contain no logic. Validation, not-found and everything else happen in Application, and their exceptions reach the caller as Lambda function errors (api-conventions).
Steps
- Add the use case first (
add-a-use-case). - Add the request as a
recordinsrc/Presentation/LambdaFunction/Models/withinitproperties, defaults where the Application request has them, and XML docs on the type and each property. - Add or reuse a response
recordin the same folder, with a<param>tag for each value. Map Application entities to it with apartialmethod onLambdaFunctionMapper(mapping-with-mapperly). Lists returnPage<T>throughToPage. - Add the method to
Handlerwith[LambdaFunction(ResourceName = "<Method>", PackageType = LambdaPackageType.Image, MemorySize = 256, Timeout = 30)]. Wrap the body inthis.Invoke(request, context, ...), so the invocation is traced and its metrics are flushed, and send throughthis.Send(..., context). Never resolve services or create tokens yourself. - Add every new request and response type to
LambdaFunctionJsonSerializerContextwith[JsonSerializable(typeof(...))](json-serialization). - Document the method:
<summary>with what it returns and in what order,<param>for the request and the context, and<returns>. - Test it through the handler in
tests/Presentation.Tests.Integration/HandlerTests.cs(presentation-integration-tests). Cover each success and each validation or not-found failure (test-design). - For an HTTP route, add the
Http<Method>method as described above, and test it intests/Presentation.Tests.Integration/HttpApiTests.csfor the success, each400, and once through the generated class with anAPIGatewayHttpApiV2ProxyRequest. - Build, and commit the function the build adds to
src/Presentation/serverless.template. It deploys as its own Lambda function from the same image, with the handler stringPresentation::CleanLambdaFunction.Presentation.LambdaFunction.Handler_<Method>_Generated::<Method>. Mention it indocs/RUN.md.
Example
// src/Presentation/LambdaFunction/LambdaFunction.cs
[LambdaFunction(ResourceName = "GetAuthors", PackageType = LambdaPackageType.Image, MemorySize = 256, Timeout = 30)]
public async Task<Page<Author>> GetAuthors(ListRequest request, ILambdaContext context)
{
return await this.Invoke(request, context, async () =>
{
var page = await this.Send(new GetAuthorsQuery
{
Query = request.Query,
Offset = request.Offset,
Limit = request.Limit
}, context);
return ToPage(page, this.mapper.ToPresentation);
});
}Don't
- Return Application entities. Map them to the records in
Models/, so the function's contract doesn't move when Application does. - Catch exceptions or check
nullin a function. - Skip
Invoke. A function that callsSendon its own still works, but it leaves no trace and its metrics wait for the next invocation to be sent. - Build a new
ServiceProviderper invocation, or register services anywhere butStartup. The generated class builds them once, andSendscopes each call. - Take services as
[FromServices]parameters. Lambda Annotations 2.4 writes a documentation link for them that doesn't resolve, and the build fails on the warning. - Edit a function's entry in
serverless.templateby hand. The build rewrites it from the attribute. Add other resources and settings beside it. - Give an
[HttpApi]method aGuidorstring?parameter. Lambda Annotations 2.4 only binds primitive types from the query string (AWSLambda0109), and its generated code has nullable turned off (CS8669). Take astring, treat empty as missing withEmptyAsNull, and parse ids withParseId, which adds a400error for text that isn't a GUID. - Remove the
CS1574entry fromNoWarninPresentation.csproj. It's our one suppression here: the classes generated for[HttpApi]methods link their docs to our method with a parameter list they don't share, the link can't resolve, and the generated code isn't ours to fix. A nested.editorconfigdoesn't reach generated files. Don't add any other code to it. - Use
async void, or block with.Resultor.Wait(). - Forget
[JsonSerializable]for a new type. The serializer has no reflection fallback.
Check
dotnet test tests/Presentation.Tests.Integration
docker compose up -d --build # then invoke it as in lambda-emulatorDoes it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

