6. A Simple JSON Server

The default data protocol of front-end JavaScript websites is JSON. When you’re writing a back-end service, handling JSON is becoming essential. This chapter will build a JSON server in ClojureScript.

In this recipe you use Clojure to create a simple JSON server. We create a new Clojure project, create an HTML page with JavaScript to post the JSON, and create a Clojure server in Compojure to receive the request and return a response. Then we’ll process and display that response in the HTML page’s JavaScript.

Assumptions

In this chapter we assume the following:

Image You know enough JavaScript to recognize a JSON post and receive (or are prepared to Google it to find out).

Image You have some familiarity with the JQuery library—so we don’t need to explain JQuery references like $.

Benefits

The benefit of this chapter is that you will get the foundational skills you’ll need when building a rich client application that sends data over the wire.

The Recipe—Code

Follow these steps:

1. Create a new Compojure project json-demo.

lein new compojure json-demo
cd json-demo

2. Include the following in your projects.clj file:

(defproject json-demo "0.1.0-SNAPSHOT"
  :min-lein-version "2.0.0"
  :dependencies [[org.clojure/clojure "1.7.0-beta2"]
                 [compojure "1.3.4"]
                 [ring/ring-defaults "0.1.5"]
                 [ring/ring-json "0.3.1"]]
  :plugins [[lein-ring "0.9.5"]]
  :ring {:handler json-demo.handler/app}
  :profiles
  {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
                        [ring/ring-mock "0.2.0"]]}})

3. Create a new file called /resources/public/postjson.html. In the file, put the following contents:

<html>
<head>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
  <form action="/a" id="jsonForm">
   <input type="submit" value="Submit a JSON post" />
  </form>
  <!-- the result of the json test will be rendered inside this div -->
  <div id="result"></div>

<script>
/* attach a submit handler to the form */
$("#jsonForm").submit(function(event) {

  /* stop form from submitting normally */
  event.preventDefault();

  var book = {
  "Title" : "The Adventures of Tom Sawyer",
  "Author" : "Mark Twain",
  "Year" : "1876"
  };

  var bookJSON = JSON.stringify(book)

  /* get some values from elements on the page: */
  var $form = $( this ),
  url = $form.attr( 'action' );

  /* Send the data using post */
  var postResult = $.post( url, { s: bookJSON } );

  /* Put the results in a div */
  postResult.done(function( data ) {
    console.log(data);
    var result = "";
    $(data).each(function(i,val){
      $.each(val,function(k,v){
        console.log(k+" : "+ v);
        result += k + " : " + v + "<br>";
      });
    });
    $( "#result" ).empty().append( result );
  });
});
</script>

</body>
</html>

4. Modify the file src/json_demo/handler.clj to contain the following:

(ns json-demo.handler
  (:require [compojure.core :refer :all]
            [compojure.route :refer [not-found]]
            [ring.middleware.resource :refer [wrap-resource]]
            [ring.middleware.params :refer [wrap-params]]
            [ring.middleware.json
            :refer [wrap-json-body wrap-json-response]]
            [ring.util.response :refer [response redirect]]))

(defn respond-to-json [s]
  ;used for debugging
  (println "post-parameters: " s)
  (response {:main-character2 "Huck"
             :main-character1 "Tom"}))

(defroutes app-routes
  (GET "/" []
         (redirect "/postjson.html"))
  (POST "/a" [s] (respond-to-json s))
  (not-found (str "no matching route found "
         "Try <a href='/postjson.html'>this</a>")))

(def app
  (-> app-routes
      (wrap-params)
      (wrap-resource "public")
      (wrap-json-body)
      (wrap-json-response)))

Testing the Solution

Next we test the solution.

1. On the command line, run

lein ring server 4000

Notice that a new web server window opens. (See Figure 6.1.)

Image

Figure 6.1 Opening the web browser

2. When you click the Search button, you get what is shown in Figure 6.2.

Image

Figure 6.2 Results of clicking the Search button

The results of the JSON are displayed in the browser window. In the server console, the following is displayed:

post-parameters:  {"Title":"The Adventures of Tom Sawyer","Author":"Mark Twain",
"Year":"1876"}

Notes on the Recipe

First we’ll take a look at the project.clj file. Of particular interest is the ring.json library and the lein-ring library. Also noteworthy is the :ring :handler that points to the app var.

The ring.json library is ring’s JSON library. The benefit of this is that you can wrap the routes and have input and output converted to JSON.

The lein-ring plug-in enables you to start a ring server from the command line using Leiningen. This uses the :ring :handler reference to the app function as a hook into the code. The namespace symbol json-demo.handler/app tells us that the var is in the handler.clj file in the json-demo.handler namespace.

Then we’ll take a look at the postjson.html file. The first line we’re particularly interested in is the serialization of the JavaScript object to JSON:

var bookJSON = JSON.stringify(book)

Here we pass the JavaScript object book into a JavaScript method to convert it to JSON data. Then we send the JavaScript object to the server via a JavaScript http POST using the form information in the page, without actually submitting the whole page:

var postResult = $.post( url, { s: bookJSON } );

This will take the results of the post and store it in the var posting. If we hadn’t wrapped the response from the server in JSON we might have to use jQuery to parse the JSON response, but this has been taken care of by the server. We have a JavaScript object, postResult, containing our JSON object tree.

Then we iterate through the map in the JSON and append it to the DOM in a div:

postResult.done(function( data ) {
 console.log(data);
 var result = "";
 $(data).each(function(i,val){
   $.each(val,function(k,v){
     console.log(k+" : "+ v);
     result += k + " : " + v + "<br>";
   });
 });
 $( "#result" ).empty().append( result );

Now we’ll look at the handler.clj file. The lines we’re particularly interested in are the handler for the JSON:

  (POST "/a" [s] (respond-to-json s))

This hands the response off to the respond-to-json method. Inside the respond-to-json method we convert the JSON string to a Clojure map and print it:

 (println "post-parameters: " s)

Then we construct a new JSON result to send back. This is a map with two entries that will get converted to a JSON string.

  (response {:main-character2 "Huck"
             :main-character1 "Tom"}))

Also of interest are the routes. The first (GET "/" [] route will redirect the browser to our .html page, which can lead to a better user experience. The (not-found route will return a simple response prompting the user to go to the .html page.

(defroutes app-routes
  (GET "/" []
    (redirect "/postjson.html"))
  (POST "/a" [s] (respond-to-json s))
  (not-found (str "no matching route found "
    "Try <a href='/postjson.html'>this</a>")))

Conclusion

In this chapter you saw how to create an HTML file to pass JSON from JavaScript. Then we set up a Compojure server to receive the JSON post, parse it, and display it on the HTTP response.

The next things to investigate on your own are two ways to send data over the wire—using EDN and Transit. EDN is a ClojureScript alternative to JSON that allows for richer serialization and deserialization of Clojure and ClojureScript values. Transit has similar goals to EDN but makes use of the parsing performance of the JSON implementations built into the browser.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.163.250