In-Database WebApps and REST Services

From MemCP
Jump to navigation Jump to search

In-Database WebApps are a huge game changer in REST API performance since the web app runs in the same context as the

REST Endpoint setup

You basically set up a REST endpoint by overwriting the http_handler variable in the global scope. Best practice is here to overload http_handler, store the old handler in old_handler and cascade the router with a prefix:

(define http_handler (begin
        (set old_handler (coalesce http_handler handler_404))

        /* here starts our custom router */
        (lambda (req res) (begin
                /* hooked our additional paths to it */
                (match (req "path")
                        (regex "^/my_prefix(.*)$" url subpath) (begin
                                (my_custom_handler req res path)
                        )
                        /* default */
                        (old_handler req res))

        ))
))

Now you can implement your own custom handler:

(define my_custom_handler (lambda (req res subpath) (begin
        /* print hello world */
        ((res "header") "Content-Type" "text/html")
        ((res "status") 200)
        ((res "print") "<h1>Hello World</h1>")
)))

Now you can query your endpoint with:

curl http://localhost:4321/my_prefix

In your custom handler, you can again parse your subpath to go to the single routes.

For more details, take a look at HTTP Server.

Including SQL or RDF queries in your custom REST endpoint

The SQL and RDF frontend have helper functions:

  • (parse_sparql schema query) to create the code for a SPARQL query
  • (parse_sql schema query) to create the code for a SQL query

Basically, you do the parsing and preparation outside of your HTTP handler in order to get the best performance out of prepared statements.

In the last step, you overwrite the query parameters as well as the function resultrow in your scope and then feed the code into eval:

(set my_code (parse_sql "my_database" "SELECT * FROM a"))
(set my_code (optimize my_code)) /* optionally run the optimizer over it */


/* now inside your HTTP handler: */
(set resultrow (res "jsonl")) /* this is the jsonl printer, but you can also use print or any lambda that takes a associative array with the results */
(eval my_code) /* execute query */

To read on how to handle the result object, take a look at: Lists and Objects

Example WebApps

You find a minimal example in the apps/ folder in the memcp sources.

You find a complex example of a RDF browser and whole template engine in:

https://github.com/launix-de/rdfop

Another example can be found in Websockets in MemCP