• Stars
    star
    261
  • Rank 156,630 (Top 4 %)
  • Language
    Clojure
  • Created over 15 years ago
  • Updated almost 12 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

a micro web framework/internal DSL to wire Ring handlers and middlewares

Moustache

  (app ["hi"] {:get "Hello World!"})

Moustache is a micro web framework/internal DSL to wire Ring handlers and middlewares.

How micro is it?

Well, there’s only one macro you need to know: app.

Every other public var is public only because app needs it in its expansion.

Syntax

See syntax.html

Walkthrough

http://gist.github.com/109955

The app macro

A (app ...) form returns a Ring application (handler).

There’s currently four usages of app:

  • to wrap a Ring handler,
  • to define routes,
  • to dispatch on HTTP methods
  • and to render plain text.

Wrapping an existing Ring handler

  (app my-handler) ; identity, returns my-handler

You can simply wrap a handler into middlewares:


(app
middleware1
(middleware2 arg)
my-handler)
; equivalent to (→ my-handler (middleware2 arg) middleware1)
; ie (middleware1 (middleware2 my-handler arg))

Note that every usage of app supports middleware-wrapping.

Routes

Basics

With Moustache you don’t write routes as encoded uri (eg "/Thank%20you%20Mario/But%20our%20princess%20is%20in%20another%20castle"), you write vectors of decoded segments (eg ["Thank you Mario" "But our princess is in another castle"]).

  (app ["foo"] my-handler) ; will route requests to "/foo" to my-handler
  (app ["foo" ""] my-handler) ; will route requests to "/foo/" to my-handler
  (app ["foo" "bar"] my-handler) ; will route requests to "/foo/bar" to my-handler
  (app ["foo" &] my-handler) ; will route requests to "/foo", "/foo/", "/foo/bar" and "/foo/bar/baz/" to my-handler (and will chop "/foo" off from the uri)
  (app ["foo" name] my-handler) ; will route requests to "/foo/", "/foo/bar" to my-handler and bind @name@ (a local) to the matched segment (eg "" or "bar")
  (app ["foo" x & xs] my-handler) ; "/foo/bar/baz/bloom" will bind x to bar and xs to ["baz" "bloom"]

You can catch all URIs with the route [&]. If you don’t provide a handler for [&] and there’s no handler for a request Moustache sends a 404 (not found) response.

Route validation/destructuring

  (defn integer [s]
   "returns nil if s does not represent an integer
    (try 
      (Integer/parseInt s)
      (catch Exception e)))

  (app ["order" [id integer]] my-handler) ; for "/order/134" @id@ will be bind to 134 (not "134"), this route will not match "/order/abc".
  
  (app ["agenda" [[_ year month day] #"(\d{4})-(\d{2})-(\d{2})"]] 
    {:get [month "-" day "-" year " agenda"]})

Fall through

The routes are tried in order until one route matches the request uri and the associated handler does not return nil.

That’s why:

  (app 
    ["foo" &] (app ["bar"] handler1)
    ["foo" "baz"] handler2)

returns a 404 for /foo/baz: the nested app form returns a 404 for /baz and this 404 bubbles up.

You can prevent such behavior by writing:

  (app 
    ["foo" &] (app 
                ["bar"] handler1
                [&] pass)
    ["foo" "baz"] handler2)

Method dispatch

  (app
    :get handler-for-get
    :post handler-for-post)

You can add a catch-all using the :any keyword.

If you don’t specify a handler for :any, Moustache sends a 405 response (method not allowed).

Shorthands

When the right-hand form of a route or of a method dispatch is a (app ...) form, you can write the form as a vector: (app ["foo" &] (app ["bar"] handler)) can be shortened to (app ["foo" &] [["bar"] handler]).

Besides when the right-hand form is a method dispatch without middlewares you can write the form as a map: (app ["foo"] (app :get handler)) can be shortened to (app ["foo"] {:get handler}).

More Repositories

1

enlive

a selector-based (à la CSS) templating and transformation system for Clojure
Clojure
1,619
star
2

xforms

Extra transducers and reducing fns for Clojure(script)
Clojure
573
star
3

enliven

Enlive next: faster, better, broader
Clojure
243
star
4

seqexp

Regexp for sequences!
Clojure
241
star
5

parsley

a DSL for creating total and truly incremental parsers in Clojure
Clojure
200
star
6

macrovich

A set of three macros to ease writing `*.cljc` supporting Clojure, Clojurescript and self-hosted Clojurescript.
Clojure
163
star
7

sjacket

Structural code transformations for the masses.
Clojure
114
star
8

megaref

STM ref types that allow for more concurrency on associative values.
Clojure
95
star
9

spreadmap

Evil project to turn excel spreadsheets in persistent reactive structures.
Clojure
89
star
10

regex

a regex DSL for those who prefer verbose composable regexes to terse ones
Clojure
88
star
11

poucet

trace as data for Clojure/JVM
Clojure
86
star
12

confluent-map

A persistent confluent map for Clojure
Java
39
star
13

packed-printer

Compact pretty printer
Clojure
37
star
14

sqrel

The SQL library that won't drive you nuts.
Clojure
37
star
15

utils

useful functions and extensible macros
Clojure
36
star
16

indexed-set

A set implementation which supports unicity constraints and maintains summaries (indexes).
Clojure
31
star
17

replay

Instant test suites from repl transcript.
Clojure
26
star
18

cljs-js-repl

Upgradable self hosted clojurescript repl
Clojure
21
star
19

parsnip

parsley is dead, long live parsnip!
Clojure
17
star
20

boring

A tunnel-boring library
Clojure
11
star
21

enlivez

Clojure
8
star
22

dynvars

dynamic bindings in callback hell
Clojure
5
star
23

sandbox

expeiments, works in progress etc.
Clojure
4
star
24

advent2017

Clojure
2
star
25

trainings.geneva.2012

Ressources issues des formations Clojure données du 13 au 15 mai 2012
Clojure
2
star
26

berlin-tron

Clojure
1
star