Home Up Back Forward Leave Message


Overview

The code is available for download from:

JSON handling in Ruby

JSON handling is build in Ruby and relatively straight forward as can be seen:
    require "json"

    logonstr = {:username => "daffy", :password => "duck"}
    jsondata = JSON.generate(logonstr)

    logonstr2 = JSON.parse(jsondata)
First a map is created with our data (this is similar to an object without the hassle of declaring one and works good enough for simple cases). Then we generate the JSON representation (which will produce {"username": "daffy", "password": "duck"}). To do the inverse we just pass the JSON to JSON.parse which will generate a representation in Ruby. Note that JSON objects are parsed to maps.

If however we have a real Ruby class that we want to convert to JSON we can add a to_json method to the class where we specify how to produce something that the JSON generation can handle. For example:
    class Message
        attr_reader :messageid, :username, :message
        def initialize(messageid,username,message)
            @messageid = messageid
            @username = username
            @message = message
        end

        def to_json(*options)
            {:messageid => self.messageid, :username => self.username, :message => self.message}.to_json(*options)
        end
    end

    msg = Message.new(1,"daffy","Hello from me!")
    jsonst = JSON.generate(msg)
All I've done here is to create a map representation of the object because JSON.generate knows how to handle maps.

HTTP handling of requests

For the handling of HTTP request on the server side I make use of "webrick" which is standard available with Ruby and which is more than adequate for what I'm trying to demonstrate here.
    require "webrick"

    class LogonHandler < WEBrick::HTTPServlet::AbstractServlet
        def do_POST (request, response)
            logon = JSON.parse(request.body())
            response.status = 200
            response['Content-Type'] = 'application/json'
            response['Access-Control-Allow-Origin'] = '*'

            if $users.key?(logon["username"]) && $users[logon["username"]].password == logon["password"]
                user = $users[logon["username"]]
                sesskey = Time.now.to_i*100+user.userid
                $sessions[sesskey] = user
                response.body = JSON.generate({:status => true, :data => sesskey})
            else
                response.body = JSON.generate({:status => true, :data => "Invalid credentials"})
            end
        end
    end

    server = WEBrick::HTTPServer.new(:Port => 8080)
    server.mount "/logon", LogonHandler
    trap("INT") {
        server.shutdown
    }
    server.start    
One create a new HTTPServer for the specified port then you mount all the route handlers (in our case the function calls of the microservice) then you add a trap for serious errors in which case the server must shutdown. Last you start the server to start serving.

The handlers are classes inherited from HTTPServlet::AbstractServlet (of webrick obviously) and although there are different function that one can override for the various methods we only override the do_POST function. Two parameters are passed to the handler request and response and you can access all you need through them.

HTTP handling of calls

The calling of a service is just as easy:
    def callService(call,data)
        uri = URI.parse("http://localhost:8080/" + call)
        header = {'Content-Type': 'application/json'}
        http = Net::HTTP.new(uri.host, uri.port)
        request = Net::HTTP::Post.new(uri.request_uri, header)
        request.body = data.to_json
        response = http.request(request)
        return JSON.parse(response.body())
    end    
One generates an URI by parsing the calling url. You create the header (as a hash map) then you create a new HTTP connection to the server, then you start the POST and you send the body as well. Now you request the results and take the body from the response.