Move the user contacts domain to Immediate.Handlers - #831
Open
Jack-Edwards wants to merge 6 commits into
Open
Conversation
Introduces Immediate.Handlers alongside MediatR and converts the first domain to it, replacing UserContactController with minimal API endpoints generated by Immediate.Apis. MediatR stays wired up for every domain that has not moved yet. Immediate has no publish/notification concept and no pipeline behaviors are in use here, so the conversion is mechanical: each request/handler pair becomes a [Handler] container class with a nested Command or Query record. Crypter.API needs its own Immediate.Handlers reference even though Crypter.Core already has one. Source generators do not flow across a project reference, and Immediate.Apis excludes the analyzer from its own dependency, so without it the API assembly gets no generated handlers. Minimal API handlers have no equivalent of ControllerBase.User, so authenticated endpoints resolve the caller through IHttpContextAccessor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Minimal API binding rejects a missing query parameter before the handler runs, returning a bare 400 with no body, where the MVC controller used to produce an ErrorResponse via InvalidModelStateResponseFactory. Rather than reinstate that at the endpoint, the handlers now validate the username themselves with Username.TryFrom, so a non-HTTP caller gets the same checking. RemoveUserContactCommand had no error channel and returned Unit, so it gains Either<RemoveUserContactError, Unit>. That changes the client signature of RemoveUserContactAsync from Maybe<Unit>, and adds DeleteEitherUnitResponseAsync to the HTTP clients, which had no Either returning delete. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Minimal API handlers have no ControllerBase.User, so every authenticated endpoint repeats the same walk from IHttpContextAccessor to the claims principal. Roughly forty endpoints are still to be migrated, so this puts the walk in one place before the pattern spreads. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The controller carried these descriptions as XML doc comments, which never reached Swagger because the project does not generate a documentation file. WithSummary puts them in the generated document instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The existing tests only checked that a failure was a Left, so a scrambled error-to-status mapping would still have passed. They now assert the error value, and cover the usernames the handlers reject. The absent-parameter case needs a raw HttpClient, since the typed client interpolates the username into the query string and so can only ever send an empty value, never omit it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Moving user contacts to DeleteEitherUnitResponseAsync left this method with no callers anywhere in the solution. The unauthenticated implementation also built its request with HttpMethod.Post, so it would not have deleted anything had it been called. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds Immediate.Handlers and Immediate.Apis alongside MediatR, and converts the user contacts domain to them.
UserContactControlleris replaced by three minimal API endpoint classes underCrypter.API/Endpoints/UserContacts. MediatR remains wired up for every domain that has not moved yet, so this merges on its own.The plan is to continue one domain per pull request until nothing is left on MediatR, then remove it and the MVC scaffolding in a final pass.
Notes for review:
api/user/contact, GET/POST/DELETE).Crypter.APItakes its ownImmediate.Handlersreference despiteCrypter.Corealready having one. Source generators do not flow across a project reference, andImmediate.Apisexcludes the analyzer from its dependency.ControllerBase.User, so authenticated endpoints now resolve the caller viaIHttpContextAccessor.AddHttpContextAccessor()is registered inProgram.cs.[Handler]container classes with a nestedCommand/Queryrecord, keeping the existingCommand/Queryfile and type names.Breaking changes to
Crypter.Common.Client:IUserContactRequests.RemoveUserContactAsyncreturnsEither<RemoveUserContactError, Unit>instead ofMaybe<Unit>.RemoveUserContactErroris new.ICrypterHttpClientgainsDeleteEitherUnitResponseAsyncand losesDeleteUnitResponseAsync, which had no remaining callers once user contacts moved over.Behavior changes:
Username.TryFrombefore querying.DELETE api/user/contactwith a malformed username now returns 400InvalidUserwhere it previously returned 200, andPOSTreturns 400InvalidUserwhere it previously returned 404NotFound.RemoveUserContact_Testsis updated for the signature change above.🤖 Generated with Claude Code