version 0.1.1-dev
Gimlet Cocktail is a micro web application framework for OpenResty[2] written in Moonscript. The hope is that it's useful, modular, and makes writing web applications (especially RESTful ones) quick and fun.
-
First thing to do is to install Moonscript [1]
-
To use the command line tool, you'll need a couple more dependencies:
- lua_cliargs >= 2.1 - For command line argument parsing.
- luafilesystem >= 1.5 - For ensuring the web server is running from the correct location.
-
Then you should make sure to either have OpenResty installed
-
(Alternatively) Install wsapi, wsapi-xavante, & xavante.
-
Create a file named app.moon with the following code:
import get, run from require 'gimlet.classic'
get '/', ->
'Hello world!'
run!
- Now you can compile the code with
moonc app.moon
- You can run use the gimlet command to start the server
gimlet app
[2]
You will now have a Gimlet application running on your web server of choice on http://localhost:8080
[1] All dependencies can be installed via LuaRocks.
[2] The default is use use OpenResty. Xavante can be used by using gimlet -x app
gimlet.classic
tries to provide reasonable defaults for most web applications. The general pieces are requiring gimlet.classic
, setting up any additional middleware, adding items to be passed to the routes, setting up your routing information, and running the application.
-- Pull in the Classic Gimlet
classic = require 'gimlet.classic'
-- Optionally define a variable to be available to all requests
classic.map "world", 'World'
-- Define a middleware to use
classic.use (require 'gimlet.render').Render!
-- Define a route '/' with params
classic.get '/', (params) ->
params.render.json hello: params.world
-- Run the Gimlet application
classic.run!
Handlers are how you get things done in Gimlet (as they are in Martini.) A handler is a any callable function.
classic.get '/', ->
print "hello world"
Handlers can return a string value and that will be sent back as a simple HTTP HTML response.
classic.get '/', ->
"hello world" -- HTTP 200 : "hello world"
If the first option is numeric, it changes the HTTP response code.
classic.get '/', ->
418, "i'm a teapot" -- HTTP 418 : "i'm a teapot"
If the first option is a table, other things about the HTTP response can be changed, such as Content-Type, headers, and the status.
classic.get '/', ->
'Content-Type': 'application/json', status: 401, [[{"error": "you're not authorized to access content"}]]
The handlers can optionally take a single table parameter.
classic.get '/', (p) ->
p.utils.now!
The following are mapped to the table by default:
- gimlet - An instance of the Gimlet class
- request - An instance of the HTTP request object
- response - An instance of the HTTP response object.
- utils - An instance of some utility functions
In addition to these, route globs and named parameters are mapped to the parameter as well. See Routing for more information on this.
In Gimlet, a route is an HTTP method paired with a URL-matching pattern. Each route can take one or more handler methods:
classic.get '/', ->
-- show something
classic.patch '/', ->
-- update something
classic.post '/', ->
-- create something
classic.put '/', ->
-- replace something
classic.delete '/', ->
-- destroy something
classic.options '/', ->
-- http options
classic.not_found ->
-- handle 404
Routes are matched in the order they are defined. The first route that matches the request is invoked.
Route patterns may include named parameters:
classic.get '/:name', (p) ->
'hello ' .. p.params.name
Routes can be matched with globs:
classic.get '/**', (p) ->
'hello ' .. p.params[1]
Route groups can be added too using the group method:
classic.group '/books', (r) ->
r\get '', get_books
r\get '/:id', get_book
r\post '/new', new_book
r\put '/update/:id', update_book
r\delete '/delete/:id', delete_book
Services are objects that are available to be injected into a handler's parameters table.
db = my_database!
classic.map "db", db -- the service will be available to all handlers as -> (p) p.db
-- Alternative
classic.map :db -- Same as above, but you can pass a table with a single {k: v} into map
-- ...
classic.run!
gimlet.classic
automatically serves files from public
relative to the main module.
You can add additional directories to serve as well:
import Static from require 'gimlet.static'
classic.use Static '/css'
Note the '/' at the beginning is needed to path match the url. This may change in the future.
If you plan on serving images from this middleware, you should install mimetypes
Alternatively, you can let the HTTP server handle static files with gimlet -s static_dir app
Middlware handlers sit between the incoming http request and the router. They are, in essence, no different than any other handler in Gimlet. You can add a middleware handler to the stack with:
classic.use ->
-- do middleware stuff
You also have full control over the middleware stack with the Gimlet\handlers
function. This will replace all handlers that were previously set:
classic.handlers middleware1, middleware2, middleware3
Middleware handlers tend to work well for things like: logging, authorization, authentication, sessions, errors, or anything else that needs to happen before and/or after an HTTP request.
During a middleware handler call, the middleware can optionally call coroutine.yield
. This allows somet things to happen before and after the request.
classic.use ->
print "before a request"
coroutine.yield!
print "after a request"
- Render - Handles rendering JSON & HTML templates.
Code reloading is accomplished by using gimlet -r
It works well with OpenResty. However, Xavante seems to have some issues currently.
Up until this point, Moonscript has been assumed for everything. There's support for using Lua; however, this isn't well tested.
local classic = require 'gimlet.classic'
classic.get('/', function()
return 'Hello world!'
end)
classic.run()
Gimlet Cocktail is inspired by projcets like Martini and Sinatra. Some code is heavily based off Martini as well.