Getting Started

Jaxer's design makes writing Javascipt on the client and server as seemless as possible. Javascript can be written on the server like you would write on the client. When a page is requested, Jaxer will look through the page for any server calls, and create callbacks on the client to be able to call the server with a simple command. Jaxer does this by defining where the Javascript is being run. By default there are three options:

  1. On the Client
  2. On the Server
  3. As a Server-Proxy

Client side Javascript is the standard Javascript you would write on the client. Server Proxy functions are functions that can be called from the client. And Server functions are functions that only run on the server. Though to be completely accurate, both "Server-Proxy" and "Server" are actually running on the server. The main difference between these two is that "Server-Proxy" functions can be called from the client, while no such functionality exists for the Server functions.

The effective application of this is in the case where you would want to use a database query on the server. Having this functionality available directly from the client is not the best idea in the world. So we have a Server-Proxy function that takes the arguments, performs a specific database query on the Server function, and then returns the results to the Client. You can see the example code for this below.

<!doctype html>
<html>

	<head>

		<title>Jaxer Server</title>
		<meta charset='utf-8'/>

		<script runat='server'>
		
			function queryDatabase(sql, args) {
				
				var params = {
					HOST: '127.0.0.1',
					USER: 'root',
					PASS: 'raspberry',
					NAME: 'test',
					PORT: 3306
				};

				var conn = new Jaxer.DB.MySQL.Connection(params);
				conn.open();

				var results = conn.execute(sql, args);

				conn.close();

				return results;
			}

		</script>

		<script runat='server-proxy'>
		
			function addArticle(text) {
				
				var sql = "INSERT INTO Articles (text) VALUES ?";
				var args = [text];
				var res = queryDatabase(sql, args);
				return res ? true : false;

			}

		</script>

	</head>

	<body>

		...

		<textarea id='textarea'>Hello, World</textarea>

		<script>
			
			var textarea = document.getElementById('textarea');
			var articleText = textarea.value;
			var added = Jaxer.async.addArticle(articleText);

			// Jaxer.async.queryDatabase can't be called directly
		
		</script>

	</body>

</html>

Including Server Files

In the above example we include the Server and Server-Proxy server functionaility included in the same file as the HTML. So how do we break apart scripts so they can be included as different files? The answer is that Server Side Javascript files can be included via 'src' attributes just like you would with normal Client scripts. The difference is that Server-Side scripts can included database connection parameters, and other information that would better off not being visible to the public at large. If you just included a script as a src tag, then the source code of the script can still be visible to the client if the path is requested from Apache directly. So to get around this problem, Jaxer includes the functionality that any Server Side source code placed inside a directory named jaxer-include will not be served by Apache. We can see this in the following example.

<!doctype html>
<html>

	<head>

		<title>Jaxer Server</title>
		<meta charset='utf-8'/>

		<script runat='server' src='jaxer-include/server_secure.js'></script>
		<script runat='server-proxy' src='dir/server_unsecure.js'></script>

	</head>

	<body>

		...

		<script src='js/client_script.js'></script>

	</body>

</html>

There are two more ways to include Server Side functions. One is to use a file url reference by define a script file with src='file:///opt/AptanaJaxer/private/session.js'. The other way is to define an 'App', of which use will be decribed in the Configuration page.

How does it Work?

Apache will pass '.html' to Jaxer, when they are called from the file server by a client. Jaxer will look over the page and look for any runat='server', or runat='server-proxy' script tags. If none of these tags exist, Jaxer will return the static content back to Apache as-is. Otherwise if those tags are found, Jaxer's Page Handler will have the page handled by the Script Processor.

The Script Processor will fullfill serveral functions. First it will compile the code and store it with a timestamp and a page id in a database that can be accessed by the server framework. Then it will edit the header of the requested page to include these parameters to be able to be requested from the server via callback from the client. The Script Processor will also mark functions as either "Server" or "Server-Proxy", so that only proxied functions will be created on the client, and more importantly be availabe for callback later. The Script Processor will also append the client framework to the page, and return it to Apache.

On the client all of the "Server-Proxy" defined functions will have callback definitions created in the Jaxer.async namespace. When a function is called, the client framework will take all of the arguments and serialize them into a JSON string. These arguments along with the calling page, timestamp, page id and requested method name are sent to server to request execution.

On the server, the Callback manager will accept these arguments as a string, and attempt to deserialize them. Once doing do the Callback Manager will request the server side code from the database to be executed and look at the flags on the requested function name. If the function name has not been defined as "server-proxy", the callback manager will return an error to the client. Otherwise the function is called, and the parameters from the client are passed in as arguments. Once the function has completed execution, the return value will be returned to the Callback manager, which will package the response to be returned to the client.

The client will get the response back from the server through the client framework, and automatically check for errors. If an error is found, the error will be returned as a value, so make sure to check for errors in applications. Otherwise the value returned from the function will be be resolved by a promise.