lfe-mug / lmug

LFE HTTP Server Abstraction and Web Application Middleware Infrastructure
20 stars 3 forks source link

lmug

Build Status LFE Versions Erlang Versions Tags

LFE HTTP Server Abstraction and Web Application Middleware Infrastructure

Project Logo

Contents

Introduction

lmug is an LFE web applications library inspired by Clojure's Ring.

lmug allows web applications to be constructed of modular components that can be shared among a variety of applications -- regardless of which web server, web framework, or HTTP client is used. This is possible by providing standard abstractions for:

For an overview, be sure to read the core concepts document. For more details, see the lmug specification.

Why?

Using lmug as the basis for your web application has a number of benefits:

If all goes well, lmug will be the de facto standard, the base upon which one will write web applications in LFE. Higher level frameworks could then use lmug as its HTTP foundation.

Installation

Just add it to your rebar.config deps:

{deps, [
    ...
    {lmug, "0.2.8}
  ]}.

And then do the usual:

rebar3 compile

Documentation

Usage

The usage examples below are done from the REPL:

rebar3 lfe repl

Simple Example

Ordinarily you would use lmug middleware in a project that was running a supported web server and which included the lmug adaptor for that web server. Below is an example showing something similar to what you would have in an lmug web application: it demonstrates the use of multiple middleware modules (the no-op/identify middleware is used as filler, to help demonstrate more middleware). If you are familiar with Clojure's Ring library, then this will look very familiar (though with a Lisp-2 flavour ...):

lfe> (set app (clj:-> (lmug:app)
                      (lmug-mw-request-id:wrap)
                      (lmug-mw-content-type:wrap)
                      (lmug-mw-status-body:wrap)))

Then, to run it, simply do the following:

lfe> (funcall app (http.request:new "http://localhost/tune.mp3"))

If you'd like to test middleware that requires more info in the request, you'll need to set that up. Let's take the request logger as an example. First, start up the logger:

lfe> (logjam:set-dev-config)
lfe> (application:ensure_all_started 'logjam)

Set up the app with the logger middleware:

lfe> (set app (clj:-> (app)
                      (lmug-mw-log-request:wrap #m(log-level notice))))

Now let's add details to the request that the logger will pull out:

lfe> (set req
      (http.request:new
       'get
       #"http://alice:sekr1t@localhost/tune.mp3"
       #""
       #m(#"user-agent" #"LFE REPL")))
lfe> (set req (mupd req 'remote-addr #"http://client.host"))
lfe> (funcall app req)
#M(status 200
   headers
     #M(#"Content-Type" #"audio/mpeg"
        #"X-Request-ID" #"116765989140096673677588780992994213888")
   body #"200")

Applications

The example usage above shows how one can chain together, but it doesn't illustrate real-world usage. The lmug library is meant to be used in conjunction with other lmug libraries (e.g., middleware for converting the body of a response to JSON) and web server adaptors (which allow you to write a single application that is runnable on any supported web server).

The simplest lmug adaptor is for the Erlang OTP http server. Here's an example of an lmug application running on OTP inets/httpd:

lfe> (set app (-> (lmug:response)
                  (lmug-mw-request-id:wrap)
                  (lmug-mw-content-type:wrap)))
lfe> (set opts '(#(server_name "lmuginets")
                 #(port 5099)))
lfe> (lmug-inets:start app opts)

Note that lmug-inets is from a separate project.

More Details

For a closer look at LFE examples, be sure read the usage details doc.

The Name?

What's with the name? Well, there was lfest ... the web app routing party. What would be at an LFE routing party? Lots of mugs, I guess. Full of tastey, hot LFE.

Really, though, a mug is topologically equivalent to a ring.

An lmug even more so.