All Projects → JuliaWeb → Mux.jl

JuliaWeb / Mux.jl

Licence: other
Middleware for Julia

Programming Languages

julia
2034 projects

Projects that are alternatives of or similar to Mux.jl

Router.cr
Minimum High Performance Middleware for Crystal Web Server.
Stars: ✭ 231 (+2.67%)
Mutual labels:  middleware, webserver
Twig
Twig - less is more's web server for golang
Stars: ✭ 98 (-56.44%)
Mutual labels:  middleware, webserver
restana
Super fast and minimalist framework for building REST micro-services.
Stars: ✭ 380 (+68.89%)
Mutual labels:  middleware, webserver
Pure Http
✨ The simple web framework for Node.js with zero dependencies.
Stars: ✭ 139 (-38.22%)
Mutual labels:  middleware, webserver
Restana
Super fast and minimalist framework for building REST micro-services.
Stars: ✭ 341 (+51.56%)
Mutual labels:  middleware, webserver
Rayo.js
Micro framework for Node.js
Stars: ✭ 170 (-24.44%)
Mutual labels:  middleware, webserver
Slim Session
A very simple session middleware for Slim Framework 2/3/4.
Stars: ✭ 200 (-11.11%)
Mutual labels:  middleware
Compression
Node.js compression middleware
Stars: ✭ 2,506 (+1013.78%)
Mutual labels:  middleware
Webpack Dev Middleware
A development middleware for webpack
Stars: ✭ 2,336 (+938.22%)
Mutual labels:  middleware
Alice
Painless middleware chaining for Go
Stars: ✭ 2,438 (+983.56%)
Mutual labels:  middleware
Jeff
🍍Jeff provides the simplest way to manage web sessions in Go.
Stars: ✭ 223 (-0.89%)
Mutual labels:  middleware
Toa
A pithy and powerful web framework.
Stars: ✭ 220 (-2.22%)
Mutual labels:  middleware
Laravel Multisite
Multiple sites on one codebase
Stars: ✭ 214 (-4.89%)
Mutual labels:  middleware
Fiery
A flexible and lightweight web server
Stars: ✭ 203 (-9.78%)
Mutual labels:  webserver
Logarr
“Logarr” is a self-hosted PHP web app that consolidates, formats, and displays log and text files for easy analysis and monitoring.
Stars: ✭ 216 (-4%)
Mutual labels:  webserver
Httpkit
⚡️ High-level, High-performance HTTP(S) Clients/Servers in Reason/OCaml
Stars: ✭ 198 (-12%)
Mutual labels:  middleware
Caddy Authz
Caddy-authz is a middleware for Caddy that blocks or allows requests based on access control policies.
Stars: ✭ 221 (-1.78%)
Mutual labels:  middleware
Webpack Hot Middleware
Webpack hot reloading you can attach to your own server
Stars: ✭ 2,279 (+912.89%)
Mutual labels:  middleware
Iceoryx
iceoryx - true zero-copy inter-process-communication
Stars: ✭ 208 (-7.56%)
Mutual labels:  middleware
Voovan
Voovan是高性能异步通信、HTTP服务器和客户端通信、动态编译支持、数据库操作帮助类等工具的框架, 如果项目觉得不错, 请点一下 star, 谢谢
Stars: ✭ 221 (-1.78%)
Mutual labels:  webserver

Mux.jl

Build Status Build status codecov.io

Pkg.add("Mux")

Mux.jl gives your Julia web services some closure. Mux allows you to define servers in terms of highly modular and composable components called middleware, with the aim of making both simple and complex servers as simple as possible to throw together.

For example:

using Mux

@app test = (
  Mux.defaults,
  page(respond("<h1>Hello World!</h1>")),
  page("/about",
       probability(0.1, respond("<h1>Boo!</h1>")),
       respond("<h1>About Me</h1>")),
  page("/user/:user", req -> "<h1>Hello, $(req[:params][:user])!</h1>"),
  Mux.notfound())

serve(test)

You can run this demo by entering the successive forms into the Julia REPL. The code displays a "hello, world" at localhost:8000, with an about page at /about and another hello at /user/[your name].

The @app macro allows the server to be redefined on the fly, and you can test this by editing the hello text and re-evaluating. (don't re-evalute serve(test))

Note that serve(test) launches an asynchronous Task that will not prevent Julia from terminating. This is good at the REPL, but not always what you want. If you want Julia to wait for the task to finish, use wait(serve(test)).

Technical Overview

Mux.jl is at heart a control flow library, with a very small core. It's not important to understand that code exactly as long as you understand what it achieves.

There are three concepts core to Mux.jl: Middleware (which should be familiar from the web libraries of other languages), stacking, and branching.

Apps and Middleware

An app or endpoint is simply a function of a request which produces a response:

function myapp(req)
  return "<h1>Hello, $(req[:params][:user])!</h1>"
end

In principle this should say "hi" to our lovely user. But we have a problem – where does the user's name come from? Ideally, our app function doesn't need to know – it's simply handled at some point up the chain (just the same as we don't parse the raw HTTP data, for example).

One way to solve this is via middleware. Say we get :user from a cookie:

function username(app, req)
  req[:params][:user] = req[:cookies][:user]
  return app(req) # We could also alter the response, but don't want to here
end

Middleware simply takes our request and modifies it appropriately, so that data needed later on is available. This example is pretty trivial, but we could equally have middleware which handles authentication and encryption, processes cookies or file uploads, provides default headers, and more.

We can then call our new version of the app like this:

username(myapp, req)

In fact, we can generate a whole new version of the app which has username support built in:

function app2(req)
  return username(myapp, req)
end

But if we have a lot of middleware, we're going to end up with a lot of appX functions. For that reason we can use the mux function instead, which creates the new app for us:

mux(username, myapp)

This returns a new function which is equivalent to app2 above. We just didn't have to write it by hand.

Stacking

Now suppose you have lots of middleware – one to parse the HTTP request into a dict of properties, one to check user authentication, one to catch errors, etc. mux handles this too – just pass it multiple arguments:

mux(todict, auth, catch_errors, app)

Again, mux returns a whole new app (a request -> response function) for us, this time wrapped with the three middlewares we provided. todict will be the first to make changes to the incoming request, and the last to alter the outgoing response.

Another neat thing we can do is to compose middleware into more middleware:

mymidware = stack(todict, auth, catch_errors)
mux(mymidware, app)

This is effectively equivalent to the mux call above, but creating a new middleware function from independent parts means we're able to factor out our service to make things more readable. For example, Mux provides the Mux.default middleware which is actually just a stack of useful tools.

stack is self-flattening, i.e.

stack(a, b, c, d) == stack(a, stack(b, c), d) == stack(stack(a, b, c), d)

etc.

Branching

Mux.jl goes further with middleware, and expresses routing and decisions as middleware themselves. The key to this is the branch function, which takes

  1. a predicate to apply to the incoming request, and
  2. an endpoint to run on the request if the predicate returns true.

For example:

mux(branch(_ -> rand() < 0.1, respond("Hello")),
    respond("Hi"))

In this example, we ignore the request and simply return true 10% of the time. You can test this in the repl by calling

mux(branch(_ -> rand() < 0.1, respond("Hello")),
    respond("Hi"))(nothing)

(since the request is ignored anyway, it doesn't matter if we set it to nothing).

We can also define a function to wrap the branch

probability(x, app) = branch(_ -> rand() < x, app)

Utilities

Despite the fact that endpoints and middleware are so important in Mux, it's common to not write them by hand. For example, respond("hi") creates a function _ -> "hi" which can be used as an endpoint. Equally, functions like status(404) will create middleware which applies the given status to the response. Mux.jl's "not found" endpoint is therefore defined as

notfound(s = "Not found") = mux(status(404), respond(s))

which is a much more declarative approach.

For example:

  • respond(x) – creates an endpoint that responds with x, regardless of the request.
  • route("/path/here", app) – branches to app if the request location matches "/path/here".
  • page("/path/here", app) – branches to app if the request location exactly matches "/path/here"

Serving static files from a package

Please use AssetRegistry.jl to register an assets directory.

DEPRECATED: The Mux.pkgfiles middleware (included in Mux.defaults) serves static files under the assets directory in any Julia package at /pkg/<PACKAGE>/.

Integrate with WebSocket

You can easily integrate a general HTTP server and a WebSocket server with Mux. To do so, define two apps, one for regular HTTP requests, and another that will handle WebSocket connections.

Here is a complete example:

using Mux

# HTTP Server
@app h = (
    Mux.defaults,
    page("/", respond("<h1>Hello World!</h1>")),
    Mux.notfound());

# WebSocket server
@app w = (
    Mux.wdefaults,
    route("/ws_io", websocket_example),
    Mux.wclose,
    Mux.notfound());

function websocket_example(x)
    sock = x[:socket]
    while !eof(sock)
        str = String(read(sock))
        println("Received data: " * str)
        write(sock, "Hey, I've received " * str)
    end
end

# Serve both servers on the same port.
serve(h, w, 2333)

And finally, run a client, optionally in another process:

import Mux.WebSockets

WebSockets.open("ws://localhost:2333/ws_io") do ws
    write(ws, "Hello World!")
    data = read(ws)
    println(stderr, ws, " received: ", String(data))
end;

Now, if you run both programs, you'll see two Hello World messages, as the server sends the same message back to the client.

Using Mux in Production

While Mux should be perfectly useable in a Production environment, it is not recommended to use the Mux.defaults stack for a Production application. The basiccatch middleware it includes will dump potentially sensitive stacktraces to the client on error, which is probably not what you want to be serving to your clients! An alternative Mux.prod_defaults stack is available for Production applications, which is just Mux.defaults with a stderrcatch middleware instead (which dumps errors to stderr).

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].