Monday, November 22, 2010

Build a Web Application In Erlang


Hiii .... I am here with an intent to help you make a web application that uses :
  •  Erlang as the programming language
  •  Mnesia , a distributed , soft-real time dbms written in Erlang 
  •  Yaws , an asynchronous HTTP 1.1 web server written in Erlang and
  •  Erlyweb , a component-oriented web development framework again written entirely in Erlang
Isn't that amazing .... Well ... lets start with the installations first.
I assure you , its not gonna be messy at all to setup all these on your system and it would be fun to see the real power of erlang in each of them.Assuming that your working on Ubuntu our prerequisites would be :
  • Erlang SDK
  • Yaws and 
  • ErlyWeb
setup on the system.
Our very first requirement , the erlang SDK can be installed directly from your Synaptic Package Manager.
For installing YAWS , download and install from here  http://yaws.hyber.org/ and the latest ErlyWeb archive can be obtained from http://code.google.com/p/erlyweb/downloads/list?q=label:Type-Archive Just need to unzip it, and put the zip file's contents in your Erlang code path i.e.  "/usr/local/lib/erlang/lib".

Now , its time to create an application in ErlyWeb that we would be using in developing our Web Application.
Make a folder named 'appfolder'(or something of your choice)
Start your YAWS shell in the interactive mode using (sudo yaws -i) and type :

erlyweb:create_app("myapp", "/path_to_your_folder/appfolder").
Edit your yaws.conf file by adding a server configuration with the following docroot, appmod, and opaque directives as below :

docroot = /path_to_your_folder/appfolder/myapp/www
appmods = <"/myapp", erlyweb>
appname = myapp
So now we have built an application named 'myapp'and we can continue by typing "yaws:restart()." in the yaws shell.
To check , open your browser and point it at http://localhost:8000/myapp( your host/port may be different, depending on your Yaws configuration). You should see a page displaying the following :


Welcome to 'myapp', your new ErlyWeb app.
Let the Erlang hacking begin!


Having things setup, I’ll brief u about the application we would develop here.

Its gonna be a web app containing a login page and a home page from where onwards you can extend it as per ur needs. For our understanding of the database operations we would use a login table storing the userid and the password and for connecting it through the yaws server we would need one .yaws file that would parse  the incoming request from the html page and forward it to the required Action.

A simple Login.html page code is here. Paste this html page into the www folder of the erlyweb app


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<title>Login Page</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<link href="css/style.css" rel="stylesheet" type="text/css" />

<script language="JavaScript" type="text/javascript">


function check()

{
   
var uid=document.Loginform.uid.value.length
   
var pwd=document.Loginform.pwd.value.length
   
if(uid==0)
{
  
alert('Please enter userid')
  
return false;
}
   
if(pwd==0)
{
  
alert('Please enter Password')
  
return false;
}
   
if(pwd<6)
{
  
alert('Password may not less than 6 characters')
  
return false;
}
   
return true;

}


function verifyLogin()

{
   
var returnedval=check();
   
if(returnedval==true)
{
  
uid=document.Loginform.uid.value;
  
pwd=document.Loginform.pwd.value;
  
if (window.XMLHttpRequest)
        
{// code for IE7+, Firefox, Chrome, Opera, Safari
 
xmlhttp=new XMLHttpRequest();
        
}
  
else
    
{// code for IE6, IE5
         
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        
}
  
xmlhttp.open("GET","controller.yaws?action=loginaction&username="+uid+"&pwd="+pwd,true);
xmlhttp.onreadystatechange=function()
     
 {
          
if (xmlhttp.readyState==4 && xmlhttp.status==200)
   
{
  
a=xmlhttp.responseText;
if(a.trim()=="success")
window.location="Adminhome.html";
           
     else
      
  document.getElementById('loginfail').innerHTML="<b>Incorrect login id or password</b>";

}
           
}
         
xmlhttp.send(null);
      
 }


}

</script>

</head>



<body>
<div id="header_wrapper">
  
<div id="header">
   
<div id="site_title"> 
<a href="#"> <span></span> </a> </div>
      
<div id="menu">
    
<ul>
 </ul>

</div>
    
</div>
  
</div>
<div id="ex" >
   
<form name="Loginform" method=""  action="">
<table style="width: 98%;" >
<tr>
<td><strong><h4>Username&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;</h4></strong></td>
<td><input name="uid" type="text" size="50" style = "background:#E0FFFF;" /></td>
</tr>
<tr>
<td><strong><h4>Password</h4></strong></td>
<td><input name="pwd" type="password" size="50" style = "background:#E0FFFF;"/></td>

</tr><br>
<tr><td></td><td><div id='loginfail'></div></td></tr>
<tr>
<td></td>
<td><button type="button" style = "background:#3B9C9C;" onclick="verifyLogin()">Login</button></td>
</tr>
</table>
   
</form>

</div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<!-- end of content wrapper -->

<div id="footer_wrapper">
  
<div id="footer">
    
<div class="footer_box">
      
<div class="cleaner_h40"></div>
</div>
    
<div class="cleaner"></div>
  
</div>
</div>

</body>

</html>


Now moving to the database part , we need to create a table in our database 
mnesia and some functions to insert , retrieve and delete the data from on it.
On your part u’ll have to create a User.erl file and copy the code below . 
You can store it anywhere on your system.


-module(User).
-export([setup_and_start/0, insert/2, retrieve/1,delete/1]).

-include("/usr/lib/erlang/lib/stdlib-1.16.4/include/qlc.hrl").

-record(user, {username, password}).

setup_and_start() ->
mnesia:create_schema([node()]),
mnesia:start(),
mnesia:create_table(user, [{disc_copies, [node()]}, {attributes, record_info(fields, user)}]).
insert(uid, pwd) ->
Record = #user{username = uid, password = pwd},
F = fun() ->
mnesia:write(Record)end,
mnesia:transaction(F).
retrieve(uid) ->
F = fun() ->
mnesia:read({user, uid})
end,
{atomic, User} = mnesia:transaction(F),
User.
delete(uid) ->
F=fun() ->
mnesia:delete({user,uid})
end,
mnesia:transaction(F).


This file is gonna act as a DAL for our application. Now that we are done with the 
view and database part of the app , we would move forward to make a .yaws file .
This file would receive the request from our application running on the server and 
use the underlying Actions we would make to serve them.
Since ours is a small application and here we have only the login page we would 
have only one action , but if you develop your application  further you would need 
many more actions. Anyways lets have this .yaws file  at hand first.

<erl>
out(X) ->
A=yaws_api:parse_query(X),
{value,{Key,Value}}= lists:keysearch("action",1,A),
list_to_atom(Value) ! {self(), request, A},
receive{From, response, Response} ->
{html,Response}
end.
</erl>
You’ll have to store this .yaws file in the www folder of the erlyweb app you have 
built.Ahhh… now we’ll build the last part of the application , its an .erl file again that 
would act as a bridge between our yaws file and the DAL.
LoginAction.erl
-module(LoginAction).
-export([authuser/0,check/2,finalcheck/1,start/0]).
-import(user,[retrieve/1]).
-import(find,[getter/2]).
start()->
Pid1=spawn(fun authuser/0),
register(loginaction,Pid1).
authuser() ->
receive{From,request,Userdata} ->
Username1=find:getter("username",Userdata),
Pwd1=find:getter("pwd",Userdata),
Uid=list_to_atom(Username1),
Pwd=list_to_atom(Pwd1),
UserObj = user:retrieve(Username1),
case UserObj of[] -> 
From!{self(),response,"failure"},
io:format("empty"),
authuser();
Data -> 
io:format("~p",[Data])
end,
UserObj1=list_to_tuple(UserObj),
{{user,Uid_retrieved,Pwd_retrieved}}=UserObj1,
M=check(Pwd1,Pwd_retrieved),
From!{self(),response,M},
authuser()
end.
check(A,B)  when A==B -> "success";
check(A,B) -> "failure".
finalcheck(A)  when A==1 -> 1;
finalcheck(A) -> 0.

Another file Find.erl that is used in LoginAction.erl :
-module(find).
-export([getter/2]).
getter(RecString,RecObject) ->
{value,{Key,Value}}= lists:keysearch(RecString,1,RecObject),
Value.

So now finally .. the fun part i.e. run the app
Before you hit the browser start your Yaws server , compile your Erlyweb app and 
the .erl files we have made . And yes .. don't forget to insert some data into your 
LoginTable before running the application.
After having done all this just hit the following link

http://localhost:your_port_no/Login.html
Hope everything here must have helped you to some extent and all the best for 
future programming in Erlang.
Any suggestions or comments would be highly appreciated..