Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

281 lines (230 sloc) 9.513 kb
<erl>
box(Str) ->
{'div',[{class,"box"}],
{pre,[], yaws_api:htmlize(Str)}}.
tbox(T) ->
box(lists:flatten(io_lib:format("~p",[T]))).
ssi(File) ->
{'div',[{class,"box"}],
{pre,[],
{ssi, File,[],[]}}}.
ss(A, File) ->
{ok, B} = file:read_file(
filename:join([A#arg.docroot, File])),
box(binary_to_list(B)).
out(A) ->
[{ssi, "TAB.inc", "%%",[{"json_intro", "choosen"}]},
{ehtml,
{'div', [{id, "entry"}],
[{h1, [], "AJAX through JSON RPC"},
{p, [],
{i, [],
["Note: this documentation used to refer to the module "
"'yaws_jsonrpc', but that module was deprecated in favor of "
"'yaws_rpc', which handles JSON RPC, haXe and SOAP remoting. "
"For more specific information about SOAP, refer to ",
{a, [{href, "/soap_intro.yaws"}], "the SOAP page."}]}},
{p, [],
["The Yaws JSON-RPC binding is a way to have JavaScript code in the "
"browser evaluate a remote procedure call (RPC) in the Yaws server. "
"JSON itself as described at ",
{a, [{href, "http://www.json.org/"}], "http://www.json.org/ "},
"is basically a simple marshaling format which can be used "
"from a variety of different programming languages, and "
"naturally it's completely straightforward to implement "
"in JavaScript itself. JSON-RPC version 2.0, the version Yaws "
"supports, is described here:"]},
{p, [],
[{a, [{href,
"http://groups.google.com/group/json-rpc/web/json-rpc-2-0"}],
"http://groups.google.com/group/json-rpc/web/json-rpc-2-0"}]},
{p, [],
"The Yaws JSON-RPC implementation consist of JavaScript clients and a "
"server side library that must be explicitly invoked by Erlang "
"code in a .yaws page, appmod, etc."},
{p,[],
"It is not particularly easy to show and explain an AJAX setup "
"through JSON-RPC, but here is an attempt:"
},
{p,[],
"First we have an HTML page which:"},
{ol, [],
[
{li,[],{p,[],
["Includes the client side of the JSON library. "
"The library is included in the Yaws distribution "
"and it is found under ",
{a,
[{href,
"https://github.com/klacke/yaws/blob/master/www/jsolait/jsolait.js"}],
"\"www/jsolait/jsolait.js\""}, "."]}},
{li,[],{p,[],"Second, the HTML code defines the name of a method, "
"i.e. the name of a server-side function that shall be "
"called by the client side JavaScript code."}},
{li,[],{p,[],"Finally the HTML code defines a FORM that's "
"used to invoke the RPC. This is just a really simple "
"example, really any JavaScript code can invoke any RPC in "
"more interesting scenarios than submitting a form."}}]},
{p, [], "The HTML code appears as shown below:"},
ss(A,"json_sample.html"),
{p, [], ["This HTML code resides in file ",
{a,[{href, "json_sample.html"}], "json_sample.html"},
" and it is the HTML code that is the AJAX GUI."]},
{p, [], "Following that we need to take a look at json_sample.yaws "
" (shown below), which is the \"serviceURL\" according to "
"the JavaScript code. This code defines the function to be "
"called. Remember that the JavaScript code defined one method, "
"called \"test1\"; this information will be passed to the "
"serviceURL. The code looks like:"},
ss(A, "json_sample.yaws"),
{p,[], "The two important lines on the server side are"},
{ol,[],
[
{li,[],
{pre,[],"yaws_rpc:handler_session(A2, {sample_mod, counter})."}},
{li,[],
{pre,[],"counter([{ip, IP}] = _State, {call, test1, Value} = _Request, Session)"}}]},
{p,[],
["The first line tells Yaws to forward all JSON-RPC methods to the "
" \"counter\" function in the \"sample_mod\" module. "
"The second line is the head of the counter function that will be "
"called when the client invokes a method called 'test1'. We would "
"duplicate this line with a different name than 'test1' for each RPC "
"function we wish to implement. Note that the first atom in the "
"request tuple will either be 'call' or 'notification' to indicate "
"the type of request. As per the ",
{a,[{href,"http://groups.google.com/group/json-rpc/web/json-rpc-2-0"}],
"JSON-RPC 2.0 specification"},
", a 'call' is a regular request-reply while a 'notification' is a "
"one-way message that does not have a corresponding reply."]},
{p,[],"On the client side we have"},
box("
var methods = [ \"test1\" ];
var jsonrpc = imprt(\"jsonrpc\");
var service = new jsonrpc.ServiceProxy(serviceURL, methods);
"),
{p,[],"This registers the Yaws page with the JSON-RPC handler and "
"gives it a list of methods that the Yaws page can satisfy. "
"In this case, the only method called 'test1'."},
{p, [],
"When we wish to return structured data, we simply let "
"the user-defined RPC function return JSON structures such as "},
box("{struct, [{field1, \"foo\"}, {field2, \"bar\"}]} "),
{p, [], " for a structure and "},
box("{array, [\"foo\", \"bar\"]}"),
{p, [],"for an array. We can nest arrays and structs in each other."},
{p, [],
"Finally, we must stress that this example is extremely simple. "
"In order to build a proper AJAX application in Yaws, a lot of "
"client side work is required, all Yaws provides is the basic "
"mechanism whereby the client side JavaScript code can RPC the "
"web server for data which can be subsequently used to populate "
"the DOM. Also required to build a good AJAX application is "
"good knowledge of how the DOM in the browser works"},
{p, [],
["The yaws_rpc:handler will also call: M:F(cookie_expire) "
"which is expected to return a proper Cookie expire string. This "
"makes it possible to setup the Cookie lifetime. If this callback "
"function is non-existent, the default behaviour is to not set a "
"cookie expiration time, i.e., it will live for this session only."]},
{h3, [], "One more example "},
{p, [],
["Here is yet another example, stolen from ",
{a,
[{href,"http://www.redhoterlang.com/entry/ac061493b201e3d1b4490cdc3f911068"}],
"Tobbe's blog."}
]},
{h4, [], "Setup the DOM"},
{p, [], "In the file ''ex1.html'' we create the DOM with a little HTML and add some JavaScript that will talk with the Erlang server side."},
box("
<html>
<head>
<script type=\"text/javascript\"
src=\"/jquery-1.2.3.js\"></script>
</head>
<body>
<script language=\"javascript\" type=\"text/javascript\">
function ex1(what) {
$.getJSON(\"/ex1.yaws\",
{'op': \"ex1\", 'what': what},
function(x) {
do_ex1(what, x)
});
}
function do_ex1(what, x) {
jQuery.each(x, doit);
}
function doit() {
$('#'+this.who).html(this.what);
}
</script>
<button onclick=\"ex1('one')\">Update one!</button>
<button onclick=\"ex1('two')\">Update two!</button>
<button onclick=\"ex1('three')\">Update three!</button>
<div id=\"one\">This is one</div>
<div id=\"two\">This is two</div>
<div id=\"three\">This is three</div>
</body>
</html>
"),
{h4, [], "The erlang server side"},
{p, [], "This is the code that needs to be installed and "
"execute on the server side. It nicely illustrates how "
"to return JSON structs to the client. "},
box("
-module(ex1).
-export([out/1]).
out(A) ->
L = yaws_api:parse_query(A),
dispatch(lkup(\"op\", L, false), A, L).
dispatch(\"ex1\", A, L) ->
ex1(A, L).
ex1(_A, L) ->
J = json2:encode(array(what(lkup(\"what\", L, false)))),
return_json(J).
what(\"one\") -> one();
what(\"two\") -> one() ++ two();
what(\"three\") -> one() ++ two() ++ three().
array(L) -> {array, L}.
one() -> obj(\"one\").
two() -> obj(\"two\").
three() -> obj(\"three\").
obj(M) ->
obj(M, \"r\").
%%%
%%% How ::= \"r\" | \"a\" , r=replace, a=append
%%%
obj(M, How) ->
C = now2str(),
[{struct,
[{\"who\", M},
{\"how\", How},
{\"what\", C ++\" \"++M++\" content\"}]}].
return_json(Json) ->
{content,
\"application/json; charset=iso-8859-1\",
Json}.
now2str() ->
{A,B,C} = erlang:now(),
i2l(A)++\"-\"++i2l(B)++\"-\"++i2l(C).
i2l(I) when is_integer(I) -> integer_to_list(I);
i2l(L) when is_list(L) -> L.
lkup(Key, List, Def) ->
case lists:keysearch(Key, 1, List) of
{value,{_,Value}} -> Value;
_ -> Def
end.
") ,
{h2, [], "The json library"},
{p, [],
["The Yaws JSON library contains 3 simple functions, "
" one for encoding and two for decoding. See source code ",
{a,
[{href,
"https://github.com/klacke/yaws/blob/master/src/json2.erl"}],
"json2.erl"},
" for detailed instructions on usage."]}
]}},
{ssi, "END2",[],[]}
].
</erl>
Jump to Line
Something went wrong with that request. Please try again.