REST API implementation using Yaws - yaws
I'm trying to build a REST API using the Yaws web server but I'm unable to get Yaws to dispatch requests to my module.
-module(rest).
-include_lib("stdlib/include/qlc.hrl").
-include_lib("yaws/include/yaws_api.hrl").
-export([out/1, addAirport/4, handle/2]).
-compile(export_all).
-define(RECORD_TYPE, airport).
-define(RECORD_KEY_FIELD, code).
-record(airport,
{code, city, country, name }).
start() ->
application:start(mnesia).
do_this_once() ->
mnesia:create_table(airport, [{attributes,record_info(fields,airport)},{index, [country]}]),
mnesia:stop().
out(Arg) ->
Method = method(Arg) ,
io:format("~p:~p ~p Request ~n", [?MODULE, ?LINE, Method]),
handle(Method, Arg).
method(Arg) ->
Rec = Arg#arg.req,
Rec#http_request.method.
convert_to_json(Lines) ->
Data = [{obj, [{airport, Line#?RECORD_TYPE.code},
{city, Line#?RECORD_TYPE.city},
{country, Line#?RECORD_TYPE.country},
{name, Line#?RECORD_TYPE.name}]} || Line <- Lines],
JsonData = {obj, [{data, Data}]},
rfc4627:encode(JsonData).
addAirport(Code, City, Country, Name) ->
NewRec = #?RECORD_TYPE{?RECORD_KEY_FIELD = Code,
city = City,
country = Country,
name = Name},
io:format("~p:~p Adding Airport ~p~n",
[?MODULE,?LINE, NewRec]),
Add = fun() ->
mnesia:write(NewRec)
end,
{atomic, _Rec} = mnesia:transaction(Add),
NewRec.
handle('GET', _Arg) ->
io:format("~n ~p:~p GET Request ~n", [?MODULE, ?LINE]),
Records = do(qlc:q([X || X <- mnesia:table(?RECORD_TYPE)])),
Json = convert_to_json( Records),
io:format("~n ~p:~p GET Request Response ~p ~n", [?MODULE, ?LINE,
Json]),
{html, Json};
handle('POST', Arg) ->
{ok, Json, _} = rfc4627:decode(Arg#arg.clidata),
io:format("~n~p:~p POST request ~p~n",
[?MODULE, ?LINE, Json]),
Airport = rfc4627:get_field(Json, "airport", <<>>),
City = rfc4627:get_field(Json, "city", <<>>),
Country = rfc4627:get_field(Json, "country", <<>>),
Name= rfc4627:get_field(Json, "name", <<>>),
_Status = addAirport(Airport, City, Country, Name),
[{status, 201},
{html, Arg#arg.clidata}];
handle('PUT', Arg) ->
[IndexValue,_] = string:tokens(Arg#arg.pathinfo),
{ok, Json, _} = rfc4627:decode(Arg#arg.clidata),
io:format("~p:~p PUT request ~p ~p~n",
[?MODULE, ?LINE, IndexValue, Json]),
Airport = rfc4627:get_field(Json, "airport", <<>>),
City = rfc4627:get_field(Json, "city", <<>>),
Country = rfc4627:get_field(Json, "country", <<>>),
Name= rfc4627:get_field(Json, "name", <<>>),
NewRec = #?RECORD_TYPE{
?RECORD_KEY_FIELD = Airport,
city = City,
country = Country,
name = Name},
io:format("~p:~p Renaming ~p",
[?MODULE, ?LINE, NewRec]),
ChangeName = fun() ->
mnesia:delete(
{?RECORD_KEY_FIELD, IndexValue}),
mnesia:write(NewRec)
end,
{atomic, _Rec} = mnesia:transaction(ChangeName),
[{status, 200},
{html, IndexValue}];
handle('DELETE', Arg) ->
[IndexValue, _ ] = string:tokens(Arg#arg.pathinfo),
io:format("~p:~p DELETE request ~p",
[?MODULE, ?LINE, IndexValue]),
Delete = fun() ->
mnesia:delete(
{?RECORD_KEY_FIELD, IndexValue})
end,
Resp = mnesia:transaction(Delete),
case Resp of
{atomic, ok} ->
[{status, 204}];
{_, Error} ->
io:format("~p:~p Error ~p ",
[?MODULE, ?LINE, Error]),
[{status, 400},
{html, Error}]
end;
handle(Method,_) ->
[{error, "Unknown method " ++ Method},
{status, 405},
{header, "Allow: GET, HEAD, POST, PUT, DELETE"}
].
do(Q)->
F = fun() ->
qlc:e(Q)
end,
{atomic, Value} = mnesia:transaction(F),
Value.
You need to register your module as a Yaws appmod in the server configuration portion of your yaws.conf file. Please see the Yaws appmod documentation for the necessary details.
Related
Ejabberd get room online occupants within module
I am currently trying to get the occupants of a room in a custom Ejabberd module within the muc_filter_message hook, but all attempts to get the room state are timing out. error: 2016-07-25 10:43:04.802 [error] <0.13909.0>#ejabberd_hooks:run_fold1:368 {timeout,{gen_fsm,sync_send_all_state_event,[<0.13909.0>,get_state]}} imports + hook function (cut down) -behaviour(gen_mod). -include("ejabberd.hrl"). -include("logger.hrl"). -include("jlib.hrl"). -include("mod_muc_room.hrl"). -include("mod_muc.hrl"). -include("ejabberd_http.hrl"). -include("ejabberd_web_admin.hrl"). -include("ejabberd_commands.hrl"). muc_message_sent(Stanza, MUCState, RoomJID, FromJID, FromNick) -> {_, RoomName, Host, _, _, _, _} = RoomJID, OccuList = get_room_occupants(RoomName, Host), ?INFO_MSG("muc_message_sent OccuList ~p~n", [OccuList]), Stanza. Code for room occupants retrieval: get_room_occupants(Room, Host) -> case get_room_pid(Room, Host) of room_not_found -> ?INFO_MSG("muc_message_sent get_room_occ ~p~n", [room]); Pid -> get_room_occupants(Pid) end. get_room_occupants(Pid) -> ?INFO_MSG("muc_message_sent get_room_pstate ~p~n", [Pid]), S = get_room_state(Pid), ?INFO_MSG("muc_message_sent get_room_state S ~p~n", [S]), lists:map( fun({_LJID, Info}) -> {jid:to_string(Info#user.jid), Info#user.nick, atom_to_list(Info#user.role)} end, dict:to_list(S#state.users)). %% #doc Get the Pid of an existing MUC room, or 'room_not_found'. get_room_pid(Name, Service) -> case mnesia:dirty_read(muc_online_room, {Name, Service}) of [] -> ?INFO_MSG("muc_message_sent get_room_pid ~p~n", [failed]), room_not_found; [Room] -> ?INFO_MSG("muc_message_sent get_room_pid ~p~n", [pid]), Room#muc_online_room.pid end. get_room_state(Room_pid) -> {ok, R} = gen_fsm:sync_send_all_state_event(Room_pid, get_state), R. The get_room_occupants code is pulled directly from mod_muc_admin where it works fine (but I couldn't find a way to directly use the functions within that module). Been stuck on this for a while now so any ideas appreciated.
Riak Commit Hook CRDT Increment Counter
I have a commit hook that I want to update a counter. Currently I have: -module(bucket_counter). -export([precommit/1]). -record(crdt_op, {mod, op, ctx}). -define(CRDT_OP, #crdt_op). -define(V1_COUNTER_TYPE, riak_kv_pncounter). precommit(RObj) -> {ok, Client} = riak:local_client(), Bucket = {<<"counters">>, <<"update_counts">>}, Id = <<"all">>, Counter = case Client:get(Bucket, Id) of {error, notfound} -> riak_object:new(Bucket, Id, 0); {ok, Obj} -> Obj end, io:format("Counter ~p~n", [Counter]), {{Context,_},_} = riak_kv_crdt:value(Counter, ?V1_COUNTER_TYPE), Op = ?CRDT_OP{mod=?V1_COUNTER_TYPE, op={increment, 1}, ctx=Context}, Counter2 = riak_kv_crdt:update(Counter, <<"1234">>, Op), io:format("Gen ~p~n", [Counter2]), %Counter3 = riak_kv_crdt:merge(Counter2), Client:put(Counter2), RObj. This produces the error: #riak_kv_put_fsm:decode_precommit:887 Problem invoking pre-commit hook bucket_counter:precommit -> error:function_clause [{riak_kv_crdt,update_crdt,[[{riak_dt_pncounter,{{dict,5,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[[<<"dot">>|{<<252,97,47,244,1,104,136,26>>,{1,63622971158}}]],[],[],[],[],[],[[<<"content-type">>,97,112,112,108,105,99,97,116,105,111,110,47,114,105,97,107,95,99,111,117,110,116,101,114],[<<"X-Riak-VTag">>,53,87,81,75,79,113,110,77,80,111,117,49,71,101,120,122,52,67,89,115,66,122]],[[<<"index">>]],[],[[<<"X-Riak-Last-Modified">>|{1455,751958,325156}]],[],[]}}},{crdt,riak_dt_pncounter,"application/riak_counter",[{<<252,97,47,244,1,104,136,26>>,1,0}]}}}],<<"1234">>,{crdt_op,riak_kv_pncounter,{increment,1},<<>>}],[{file,"src/riak_kv_crdt.erl"},{line,234}]},{riak_kv_crdt,update,3,[{file,"src/riak_kv_crdt.erl"},{line,61}]},{bucket_counter,precommit,1,[{file,"bucket_counter.erl"},{line,24}]},{riak_kv_put_fsm,invoke_hook,4,[{file,"src/riak_kv_put_fsm.erl"},{line,853}]},{riak_kv_put_fsm,precommit,2,[{file,"src/riak_kv_put_fsm.erl"},{line,503}]},{gen_fsm,handle_msg,7,[{file,"gen_fsm.erl"},{line,505}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,239}]}] Looking into riak_kv source, It looks like merge only works with Maps and Sets when you have a context: https://github.com/basho/riak_kv/blob/master/src/riak_kv_crdt.erl#L246 I have tried removing the context but it then crashes because of siblings: riak_index:parse_object_hook:116 Siblings not allowed: {r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,49,67,49,85,69,121,66,118,111,84,56,85,118,81,104,104,106,74,101,98,49,71]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,750950,430934}]],[],[]}}},<<69,2,0,0,0,17,114,105,97,107,95,100,116,95,112,110,99,111,117,110,116,101,114,71,2,131,108,0,0,0,1,104,3,109,0,0,0,8,252,97,47,244,156,20,105,128,97,1,97,0,106>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,49,67,49,85,69,121,66,118,111,84,56,85,118,81,104,104,106,74,101,98,49,71]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,750950,430934}]],[],[]}}},<<69,1,71,1,0,0,0,22,70,1,131,108,0,0,0,1,104,2,109,0,0,0,4,49,50,51,52,97,1,106,0,0,0,4,70,1,131,106>>}],[{<<252,97,47,244,156,20,105,128>>,{1,63622970068}}],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined} Updating to map gives me a sibling error: -module(bucket_counter). -export([precommit/1]). -record(crdt_op, {mod, op, ctx}). -define(CRDT_OP, #crdt_op). -define(V1_COUNTER_TYPE, riak_kv_pncounter). precommit(RObj) -> {ok, Client} = riak:local_client(), Bucket = {<<"counters">>, <<"update_counts">>}, Id = <<"all">>, {Counter, Context} = case Client:get(Bucket, Id) of {error, notfound} -> Obj = riak_object:new(Bucket, Id, 0), {Obj, undefined}; {ok, Obj} -> {{CountContext,_},_} = riak_kv_crdt:value(Obj, riak_dt_map), {Obj, CountContext} end, io:format("Counter ~p~n", [Counter]), Op = ?CRDT_OP{mod=riak_dt_map, op={update,[{update,{<<"count">>,riak_dt_emcntr},increment}]}, ctx=Context}, Counter2 = riak_kv_crdt:update(Counter, <<"1234">>, Op), io:format("Gen ~p~n", [Counter2]), %Counter3 = riak_kv_crdt:merge(Counter2), Client:put(Counter2), RObj. riak_index:parse_object_hook:116 Siblings not allowed: {r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},<<69,2,0,0,0,11,114,105,97,107,95,100,116,95,109,97,112,77,1,131,80,0,0,0,132,120,1,203,96,206,97,96,96,96,204,96,202,5,82,44,134,70,198,38,137,140,89,80,33,136,32,107,114,126,105,94,73,10,3,95,81,102,98,118,124,74,73,124,106,110,114,94,73,81,6,19,138,42,168,86,184,40,22,227,224,66,25,204,137,140,64,200,144,149,149,193,148,5,4,0,198,254,26,118>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},0}],[],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined} 2016-02-18 00:48:25.966 [debug] <0.2105.0>#riak_kv_put_fsm:decode_precommit:880 Pre-commit hook riak_index:parse_object_hook failed with reason {siblings_not_allowed,{r_object,{<<"counters">>,<<"update_counts">>},<<"all">>,[{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},<<69,2,0,0,0,11,114,105,97,107,95,100,116,95,109,97,112,77,1,131,80,0,0,0,132,120,1,203,96,206,97,96,96,96,204,96,202,5,82,44,134,70,198,38,137,140,89,80,33,136,32,107,114,126,105,94,73,10,3,95,81,102,98,118,124,74,73,124,106,110,114,94,73,81,6,19,138,42,168,86,184,40,22,227,224,66,25,204,137,140,64,200,144,149,149,193,148,5,4,0,198,254,26,118>>},{r_content,{dict,2,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,74,73,109,71,89,110,100,82,71,101,88,80,71,107,72,105,53,113,78,48,90]],[],[],[[<<"X-Riak-Last-Modified">>|{1455,756505,963692}]],[],[]}}},0}],[],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined}}
I have figured it out, I was going off of 1.4 documentation and instead I needed to do riak_kv_crdt:new(Bucket, Id, riak_dt_map)
User send packet hook returning `badmatch` error
I am using user send packet hook in my custom module, I am not understanding why getting badmatch error for each of the packet received. i have added declaration part here too. **Code** -module(mod_post_log). -behaviour(gen_mod). -export([start/2,stop/1,log_user_send/4,post_result/1,send_message/3]). **strong text** -include("ejabberd.hrl"). -include("jlib.hrl"). -include("logger.hrl"). start(Host, _Opts) -> ok = case inets:start() of {error, {already_started, inets}} -> ok; ok -> ok end, ejabberd_hooks:add(user_send_packet, Host, ?MODULE, log_user_send, 50), ok. stop(Host) -> ejabberd_hooks:delete(user_send_packet, Host, ?MODULE, log_user_send, 50), ok. log_user_send(Packet, _C2SState, From, To) -> ok = log_packet(From, To, Packet), Packet. log_packet(From, To, #xmlel{name = <<"message">>} = Packet) -> MessageId = xml:get_tag_attr_s(<<"id">>, Packet), Type = xml:get_tag_attr_s(list_to_binary("type"), Packet), send_message(From, To, MessageId, Type), %% send_message(From, To, xml:get_tag_attr_s(list_to_binary("id"), Packet),xml:get_tag_attr_s(list_to_binary("type"), Packet)), %% ?INFO_MSG("mod_ack_receipt - MsgID: ~p To: ~p From: ~p", [MessageId, To, From]), ok = log_message(From, To, Packet); log_packet(_From, _To, _Packet) -> ok. log_message(From, To, #xmlel{attrs = Attrs} = Packet) -> Type = lists:keyfind(<<"type">>, 1, Attrs), log_message_filter(Type, From, To, Packet). log_message_filter({<<"type">>, Type}, From, To, Packet) when Type =:= <<"chat">>; Type =:= <<"groupchat">> -> log_chat(From, To, Packet); log_message_filter(_Other, _From, _To, _Packet) -> ok. log_chat(From, To, #xmlel{children = Els} = Packet) -> case get_body(Els) of no_body -> ok; {ok, _Body} -> log_chat_with_body(From, To, Packet) end. log_chat_with_body(From, To, Packet) -> case should_acknowledge(Packet) of S when (S==true) -> post_xml(From, To, Packet); false -> ok end, Packet. should_acknowledge(#xmlel{name = <<"message">>} = Packet) -> case {xml:get_attr_s(<<"type">>, Packet#xmlel.attrs), xml:get_subtag_cdata(Packet, <<"body">>)} of {<<"error">>, _} -> false; {_, <<>>} -> %% Empty body false; _ -> true end; should_acknowledge(#xmlel{}) -> false. post_xml(From, To, Packet) -> Ts = to_iso_8601_date(os:timestamp()), MessageId = xml:get_tag_attr_s(list_to_binary("id"), Packet), Type = xml:get_tag_attr_s(list_to_binary("type"), Packet), Chat_sent = xml:get_tag_attr_s(list_to_binary("chat_sent"), Packet), Subject = xml:get_path_s(Packet, [{elem, list_to_binary("subject")},cdata]), Body = xml:get_path_s(Packet,[{elem, list_to_binary("body")}, cdata]), Sep = "&", Post = [ "from=", From#jid.luser, Sep, "to=", To#jid.luser, Sep, "body=", binary_to_list(Body), Sep, "type=", binary_to_list(Type),Sep, "chat_sent=", binary_to_list(Chat_sent),Sep, "subject=",binary_to_list(Subject),Sep, "message_id=", binary_to_list(MessageId),Sep, "xml=",xml:element_to_binary(Packet),Sep, "done=11" ], Url = get_opt(url), TsHeader = get_opt(ts_header, "X-Message-Timestamp"), FromHeader = get_opt(from_header, "X-Message-From"), ToHeader = get_opt(to_header, "X-Message-To"), HttpOptions = get_opt(http_options, []), ReqOptions = get_opt(req_options, []), {ok, _ReqId} = httpc:request(post, {Url, [], "application/x-www-form-urlencoded", list_to_binary(Post)}, HttpOptions, [ {sync, false}, {receiver, {?MODULE, post_result, []}} | ReqOptions ]), ?INFO_MSG("post http - MsgID: xml: ~p", [post]), ok. post_result({_ReqId, {error, Reason}}) -> report_error([ {error, Reason } ]); post_result({_ReqId, Result}) -> {StatusLine, Headers, Body} = Result, {_HttpVersion, StatusCode, ReasonPhrase} = StatusLine, if StatusCode < 200; StatusCode > 299 -> ok = report_error([ {status_code, StatusCode}, {reason_phrase, ReasonPhrase}, {headers, Headers}, {body, Body} ]), ok; true -> ok end. send_message(From, To, MessageId,Type) -> Packet = #xmlel{name = <<"iq">>, attrs = [{<<"to">>, From},{<<"ack">>, MessageId}, {<<"type">>, <<"result">>},{<<"chattype">>, Type}], children = [#xmlel{name = <<"ack">>, attrs = [{<<"xmlns">>,<<"xmpp:ack">> }], children = []}]}, ejabberd_router:route(From, From, Packet). get_body(Els) -> XmlEls = [ El || El <- Els, is_record(El, xmlel) ], case lists:keyfind(<<"body">>, #xmlel.name, XmlEls) of false -> no_body; #xmlel{children = InnerEls} -> case lists:keyfind(xmlcdata, 1, InnerEls) of false -> no_body; {xmlcdata, Body} -> {ok, Body} end end. get_opt(Opt) -> get_opt(Opt, undefined). get_opt(Opt, Default) -> F = fun(Val) when is_binary(Val) -> binary_to_list(Val); (Val) -> Val end, gen_mod:get_module_opt(global, ?MODULE, Opt, F, Default). report_error(ReportArgs) -> ok = error_logger:error_report([ mod_post_log_cannot_post | ReportArgs ]). **Error Log** {{badmatch,{xmlel,<<"message">>, [{<<"xml:lang">>,<<"en">>}, {<<"to">>,<<"123456789#xyz.myapp.com">>}, {<<"id">>,<<"AF1xJ-149">>}, {<<"chat_sent">>,<<"2015-12-15T06:45:29.399Z">>}, {<<"type">>,<<"chat">>}], [{xmlel,<<"size">>,[],[{xmlcdata,<<"0">>}]}, {xmlel,<<"subject">>,[],[{xmlcdata,<<"poke">>}]}, {xmlel,<<"body">>,[],[{xmlcdata,<<"95">>}]}, {xmlel,<<"request">>, [{<<"xmlns">>,<<"urn:xmpp:receipts">>}], []}]}}, [{mod_post_log,log_packet,3, [{file,"src/mod_post_log.erl"},{line,44}]}, {mod_post_log,log_user_send,4, [{file,"src/mod_post_log.erl"},{line,33}]}, {ejabberd_hooks,safe_apply,3, [{file,"src/ejabberd_hooks.erl"},{line,382}]}, {ejabberd_hooks,run_fold1,4, [{file,"src/ejabberd_hooks.erl"},{line,365}]}, {ejabberd_c2s,session_established2,2, [{file,"src/ejabberd_c2s.erl"},{line,1296}]}, {p1_fsm,handle_msg,10,[{file,"src/p1_fsm.erl"},{line,582}]}, {proc_lib,init_p_do_apply,3, [{file,"proc_lib.erl"},{line,237}]}]}
In file src/mod_post_log.erl at line 44 in function mod_post_log:log_packet/3 is some match operator which doesn't expect to get {xmlel,<<"message">>, [{<<"xml:lang">>,<<"en">>}, {<<"to">>,<<"123456789#xyz.myapp.com">>}, {<<"id">>,<<"AF1xJ-149">>}, {<<"chat_sent">>,<<"2015-12-15T06:45:29.399Z">>}, {<<"type">>,<<"chat">>}], [{xmlel,<<"size">>,[],[{xmlcdata,<<"0">>}]}, {xmlel,<<"subject">>,[],[{xmlcdata,<<"poke">>}]}, {xmlel,<<"body">>,[],[{xmlcdata,<<"95">>}]}, {xmlel,<<"request">>, [{<<"xmlns">>,<<"urn:xmpp:receipts">>}], []}]}
it would be much better to see full module "mod_post_log.erl" as is. But i think that problem is here : MessageId = xml:get_tag_attr_s(<<"id">>, Packet), Packet is a record, and function wait for iolist, so it should be something like MessageId = xml:get_tag_attr_s(<<"id">>, Packet#xmlel.{{see record declaration}}),
How to POST Json data using content_type_accepted method in erlang in the handler
Here is the json data { "title": "The Title", "content": "The Content" } curl -vX POST http://localhost:10003/sample -H "Content-Type:application/json" \ -d '{ "title": "The Title", "content": "The Content" }' -export([content_types_accepted/2]). allowed_methods(Req, State) -> {[<<"GET">>, <<"POST">>], Req, State}. content_types_accepted(Req, State) -> {[{{<<"application">>, <<"json">>, []}, welcome}], Req, State}. welcome(Req, State) -> Req_method = cowboy_req:method(Req), io:format("Req_method is ~p ~n", [Req_method]), Req_Body = cowboy_req:body(Req), io:format("Body is ~p ~n", [Req_Body]), Body = <<"<h1>This is a response for other methods</h1>">>, io:format("Body is ~p ~n",[Body]), {Body, Req, State}. I see Method and Body but trying to catch json data unable to do such.
I was looking for http-Post-method, passing Json data using content_type_accepted method. Here is the code which worked for me :) -export([init/3]). -export([welcome/2, terminate/3, allowed_methods/2]). -export([content_types_accepted/2]). init(_Transport, _Req, []) -> {upgrade, protocol, cowboy_rest}. allowed_methods(Req, State) -> {[<<"POST">>], Req, State}. content_types_accepted(Req, State) -> {[{<<"application/json">>, welcome}], Req, State}. terminate(_Reason, _Req, _State) -> ok. welcome(Req, State) -> {ok, ReqBody, Req2} = cowboy_req:body(Req), Req_Body_decoded = jsx:decode(ReqBody), [{<<"title">>,Title},{<<"content">>,Content}] = Req_Body_decoded, Title1 = binary_to_list(Title), Content1 = binary_to_list(Content), io:format("Title1 is ~p ~n ", [Title1]), io:format("Content1 is ~p ~n", [Content1]), io:format("Title is ~p ~n", [Title]), io:format("Content is ~p ~n", [Content]), lager:log(info, [], "Request Body", [Req_Body_decoded]), Res1 = cowboy_req:set_resp_body(ReqBody, Req2), Res2 = cowboy_req:delete_resp_header(<<"content-type">>, Res1), Res3 = cowboy_req:set_resp_header(<<"content-type">>, <<"application/json">>, Res2), {true, Res3, State}.
Making an HTTP POST in Erlang itself is very simple. Taken from this other StackOverflow answer, here is a simple Example: ssl:start(), application:start(inets), PostBody = "{ \"title\": \"The Title\", \"content\": \"The Content\" }", Url = "http://some.url/endpoint", httpc:request(post, {Url, [], "application/x-www-form-urlencoded", PostBody }, [], []). Hope this helps! These resources also seem like they would be helpful: http://erlang.org/doc/man/httpc.html http://no-fucking-idea.com/blog/2013/01/22/making-request-to-rest-resources-in-erlang/
To catch the json values you can use jiffy https://github.com/davisp/jiffy Example usage : {JsonDecode} = jiffy:decode(ReqBody), error_logger:info_msg("JSON Decoded by jiffy ", JsonDecode), UserId = proplists:get_value(<<"userid">>, JsonDecode), Amount = proplists:get_value(<<"amount">>, JsonDecode), Rate = proplists:get_value(<<"rate">>, JsonDecode), Duration = proplists:get_value(<<"duration">>, JsonDecode),
Implementing mod_blocking on MongooseIM
I'm trying to implement mod_blocking that will work only with mod_privacy in odbc module. I keep getting the response: <error code='500' type='wait'><internal-server-error0 xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error> Here is my code: process_blocklist_block(LUser, LServer, JIDs) -> Filter = fun (List) -> AlreadyBlocked = list_to_blocklist_jids(List, []), lists:foldr(fun (JID, List1) -> case lists:member(JID, AlreadyBlocked) of true -> List1; false -> [#listitem{type = jid, value = JID, action = deny, order = 0, match_all = true} | List1] end end, List, JIDs) end, case process_blocklist_block(LUser, LServer, Filter,odbc) of {atomic, {ok, Default, List}} -> UserList = make_userlist(Default, List), broadcast_list_update(LUser, LServer, Default, UserList), broadcast_blocklist_event(LUser, LServer, {block, JIDs}), {result, [], UserList}; _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} end. process_blocklist_block(LUser, LServer, Filter, odbc) -> F = fun () -> Default = case mod_privacy_odbc:sql_get_default_privacy_list_t(LUser) of {selected, [<<"name">>], []} -> Name = <<"Blocked contacts">>, mod_privacy_odbc:sql_add_privacy_list(LUser, Name), mod_privacy_odbc:sql_set_default_privacy_list(LUser, Name), Name; {selected, [<<"name">>], [[Name]]} -> Name end, {selected, [<<"id">>], [[ID]]} = mod_privacy_odbc:sql_get_privacy_list_id_t(LUser, Default), case mod_privacy_odbc:sql_get_privacy_list_data_by_id_t(ID) of {selected, [<<"t">>, <<"value">>, <<"action">>, <<"ord">>, <<"match_all">>, <<"match_iq">>, <<"match_message">>, <<"match_presence_in">>, <<"match_presence_out">>], RItems = [_ | _]} -> List = lists:map(fun mod_privacy_odbc:raw_to_item/1, RItems); _ -> List = [] end, NewList = Filter(List), NewRItems = lists:map(fun mod_privacy_odbc:item_to_raw/1, NewList), mod_privacy_odbc:sql_set_privacy_list(ID, NewRItems), {ok, Default, NewList} end, ejabberd_odbc:sql_transaction(LServer, F). I've checked all the queries. They work fine. I struggling with understanding the logic of this piece of code. What is the best way to debug this code, so i can understand when my logic is failing? Could anyone point me in the right direction? UserList = make_userlist(Default, List), broadcast_list_update(LUser, LServer, Default, UserList), broadcast_blocklist_event(LUser, LServer, {block, JIDs}), {result, [], UserList}; _ -> {error, ?ERR_INTERNAL_SERVER_ERROR}
if you expect _ -> {error, ?ERR_INTERNAL_SERVER_ERROR} is the point where server returns 'internal server error', you can just change this place to _Otherwise -> ?WARNING_MSG("Got some unexpected result in mod_priv ~100000p",[_Otherwise]), {error, ?ERR_INTERNAL_SERVER_ERROR) and then look at log/ejabberd.log Of course you need to start mongooseim with loglevel at least 3 in the ejabberd.cfg