How to fully leverage Wolverine with its HTTP package
My previous blog post Wolverine is for the developers was an introduction to the Wolverine package, which is created by Jeremy D. Miller. In the blog post, we only discovered the surface, but with this post, we'll delve a bit deeper to fully experience Wolverine.
To keep things as simple as possible I like to use vertical slices because it helps to remove unnecessary abstractions and layers. The examples that are used in the previous blog post show the what and the how of Wolverine, but there's some ceremony involved to orchestrate the flow.
In this post, we'll see how to use Wolverine to Treat a controller as the application layer. As you will see in the examples this simplifies your codebase, resulting in a Minimal Architecture.
To refresh our minds, the following example was used in the previously.
Within this code, we notice two things:
- There's the
/carts
POST endpoint that invokes the "Wolverine Bus" and sends it a command - There's a
CartHandler
class that handles the incoming command
I specifically want to highlight the first point. While this doesn't seem like a big thing, it adds a little noise. Using the WolverineFx.HTTP NuGet package, we can further reduce some moving parts. Not only does this result in a better experience in dealing with HTTP requests, it's also an improvement to the performance (although this might be negligible).
In the next sections, we'll cover the possibilities.
Bus invocations using app.MapVERBToWolverine
link
Using a minimal API the above code can be refactored using the MapPostToWolverine
method (or the MapPutToWolverine
or MapDeleteToWolverine
methods).
This will do the exact same thing, but shorter.
The bus is invoked using the request body of the request. This will use the generic type to parse the body into an object.
More information can be found in the HTTP Services Documentation.
Endpoints link
Endpoints use the Request EndPoint Response (REPR) approach
Using the Wolverine attributes ([WolverineVerb]
), which are equivalent to the ASP.NET attributes ([HTTPVerb]
), an endpoint turns into a handler and vice versa.
For example, a POST endpoint using HttpPost
turns into WolverinePost
.
Just as handlers, endpoints have the additional benefit that some orchestration code can be extracted into a Before
(or Load
) method.
In the example below we use the Before
to orchestrate the next flow:
- when a cart already exists, Wolverine short-circuits the request and a
BadRequest
, theCreate
method is not invoked in this case; - when the cart doesn't exist, the
Create
method is invoked because theBefore
method returns aWolverineContinue
instance;
Although this isn't a perfect example, using the Before
helper method keeps the handler's logic of handling the request to the point and easy to test.
In other words, it turns the handler into a pure function (in most of the cases).
A better example is that Before
returns the associated entity to the handler.
Because the handler receives the entity (instead of having to fetch it), which is fetched in Before
and passed along, this results in a simpler test. Within the test case, a mock implementation of the database is probably unneeded with this approach.
Because the handler doesn't require a fetched entity, the above implementation can be refactored using the Problem Details specification.
Instead of using WolverineContinue.Result()
to continue the request, we have to use WolverineContinue.NoProblems
here.
The last change to make the enpoint cleaner, as Jeremy pointed out in the comments, is to use the EmptyResponse
attribute.
The presence of this attribute on top of the endpoint results in an empty response with the 204 status code.
The returned values are ignored in the response body, but are still published to the bus to be processed.
Within our example, we don't have to manually return an IResult
anymore, which simplifies the signature and further removes some noise.
More info can be found in the Endpoint Documentation.
HTTP Messaging using MapWolverineEndpoints
link
The last option is to use MapWolverineEndpoints
.
MapWolverineEndpoints
can be used to configure the Wolverine HTTP pipeline, which we won't go into in this post.
Within the callback, endpoints can be configured to send or publish incoming requests. Just as with the MapVERBToWolverine approach, these methods expect a generic type to parse the body before it's sent/published to the bus. These are just fire-and-forget endpoints that don't return a response, but an acknowledgment that the request is received (202 Accepted).
More info can be found in the HTTP Messaging Documentation.
Conclusion link
In this blog post, we covered some basic functionality of the WolverineFx.HTTP
package.
Using this package results in a simpler architecture by removing the need to manually communicate with the bus.
An indirect result, which isn't brought up, is that the Wolverine HTTP package helps to keep results (using ProblemDetails) and result codes consistent across the whole API.
The handler keeps the same benefits that were discussed in Wolverine is for the developers.
Outgoing links
Feel free to update this blog post on GitHub, thanks in advance!
Join My Newsletter (WIP)
Join my weekly newsletter to receive my latest blog posts and bits, directly in your inbox.
Support me
I appreciate it if you would support me if have you enjoyed this post and found it useful, thank you in advance.