Assume responsibility for body params parsing
Over in https://github.com/hanami/hanami/issues/1541, I shared how that (at the present moment) a new Hanami user would need to know to activate a body parser middleware in order to correctly process form submissions containing file uploads.
Our body parser middleware comes from Hanami Router. But everything that eventually uses those body parsed params is inside Hanami Action. These are two separate gems.
Because of this split, the only place we have to tie them together is inside the Hanami gem itself. This is why we have special behaviour in Hanami::Config to use certain body parser middleware (currently only JSON) if the user configures an app-side action format using config.actions.format :json.
I think this approach is indirect, inflexible, and ultimately reveals that our separations aren't right.
I think we should introduce body parsing functionality into actions. This way, each individual action can parse the request body based on what its own knowledge the formats it is specifically is configured to handle. We move away from indirect, global behaviour (like a single middleware) to behaviour available right on the action objects.
Actions are quite concerned with params already: they offer params validation, and make the params available in the request objects they build. So it seems fitting that actions take care of params parsing too.
Actions are also intended to be able to serve as mini Rack apps unto themselves, but the current reality is that this capability is limited due to their reliance on the router doing body parsing for them.
In this way, this would make Hanami Controller more useful as a standalone gem, while at the same time getting rid of awkwardness when it is used as part of a full Hanami app.
Built right, this would solve the issue in https://github.com/hanami/hanami/issues/1541 because an action configured to respond to :html would know to parse multipart/form-data request bodies.
As part of this change, I don't think we need to get rid of body parsers from Hanami Router. That capability can remain there for people who might want to use the router standalone, and have it provide some params parsing, but we can stop using it for full Hanami apps.
Code-wise, this would probably look something like:
- A collection of classes that registered as body parsers, mapped to format names
- A standard set available by default (covering at least JSON and multipart forms)
- Stored in an action's config, so it can be inherited, and so the user can override on a per-action basis, or for all actions by using
config.actionsin an app class - The appropriate body parser(s) for the request's format are resolved and called at the beginning of
Action#call - The parsed params are stored in the env under a well-known key
- Then
Params#_extract_paramscan look for that key to find the params