Developing web apps using Erlang-Web


Published on

Developing web apps using the Erlang-Web MVC framework.

Published in: Technology
1 Comment
No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Developing web apps using Erlang-Web

  1. 1. Server-side web development Using ErlangWeb Stefan Comanescu
  2. 2. A brief history of Erlang <ul><li>Initially developed by Joe Armstrong in 1986, as a proprietary language within Ericsson for usage in telephony applications
  3. 3. Named after the Danish mathematician Agner Krarup Erlang
  4. 4. First versions were running on a Prolog interpreter, a C emulator and a compiler were later written, for reasons concerning performance
  5. 5. In 1997 bit syntax and binaries were added (for protocol programming) and in the same year work started on OTP
  6. 6. Released as open source in 1998
  7. 7. SMP support was added in 2006 </li></ul>
  8. 8. Why Erlang ? <ul><li>Concurrency </li><ul><li>Actor model (no threads, no locks, no shared memory, only asynchronous message passing) </li></ul><li>Fault Tolerance </li><ul><li>Process linking, supervising trees, distribution and event managers help in keeping the system going when processes crash. </li></ul><li>Distribution </li><ul><li>Abstracts the difference between local and distributed message passing </li></ul></ul>
  9. 9. <ul><li>Runs on Yaws or Inets web server
  10. 10. MVC (Model-View-Controller) paradigm </li><ul><li>Model – data (stored in mnesia/dets tables) manipulation
  11. 11. Templates – XHTML files and templating engine
  12. 12. Controller – Erlang functions called on dispatching rules
  13. 13. Dispatcher – Request routing based on regexp
  14. 14. Request dictionary </li></ul><li>Reusable components (“ecomponent”)
  15. 15. Caching system
  16. 16. Annotations </li></ul>
  17. 17. Directory structure <ul><li>For creating the directory tree of a new application, ./bin/add is executed which generates the directories:
  18. 18. config –dispatch.conf, errors.conf, projects.conf, server specific .conf
  19. 19. docroot –static files and folders (except html templates), e.g : js, css, img
  20. 20. lib –framework applications and applications created by the user
  21. 21. log –logs created while running in embedded mode and server specific log
  22. 22. pipes –OS pipes for cummunicating with the shell while in embeded mode
  23. 23. priv –project specific data (usually static html)
  24. 24. release –separated subdirectories for each release version
  25. 25. templates –all the template files </li><ul><li>templates/cache – cached files </li></ul></ul>
  26. 26. Generator script (bin/generate.erl) <ul><li>Module responsible for generating the boilerplate code
  27. 27. General format: ./bin/generate.erl TYPE -argument_name -argument_value
  28. 28. Generating a controller: </li><ul><li>./bin/generate.erl controller --app app_name --name name_of_the_generated_model --functions (fun1, fun2)
  29. 29. ./bin/generate.erl model --app app_name --name name_of_the_generated_model --hrl name_of_the_header_file </li><ul><li>Generates a file named wtype_name where 'name' is the given arg
  30. 30. Generates basic CRUD functionality for the given header </li></ul></ul></ul>
  31. 31. Dispatcher Dispatching types <ul><ul><li>Static dispatching: serving static content, like xml pages, media or javascript. The controller is not accessed. The server first searches for the file in the “templates” dir, afterward in the “docroot” dir. For faster retrieval of static content, they should be placed in the docroot dir and enoent should be placed instead of File </li><ul><li>{static, Regexp, File} | {static, Regexp, enoent} </li></ul><li>Dynamic dispatching: the controller will handle the URL requests allowing specific content to be created or retrieved on demand </li><ul><li>{dynamic, Regexp, {Module, Function}} </li></ul><li>Alias dispatching: if the URL matches the Regexp, the rule of NewURL will be triggered </li><ul><li>{alias, Regexp, NewURL} </li></ul><li>Delegates: passing the URL to another dispatch config file, only helps in structuring the application </li><ul><li>{dynamic, delegate, Regexp, File} </li></ul></ul></ul>
  32. 32. Dispatcher evaluation order <ul><li>Docroot content is served (files that point to 'enoent')
  33. 33. Dynamic entries are matched with their URLs
  34. 34. Static routes are matched
  35. 35. If no patterns are matched, a 404 error page is displayed </li></ul>
  36. 36. Request dictionary <ul><li>Temporary storage – created for each HTTP request, lives as long as the request lives
  37. 37. Provides an easy to use API for setting and getting values from the dictionary
  38. 38. Used for retrieving GET/POST request data from the query string and also used by the expanding templates
  39. 39. API: </li><ul><li>wpart:fget(“post:user_address”).
  40. 40. wpart:fget(“get:page_number”).
  41. 41. wpart:fset(“user”,[[{“name”,”bogdan”},{age,21}],[{“name”,”marian”},{age,18}]]). </li></ul></ul>
  42. 42. Request dictionary Sample browser request {<0.3110.0>,[ {&quot;get&quot;,[]}, {&quot;post&quot;,[ {&quot;action_type&quot;,&quot;add&quot;},{&quot;id&quot;,[]},{&quot;type&quot;,&quot;user&quot;},{&quot;user_password&quot;,&quot;nuitizic&quot;}, {&quot;user_phone&quot;,&quot;07273447823&quot;},{&quot;user_cnp&quot;,&quot;1901231231723&quot;}, {&quot;user_lastname&quot;,&quot;alex&quot;},{&quot;user_firstname&quot;,&quot;popescu&quot;} ] }, {&quot;__https&quot;,false}, {&quot;__cookies&quot;,[{&quot;eptic_cookie&quot;,&quot;nonode@nohost-7985065742948673537&quot;}]}, {&quot;session&quot;,[{&quot;user_id&quot;,&quot;1111111111111&quot;}, {&quot;groups&quot;,[&quot;admin&quot;]}]}, {&quot;__path&quot;,&quot;admin/add&quot;}, {&quot;__cookie_key&quot;,&quot;nonode@nohost-7985065742948673537&quot;},{&quot;__ip&quot;,{127,0,0,1}}, {&quot;__controller&quot;,controller} ] }
  43. 43. Controller <ul><li>Responsible for handling the user's requests
  44. 44. Has the arity 1, getting a proplist (list of key-value pairs)
  45. 45. Handles user input, model manipulation, etc.
  46. 46. Must return a tuple, which tells the template what to do: </li><ul><li>{redirect, URL} | {content,html,Data} | {content,text,Data} | {json,Data} | {template,Template} | {error,Code} | {headers, Headers, RetVal} where : </li><ul><li>Headers is a list of headers, of the form {cookie, CookieName, CookieValue, CookiePath, CookieExpDate}
  47. 47. Retval is one of the previous touples </li></ul></ul></ul>
  48. 48. Templating Engine <ul><li>The view is represented by a regular XHTML file with a few namespaces defined.
  49. 49. The most commonly used namespace, wpart, is always expanded by the framework . When the parser meets <wpart:lookup … /> for example, it will call the function wpart_lookup:handle_call/1, with the whole xmerl parsed tag as an argument. </li></ul>
  50. 50. Templating Engine Wpart tags <ul><li>wpart:choose provides “if” functionality; it contains the tags: </li><ul><li><wpart:when test=”...”> … </wpart:when>
  51. 51. <wpart:otherwise> Something else </wpart:otherwise>
  52. 52. The test is an expression of the form test=”1 + 1 eq 2”, where the operators can be: </li><ul><li>eq, neq, lt, le, gt, ge (for =:=, =/=, <, >, =<, >=) </li></ul></ul></ul>
  53. 53. Templating Engine Wpart tags <ul><li>wpart:list provides “for” functionality; it contain the attributes: </li><ul><li>select, specified what part of the list we want, attributes: </li><ul><li>map – renders every element in the list
  54. 54. head – renders only the first element
  55. 55. tail – renders the last element of the list
  56. 56. filter – has an attribute named “pred” for filtering the list
  57. 57. find – the first element of the list where “pred” is evaled to true
  58. 58. sort – sorts according to the “pred” attribute </li></ul><li>as, every element of the list from inside the wpart:list will be known as the value of this attribute </li></ul></ul>
  59. 59. Templating Engine Wpart tags <ul><ul><li>list, specifies the list from the request dictionary that we want to traverse
  60. 60. pred, predicate used for some of the select tags, it's optional
  61. 61. e.g. : </li></ul></ul><wpart:list select=”map” list=”students” as=”student”> <span class=”name”><wpart:lookup value=”student:name”/></span> <span class=”group”><wpart:lookup value=”student:group”/></span> </wpart:list>
  62. 62. Templating Engine Wpart tags <ul><li>wpart:lookup provides access to a value from inside the request dictionary, it contains the attributes: </li><ul><li>key, the key from the dictionary that we are looking for
  63. 63. format, optional formatters
  64. 64. type, can have the values “text” (default) or “html”, setting “html” turns off html-escaping and can be dangerous
  65. 65. e.g : <wpart:lookup key=”name”/> <wpart:lookup key=”student:name”/> </li></ul></ul>
  66. 66. Templating Engine (wtpl) <ul><li>Tool for faster building of html pages, by expanding or replacing content from other template files
  67. 67. Allows building of websites from small chunks of html
  68. 68. It helps with : </li><ul><li>Code re-usage
  69. 69. Not writing the same thing multiple times
  70. 70. Updating the common part of the pages only one time </li></ul></ul>
  71. 71. Templating Engine (wtpl) Wtpl tags <ul><li><wtpl:include name=Name /> - the location where the wtpl:content with the corresponding name will be placed
  72. 72. <wtpl:parent path=Path /> - specifies which template will be filled with the content provided by the wtpl:content content
  73. 73. <wtpl:content name=Name/> - content that will fill the wtpl:include tag which has the same name as the tag 'name' attribute, in the file specified by wtpl:parent </li></ul>
  74. 74. Templating Engine wpart_gen <ul><li>Enables building of HTML code directly from within Erlang modules.
  75. 75. wpart_gen:load_tpl(Namespace, Name, Path) – loads the html snippet specified by Path, and saves it in the memory under the key {Namespace,Name}
  76. 76. Tpl = wpart_gen:tpl_get(Namespace,Name) – gets the snippet from memory
  77. 77. wpart_gen:build_html(Tpl,Values) – builds the template file with the values from the list Values </li></ul>
  78. 78. Templating Engine wpart_gen – Template Format Anonymous slots: <!-- HTMLCode --> <% slot %> <!-- HTMLCode --> Named slots: <!-- HTMLCode --> <% name_of_the_slot %> <!-- HTMLCode -->
  79. 79. Templating Engine wpart_gen – Passed Values Anonymous slots: [Value | … ] All fields must be filled. Named slots: [{ “slot_name”, Value} | … ] The unfilled slots will remain empty.
  80. 80. Controlling cache <ul><li>persistent – data cached this way is not removed until the server is restarted or the cache is invalidated
  81. 81. timeout – every T minutes the cache is traversed and expired content is removed, each URL can have a different timeout.
  82. 82. no_cache </li></ul>
  83. 83. Controlling cache <ul><li>The caching configuration is made directly from the dispatch configuration file. E.g. : </li><ul><li>{dynamic, “^/index/?$”,{main,home},[{cache,persistent}]}.
  84. 84. {static, “^/faq$”,”doc/faq.html”,[{cache,normal}]}.
  85. 85. {dynamic, “^/posts/?$”,[{cache,{timeout,30}}]}.
  86. 86. {dynamic, “^/the_time/?$”,[{cache,no_cache}]}. </li></ul></ul>
  87. 87. Controlling cache <ul><li>For controlling cache based on aspects other than URL, the tuple {is_cachable_mod, my_mod} should be placed in the configuration(config/project.conf) file.
  88. 88. Before processing any request, the function my_mod:is_cachable() will be called
  89. 89. The function is_cachable() should return </li><ul><li>true if the request should be cached under the URL key
  90. 90. {true,NewId} , if the request should be cached under NewId
  91. 91. false , if we don't want to check the cache </li></ul></ul>
  92. 92. Annotations <ul><li>Available since version 1.3
  93. 93. Allows separation of the target function from different types of functions, non-domain specific wrappers.
  94. 94. e.g.: before making a post to a blog you should be logged in and your message should be checked for “bad words” maybe; after posting the message the cache should be invalidated and your post-count could be modified.
  95. 95. Usual dataflow mechanisms can be used but it could make the code harder to read and repetitive. </li></ul>
  96. 96. Annotations Controller Syntax % keeps the stored macros -include_lib(“blog/include/utils_annotations.hrl”). % before posting ?AUTHENTICATE([“administrator”]). ?CHECK(blog_post). % after posting ?INVALIDATE(posts). ?UPDATE(user). post(_Args) -> ...
  97. 97. Annotations Annotation Module Syntax ?BEFORE. %% ?AFTER. annotation_name(AnnotationArg, TargetModule, TargetFunction, TargetFunctionArgs | TargetFunctionResult) -> Result Result :: {proceed, NewFunctionArgs | NewResult} | {skip, NewResult} | {error, {ErrorMod, ErrorFun, ErrorArgs}}
  98. 98. Annotations Annotation Module Example ?AFTER. check (blog_post, _Mod, _Fun, _Args) -> case is_bad(wpart:fget(“post:msg”)) of true-> {skip, {redirect, “”}}; _-> {proceed, _Args} end.
  99. 99. e_components <ul><li>e_components is a mechanism for extending the capabilities of the framework
  100. 100. Erlang-Web comes with e_components for authentication, mnesia backup and for generating rss feeds
  101. 101. To search for an e_component we can run ./bin/e_component search component_name, command that will list all available components matching the name and their description
  102. 102. To install an e_component we run ./bin/e_component install component_name, the e_component is now copied in the lib folder of our application. ./bin/compile is now required, in order to compile the component's source files. </li></ul>
  103. 103. e_components <ul><li>One more thing is required in order to use the component in our project: inserting a new tuple in the configuration file: </li><ul><li>{ecomponents, [{e_auth, []}, {e_auth_dets, []} ]}. </li></ul><li>After restarting the server we can verify that the components are running, by executing the function that lists all running applications : application:which_applications() </li></ul>
  104. 104. e_components <ul><li>e_components is a mechanism for extending the capabilities of the framework
  105. 105. Erlang-Web comes with e_components for authentication, mnesia backup and for generating rss feeds
  106. 106. To search for an e_component we can run ./bin/e_component search component_name, command that will list all available components matching the name and their description
  107. 107. To install an e_component we run ./bin/e_component install component_name, the e_component is now copied in the lib folder of our application. ./bin/compile is now required, in order to compile the component's source files. </li></ul>