Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Router should allow handling HEAD requests #269

Open
rmunn opened this issue Aug 21, 2020 · 2 comments
Open

Router should allow handling HEAD requests #269

rmunn opened this issue Aug 21, 2020 · 2 comments

Comments

@rmunn
Copy link
Contributor

rmunn commented Aug 21, 2020

Currently the router { } CE has no way to allow a HEAD request to be handled. A HEAD request is supposed to return the headers, but not the body, that would have been produced by a GET request. I suggest adding two (well, four) more CE custom operations to the router { } CE:

  • get_head and get_headf: uses the Giraffe GET_HEAD handler to automatically handle either a GET or HEAD request. According to HTTP HEAD considerations giraffe-fsharp/Giraffe#314, ASP.NET Core already handles the "if it's a HEAD request, do not return a body in the HTTP response" part of the logic, so the extra code in the router for this would be minimal.
  • head and headf: useful for applications that can cheaply produce the HTTP headers for a resource, but would require expensive work to produce the response body for that resource. This would allow them to skip the expensive work if the client is not actually asking for the response body.

The alternative is to do something kind of ugly like the following:

let head (handler : string -> HttpHandler) (next : HttpFunc) (ctx : HttpContext) =
    if HttpMethods.IsHead ctx.Request.Method then
        routef "/%s" handler next ctx
    else
        next ctx

let itemRouter = router {
    pipe_through (head ItemController.itemExists)
    get     "/" ItemController.getAllItems
    post    "/" ItemController.createItem
    getf    "/%s" ItemController.getSingleItem
    patchf  "/%s" ItemController.patchItem
    deletef "/%s" ItemController.archiveItem
}

let appRoot = router {
    forward "/api/items" (itemRouter true)
    // ...
}

(ItemController implementations omitted for brevity and because frankly, they're pretty obvious). Instead of pipe_through (head ItemController.itemExists), I'd like to be able to do headf "/%s" Controller.itemExists in my itemRouter, or else get_headf "/%s" ItemController.getSingleItem if the cost of building the response body for a single item isn't too great.

P.S. Although I've chosen not to use the Saturn controller CE in my application, it would be nice for the controller CE to also grow an exists operation to handle HEAD requests, and to have its show operation default to handling either GET or HEAD requests.

@Krzysztof-Cieslak
Copy link
Member

Yes, this definitely makes sense, we should add it.

@rmunn
Copy link
Contributor Author

rmunn commented Sep 3, 2020

PR #273 is an initial implementation. I would welcome feedback on it; see the PR description for the specific items I want to discuss.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants