Data Serving

http Server

To share data with the outside world, we can run an http server. It will take requests from clients (e.g. web browsers) and join them with matching handlers which we can write to construct responses. Here's a short program, saved as server1.ra, to serve some text:

import("http")

route := {path:str,   relgen:str}{ 
         ["/",        "index_handler"]
}

index_handler := {
    method:str, path:str, 
    response:tuple{header:{k:str, seq:int, v:str}, status:int, body:str},
} begin
    response := http.response{*, body := "Hello world, wide web"}
    yield
end


main := {} begin
    res := http.serve(route:=route)
    print(res)
end

It imports the http module and then defines a route relvar to map http paths (and methods) to handler names. The main function is set to start the server using the http.serve relation generator. The route relvar is passed into http.serve() and, once started, it will compose responses from incoming requests and handlers. It will keep accepting requests and returning the composed responses to clients until it's stopped.

We have one handler here, which we've named index_handler, to work with any requests for the / path. This handler sets the response body to some text and then yield returns it. The text isn't a complete web-page but the client browser should still show it.

Run the server program:

$ ra server1.ra

Visit http://localhost:8080 in your browser and you should see:

Hello world, wide web

Press Ctrl+C to stop the server1.ra program and then Ctrl+D to exit and stop the http server.

To avoid having to remember or re-type the handler heading each time, you can use the http.hh handler-heading with attr_types like so:


...
index_handler := {attr_types(http.hh)} begin 
...

We'll use this from now on.

Next we'll see how we can build more complete responses by using templates and passing parameters to them.