0
votes

I'm trying to implement Rest handler and have next code:

-module(example_handler).
-behaviour(cowboy_handler).

-export([init/2,
         allowed_methods/2,
         content_types_provided/2,
         get_json/2]).

init(Req, State) ->
    {cowboy_rest, Req, State}.

allowed_methods(Req, State) ->
    io:format("allowed_methods~n"),
    {[<<"GET">>, <<"POST">>], Req, State}.

content_types_provided(Req, State) ->
    io:format("content_types_provided~n"),
    {[{{<<"application">>, <<"json">>, []}, get_json}], Req, State}.

get_json(_Req, _State) ->
    io:format("get_json~n")

Then when I try to send request with curl like that:

curl -H "Accept: application/json" -X POST http://localhost:8080/xxx/xx

I get next output:

allowed_methods
content_types_provided

get_json() is not called! But when I use GET method everything looks ok:

curl -H "Accept: application/json" -X GET http://localhost:8080/xxx/xx
----------------------------------------------------------------------
allowed_methods
content_types_provided
get_json

What I missed?

1
It would be nice if you start doing something on your own, and when you get stuck on something, ask about it in particular. - x80486
@ɐuıɥɔɐɯ I changed my question, could you please answer? - Hemul

1 Answers

1
votes

TL;DR

content_types_provided is not the same as content_types_accepted; since you are handling a POST you need the later.


In Cowboy 2.0.0, which is what I use, content_types_provided callback return the list of media types the resource provides in order of preference. So, when you use:

content_types_provided(Req, State) ->
  {[
    {{<<"application">>, <<"json">>, []}, get_json}
  ], Req, State}.

You are basically telling Cowboy that, from now on, this handler supports JSON responses. That's why when you do a GET you will successfully get an HTTP 200 (OK)...but a POST doesn't work.

On the other hand, the content_types_accepted callback allow to state what content-types to accept. You are indeed allowed to send POST requests since you added <<"POST">> in the allowed_methods callback but that will result in an HTTP 415 (Unsupported Media Type) response because you haven't told cowboy_rest that you want to accept application/json.

This is something that should work for you:

-module(example_handler).

-export([init/2]).

-export([
  allowed_methods/2,
  content_types_accepted/2,
  content_types_provided/2
]).

-export([get_json/2, post_json/2]).

%%%==============================================
%%% Exports
%%%==============================================
init(Req, Opts) ->
  {cowboy_rest, Req, Opts}.

allowed_methods(Req, State) ->
  lager:debug("allowed_methods"),
  {[<<"GET">>, <<"POST">>], Req, State}.

content_types_accepted(Req, State) ->
  lager:debug("content_types_accepted"),
  {[
    {{<<"application">>, <<"json">>, []}, post_json}
  ], Req, State}.

content_types_provided(Req, State) ->
  lager:debug("content_types_provided"),
  {[
    {{<<"application">>, <<"json">>, []}, get_json}
  ], Req, State}.

get_json(Req, State) ->
  lager:debug("get_json"),
  {<<"{ \"hello\": \"there\" }">>, Req, State}.

post_json(Req, State) ->
  lager:debug("post_json"),
  {true, Req, State}.

%%%==============================================
%%% Internal
%%%==============================================