diff options
author | Martin Björklund <[email protected]> | 2020-09-11 12:35:36 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2020-11-27 16:17:43 +0100 |
commit | 8795233c57f1f472781a22ffbf186ce38cc5b049 (patch) | |
tree | 140478621afdef80d4957e17e417a2751ef7694c | |
parent | 63a6b86fbae1190ba78dceb196588fdcae50e17a (diff) | |
download | cowboy-8795233c57f1f472781a22ffbf186ce38cc5b049.tar.gz cowboy-8795233c57f1f472781a22ffbf186ce38cc5b049.tar.bz2 cowboy-8795233c57f1f472781a22ffbf186ce38cc5b049.zip |
AcceptCallback may now return created/see_other tuples for POST
They replace and deprecate the {true,URI} return value.
-rw-r--r-- | doc/src/manual/cowboy_rest.asciidoc | 17 | ||||
-rw-r--r-- | src/cowboy_rest.erl | 8 | ||||
-rw-r--r-- | test/handlers/create_resource_h.erl | 28 | ||||
-rw-r--r-- | test/rest_handler_SUITE.erl | 24 |
4 files changed, 73 insertions, 4 deletions
diff --git a/doc/src/manual/cowboy_rest.asciidoc b/doc/src/manual/cowboy_rest.asciidoc index a445948..0bb6d47 100644 --- a/doc/src/manual/cowboy_rest.asciidoc +++ b/doc/src/manual/cowboy_rest.asciidoc @@ -86,7 +86,10 @@ normal:: ---- AcceptCallback(Req, State) -> {Result, Req, State} -Result :: true | {true, URI :: iodata()} | false} +Result :: true + | {created, URI :: iodata()} + | {see_other, URI :: iodata()} + | false Default - crash ---- @@ -99,11 +102,14 @@ For PUT requests, the body is a representation of the resource that is being created or replaced. For POST requests, the body is typically application-specific -instructions on how to process the request, but it may also -be a representation of the resource. When creating a new -resource with POST at a different location, return `{true, URI}` +instructions on how to process the request, but it may also be a +representation of the resource. When creating a new resource with POST +at a different location, return `{created, URI}` or `{see_other, URI}` with `URI` the new location. +The `see_other` tuple will redirect the client to the new location +automatically. + For PATCH requests, the body is a series of instructions on how to update the resource. Patch files or JSON Patch are examples of such media types. @@ -724,6 +730,9 @@ listed here, like the authorization header. == Changelog +* *2.9*: An `AcceptCallback` can now return `{created, URI}` or + `{see_other, URI}`. The return value `{true, URI}` + is deprecated. * *2.7*: The media type wildcard in `content_types_accepted` is now documented. * *2.6*: The callback `rate_limited` was added. diff --git a/src/cowboy_rest.erl b/src/cowboy_rest.erl index 468f9ab..7d0fe80 100644 --- a/src/cowboy_rest.erl +++ b/src/cowboy_rest.erl @@ -1104,6 +1104,14 @@ process_content_type(Req, State=#state{method=Method, exists=Exists}, Fun) -> next(Req2, State2, fun maybe_created/2); {false, Req2, State2} -> respond(Req2, State2, 400); + {{created, ResURL}, Req2, State2} when Method =:= <<"POST">> -> + Req3 = cowboy_req:set_resp_header( + <<"location">>, ResURL, Req2), + respond(Req3, State2, 201); + {{see_other, ResURL}, Req2, State2} when Method =:= <<"POST">> -> + Req3 = cowboy_req:set_resp_header( + <<"location">>, ResURL, Req2), + respond(Req3, State2, 303); {{true, ResURL}, Req2, State2} when Method =:= <<"POST">> -> Req3 = cowboy_req:set_resp_header( <<"location">>, ResURL, Req2), diff --git a/test/handlers/create_resource_h.erl b/test/handlers/create_resource_h.erl new file mode 100644 index 0000000..f82e610 --- /dev/null +++ b/test/handlers/create_resource_h.erl @@ -0,0 +1,28 @@ +-module(create_resource_h). + +-export([init/2]). +-export([allowed_methods/2]). +-export([resource_exists/2]). +-export([content_types_accepted/2]). +-export([from_text/2]). + +init(Req, Opts) -> + {cowboy_rest, Req, Opts}. + +allowed_methods(Req, State) -> + {[<<"POST">>], Req, State}. + +resource_exists(Req, State) -> + {true, Req, State}. + +content_types_accepted(Req, State) -> + {[{{<<"application">>, <<"text">>, []}, from_text}], Req, State}. + +from_text(Req=#{qs := Qs}, State) -> + NewURI = [cowboy_req:uri(Req), "/foo"], + case Qs of + <<"created">> -> + {{created, NewURI}, Req, State}; + <<"see_other">> -> + {{see_other, NewURI}, Req, State} + end. diff --git a/test/rest_handler_SUITE.erl b/test/rest_handler_SUITE.erl index 43695c3..1667565 100644 --- a/test/rest_handler_SUITE.erl +++ b/test/rest_handler_SUITE.erl @@ -52,6 +52,7 @@ init_dispatch(_) -> {"/content_types_accepted", content_types_accepted_h, []}, {"/content_types_provided", content_types_provided_h, []}, {"/delete_resource", delete_resource_h, []}, + {"/create_resource", create_resource_h, []}, {"/expires", expires_h, []}, {"/generate_etag", generate_etag_h, []}, {"/if_range", if_range_h, []}, @@ -474,6 +475,29 @@ delete_resource_missing(Config) -> {response, _, 500, _} = gun:await(ConnPid, Ref), ok. +create_resource_created(Config) -> + doc("POST to an existing resource to create a new resource. " + "When the accept callback returns {created, NewURI}, " + "the expected reply is 201 Created."), + ConnPid = gun_open(Config), + Ref = gun:post(ConnPid, "/create_resource?created", [ + {<<"content-type">>, <<"application/text">>} + ], <<"hello">>, #{}), + {response, _, 201, _} = gun:await(ConnPid, Ref), + ok. + +create_resource_see_other(Config) -> + doc("POST to an existing resource to create a new resource. " + "When the accept callback returns {see_other, NewURI}, " + "the expected reply is 303 See Other with a location header set."), + ConnPid = gun_open(Config), + Ref = gun:post(ConnPid, "/create_resource?see_other", [ + {<<"content-type">>, <<"application/text">>} + ], <<"hello">>, #{}), + {response, _, 303, RespHeaders} = gun:await(ConnPid, Ref), + {_, _} = lists:keyfind(<<"location">>, 1, RespHeaders), + ok. + error_on_malformed_accept(Config) -> doc("A malformed Accept header must result in a 400 response."), do_error_on_malformed_header(Config, <<"accept">>). |