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

How to return HTTP 201 (created) after a POST? #32

Closed
slegrand45 opened this issue Nov 1, 2015 · 4 comments
Closed

How to return HTTP 201 (created) after a POST? #32

slegrand45 opened this issue Nov 1, 2015 · 4 comments

Comments

@slegrand45
Copy link
Contributor

Hello,

It seems that the only path which can return a 201 is from P11 state. And in https://raw.githubusercontent.com/wiki/webmachine/webmachine/images/http-headers-status-v3.png we can see that there is a new resource check from this state. But how to implement this with webmachine? Currently, the v3p11 method only checks if a location header exists.

Thanks.

@seliopou
Copy link
Member

seliopou commented Nov 1, 2015

Hey there, the new resource check amounts to checking whether a Location response header exists, as you observed. Without a Location header, a 201 would not conform to the HTTP spec. You should set the location header in the process_post method or in a handler returned by content_types_provided when handling PUT requests.

Note that there is a subgraph of the decision diagram that was not implemented as part of the initial release that may be relevant to the use-case you're contemplating with this question. That part is related to allowing POST requests to non-existent resources. You can see some stub code for the handlers commented out here. This should be supported by the library, but wasn't part of the initial release for the sake of expediency.

@slegrand45
Copy link
Contributor Author

Thanks for your answer. So i tried to set a location header but now i get a 303 and not a 201 when i send a POST request. Without setting the location header i get a 200. Basically, my code is similar to that:

class id = object(self)
  inherit [Cohttp_lwt_body.t] Wm.resource

  method allowed_methods rd =
    Wm.continue [`GET; `POST; `PUT; `DELETE] rd

  method content_types_provided rd =
    Wm.continue [
      ("application/json", self#to_json);
    ] rd

  method content_types_accepted rd =
    Wm.continue [
      ("application/json", (Wm.continue true));
    ] rd

  method process_post rd =
    self#post rd >>= Wm.continue true

  method private post rd = 
    Cohttp_lwt_body.to_string rd.Wm.Rd.req_body >>= (
      fun v -> ... (* do stuff *)
           let h = rd.Wm.Rd.resp_headers in
           let h = Cohttp.Header.add_unless_exists h "location" "/item/id/xxx" in
           Lwt.return { rd with Wm.Rd.resp_body = `String json; resp_headers = h }
    )

  method private to_json rd =
         ...
         Wm.continue (`String json) rd

end

@seliopou
Copy link
Member

seliopou commented Nov 1, 2015

I see. This is indeed a bug. Essentially, the code cannot distinguish between the "redirect" case and the "resource created" case. The solution is to add a field to the Rd.t type indicating whether or not this is a redirect or not. The module should most likely include a redirect helper function to set the Location header and flip the bit as well.

@seliopou seliopou added the bug label Nov 1, 2015
@slegrand45
Copy link
Contributor Author

Ok, thanks. I will for now use the 200 code return. By the way, i also don't succeed to make a PUT request. I will open a new PR for that.

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

2 participants