Ковбойский обработчик нескольких METHOD

Пытаясь настроить restful API через Cowboy, главное, чтобы я использовал один обработчик для всех методов.

вот роутер ::

 start(_Type, _Args) ->
    Dispatch = cowboy_router:compile([
        {'_', [
            {"/api", handler, []},
            {"/api/:id", handler, []}
        ]}
    ]),
    {ok, _} = cowboy:start_clear(http, 100, [{port, 8080}], #{
        env => #{dispatch => Dispatch}
    }),
    api_sup:start_link().

а вот код обработчика::

-module(handler).
-export([init/3, handle/2]).

init(_Transport, Req, []) ->
    {ok, Req, undefined}.

handle(Req, Opts) -> 
  case cowboy_req:method(Req) of
    <<"POST">> -> 
      Body = cowboy_req:has_body(Req),
      Request = postMethod(<<"POST">>, Body, Req),
        {ok, Request, Opts};
    <<"GET">> -> 
      #{id := Id} = cowboy_req:match_qs([{id, [], undefined}], Req),
      Request = getMethod(<<"GET">>, Id, Req),
        {ok, Request, Opts};
    <<"PUT">> -> 
      Body = cowboy_req:has_body(Req),
      Request = putMethod(<<"PUT">>, Body, Req),
        {ok, Request, Opts};
    <<"DELETE">> -> 
      #{id := Id} = cowboy_req:match_qs([{id, [], undefined}], Req),
      Request = deleteMethod(<<"DELETE">>, Id, Req),
        {ok, Request, Opts}
  end.

  postMethod(<<"POST">>, _Body, Req) -> 
    cowboy_req:reply(200, #{<<"content-type">> => <<"application/json; charset=utf-8">>}, <<"{\"status\": \"POST\"}">>, Req).
  getMethod(<<"GET">>, _Id, Req) -> 
      cowboy_req:reply(200, #{<<"content-type">> => <<"application/json; charset=utf-8">>}, <<"{\"status\": \"GET\"}">>, Req).
  putMethod(<<"PUT">>, _Body, Req) -> 
      cowboy_req:reply(200, #{<<"content-type">> => <<"application/json; charset=utf-8">>}, <<"{\"status\": \"PUT\"}">>, Req).
  deleteMethod(<<"DELETE">>, _Id, Req) -> 
      cowboy_req:reply(200, #{<<"content-type">> => <<"application/json; charset=utf-8">>}, <<"{\"status\": \"DELETE\"}">>, Req).

Я получаю сообщение об ошибке: ошибка ковбоя 500


person Eugen Dubrovin    schedule 05.02.2017    source источник
comment
Вы получаете какие-либо ошибки в терминале, где вы запустили этот сервер?   -  person Dogbert    schedule 05.02.2017
comment
нет, все в порядке, когда я запускаю сервер   -  person Eugen Dubrovin    schedule 05.02.2017
comment
Удалил лагер из api_app.app и ошибка подключения ушла. Но теперь я столкнулся с ошибкой 500   -  person Eugen Dubrovin    schedule 05.02.2017


Ответы (4)


Нашел ответ. вот код, который отлично работает (используя основную версию Cowboy)

-module(handler).

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

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

allowed_methods(Req, State) ->
    {[<<"GET">>, <<"POST">>, <<"PUT">>, <<"DELETE">>], Req, State}.

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

content_types_accepted(Req, State) ->
    {[{<<"application/json">>, router}], Req, State}.

router(Req, Opts) -> 
  case cowboy_req:method(Req) of
    <<"POST">> -> 
        {<<"{\"status\": \"POST\"}">>, Req, State};
    <<"GET">> -> 
      {<<"{\"status\": \"GET\"}">>, Req, State};
    <<"PUT">> -> 
      {<<"{\"status\": \"PUT\"}">>, Req, State};
    <<"DELETE">> -> 
      {<<"{\"status\": \"DELETE\"}">>, Req, State}
  end.
person Eugen Dubrovin    schedule 08.02.2017

Я пришел к немного другому подходу. Вместо того, чтобы использовать case, я использую функции, сопоставление с образцом метода в запросе, а затем все с кодом 405 Method Unsupported.

-module(handler).

-export([init/2]).

init(Req0, State) ->
  Req = case api:validate_headers(api_key, Req0) of
    ok -> handle(Req0, State);
    {error, Error} -> api:reply_failure(403, Error, Req0)
  end,
  {ok, Req, State}.

handle(Req0=#{method := <<"GET">>}, _) ->
  Data = "...", % Some data goes here
  api:reply_success([{<<"data">>, Data}], Req0);

handle(Req0=#{method := <<"POST">>}, _) ->
  Data = "...", % Some data goes here
  api:reply_success([{<<"data">>, Data}], Req0);

handle(Req=#{method := <<"OPTIONS">>}, _) ->
  api:reply_options(Req);

handle(Req, _) ->
  cowboy_req:reply(405, Req).
person Aleksey Gureiev    schedule 25.09.2018

Поскольку {Method, Req1} = cowboy_req:method(Req0) — это кортеж, как и {<<"PUT">>, _}, а не двоичный<<"PUT">>

person Maryna Krasnova    schedule 06.02.2017
comment
Да, я мог видеть это в Руководстве пользователя, но я не понимаю, почему это <<"PUT">> в примере cowboy echo_post ::: [github.com/ninenines/cowboy/blob/master/examples/echo_post/src/ - person Eugen Dubrovin; 06.02.2017
comment
Этот вопрос для команды 99-х, используйте кортеж - person Maryna Krasnova; 06.02.2017
comment
{Method, Req1} = cowboy_req:method(Req0) -- это было для версии 1.1.x. Основная версия теперь использует двоичный код - person Eugen Dubrovin; 08.02.2017

Вы также можете добавить логику маршрутизатора в метод обратного вызова content_types_accepted/2 следующим образом:

 content_types_accepted(Req, State) ->
       case cowboy_req:method(Req) of
         {<<"POST">>, _ } ->
           Accepted = {[{<<"application/json">>, post_json}], Req, State};
         {<<"PUT">>, _ } ->
           Accepted = {[{<<"application/json">>, put_json}], Req, State}
       end,
 Accepted.

Я думаю, что таким образом вы можете иметь отдельные обработчики для разных глаголов/методов HTTP. Это также дает вам более чистый код :)

person Oladipo Olasemo    schedule 05.09.2017