The main `Server.Internal` module was getting a bit large for my taste.
It now contains just the instances. All the administrative utilities
are in their own dedicated modules.
Instead of directly interpreting a server as a `RoutingApplication`,
this change introduces the concept of a `Router`, which is a datatype
with several constructors.
In particular, the type of the `route` function changes from
route :: Proxy layout -> Server layout -> RoutingApplication
to
route :: Proxy layout -> IO (RouteResult (Server layout)) -> Router
Most important in practice is the case of the `StaticRouter` constructor
in `Router`. For choices between statically known paths, we can now use
a lookup table to dispatch requests rather than trying each request
individually.
This brings down routing complexity of a common case from
O(n) to O(log n).
Another important change is that the handler that is passed down by
`route` is no longer of type `Server layout`, but of type
`IO (RouteResult (Server layout))`. This means that API constructs
can "delay" checks and failure. For example, `ReqBody` does not have
to fetch the request body and feed it to the handler immediately; it
can instead record these actions in the handler that is passed down.
The code will only be executed at a leaf / endpoint of the API.
This is desired behaviour: We prefer to save work by doing all matching
on static path components first. Furthermore, we get better error codes
by doing so.