I have heard about Luvit for a long time, but I never get deep into it until recently. Luvit is a nodejs style lua libray with callback hell Asynchronous feature by Tim Caswell :) , it works well in most of the platforms, it's small and fast. It's really an interesting pramgraming language, and it's very easy to learn.

sample code of luvit:

local http = require('http')
http.createServer(function (req, res)
    res:writeHead(200, {['Content-Type'] = 'text/plain'})
    res:finish('Hello World\n')
end):listen(1337, '127.0.0.1')
print('Server running at http://127.0.0.1:1337/')

looks right like nodejs, right?

So I write a http framework library base on http module, it's luvit-mooncake. I'm trying to make it looks like connect or express framework of nodejs as possible as I can. and below is the demo usage of luvit-mooncake:


Intro:

Firstly, you can install luvit-mooncake with npm(yes, it's npm).

npm install mooncake

Then you can use mooncake in your lua file:

local MoonCake = require("./node_modules/mooncake")
local server = MoonCake()

-- route your application
server:get("/", function(req, res)
local content = "<p>Hello world from MoonCake</p>"
res:send(content, 200)
end)

server:start(8080)

Router:

you can route your application by calling server:get, server:post, server:put, server:delete directly like the sample code above, or you can add your route in this way:

server:route({
  ["get"] = {
    ["/users/:id"] = function(q, s)
      s:send("List User in Databases => " .. q.params.id)
    end
  }
})

avaialble method for route: "get", "post", "put", "delete" and "all", all means any method will be routed.

server:all("/hello", function(q, s)
  s:send("HELLO!")
end)

server:get("/admin", function(q, s)
  -- if user not login then
  s:redirect("/login")
end)

Response:

extra method for response res:

  • res:send
    res:send("Hello world!")
  • res:redirect
    res:redirect("/login")
  • res:render
    res:render('./view/index.html')
    see renderer below
  • res:status
    res:status(404):render("/view/404.html")

Request

You can get post data via req.body, get query data(such as "/users?page=1") via req.query.page

req.body

server:post("/posts/new", function(req,res)
  if req.body.title and req.body.content then
    print("new post")
    -- Save to DB:
    -- DB.save("post", {title = req.body.title, content = req.body.content})
    res:redirect("/posts")
  end
end)

req.params

server:get("/posts/:id", function(req, res)
    post = DB.find("post", {id = req.params.id})
    res:render("./view/post.html", {post = post})
end)

req.query

-- [GET] 'http://example.com/posts?page=4'
server:get("/posts", function(req, res)
    local page = req.query.page
    local skip = (page-1) * 10  --(10 post per page)
    res:render("./view/post-list.html", {
        post = DB.find("post", {
            skip = skip, 
            limit = 10
        })
    })
end)

renderer

create a html file with content like this:

{(header.html)} <!--import layout-->
<h1>Post List</h1>
<ul class='posts'>
<!--loop in content with lua syntax style. -->
{% for _, post in ipairs(posts) do %}
    <li>
    <h2>{{post.title}}</h2>
    <p>{{post.content}}</p>
    </li>
{% end %}
</ul>
{(footer.html)}

Template renderer powered by https://github.com/bungle/lua-resty-template/ , you can use it simply with res:render(TEMPLATEPATH, CONTEXT):

You can get more about render template syntax at: https://github.com/bungle/lua-resty-template/ .

server:get("/posts", function(req,res)
  -- get post list, render template.
  res:render("./view/post-list.html", {posts = DB.find("posts")})
end)

Static files:

One more thing, static server for static files!

root option means mount path, for example: "/static/" means url path will be "http://example.com/static/file.ext"

server:static("./public/", {
  root = "/static/",
  maxAge = 31536000 -- one year
})

Start Server:

Start your server: (server:start must be called lastly.)

server:start(8080)

Now you can open your browser with url: http://localhost:8080, here we go!

If you are interested in this project, please don't hesitate to let me know. All stars, comments, suggestions, contributions and Pull Requests are welcome :)

Fork me at github!