Version: 1.5.0
Ultra-Lightweight and modular Node.js like http server for NodeMCU.
Emphasizes code-as-a-config.
You love NodeMCU.
You don't want to learn the HTTP Protocol by heart.
You want a performant, über-simple yet exhaustive HTTP Server to serve websites.
Or maybe make your own custom API with webservices to execute remote commands.
It only gets a few seconds to get started.
You can read this document to learn the API, or just copy-paste one of the many samples ready for you in the appropriate section (forms, API, simple websites, etc...).
Can't find an example for your use case? Open an issue and let's figure it out together.
Tested under 2.0.0 and beyond. For NodeMCU 1.x, please check previous releases.
- ApiKey authentication module
- Easy service of static pages for your website
- Easy custom webservices with your own lua code
- GET, POST PUT, DELETE, OPTIONS, HEAD supported
- Handles gzipped files (.gz)
- Querystring, headers, method, form and body parser, easily accessible via req.params, req.headers, req.method...
- Completely customizable. Make your own plugin work in a few seconds.
- Inspired by Node.js Express API
- ESP8266 friendly : Can take between 15 and 20 Kb of memory for typical setups
- Good at handling concurrent-requests (request buffer implemented)
- Makes coffee, and cookies
Transfer the relevant content with any upload tool (we recommend using https://www.npmjs.com/package/nodemcu-tool).
A binary pre-compiled version is available in bin/ folder.
local espress = require 'espress'
local port = 80
-- Initialize a server creation (lazy)
local server = espress.createserver()
-- Declare desired plugins one by one
-- syntax is server:use("plugin" [, opts)
server:use("auth_api_key.lc", {apikey = "1234-abcd", includes = "/api"})
server:use("routes_auto.lc")
server:listen(port)
req = {
params,
headers,
method,
body
}
Holds the querystring or the forms parameters. Example: for http://host/api/computers?id=1234
local id = tonumber(req.params["id"]) -- 1234
If forms or querystring have multiple values for the same key, req.params.field will be a table with all values stored within.
Holds the request headers.
N.B.: header name is stored in lower-case
local contenttype = req.headers["content-type"] -- "application/json"
Contains the request method: "GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD"
Contains the body parsed into a string.
N.B.: You have the liberty of parsing this string to whatever you feel comfortable with. It is a voluntary choice not to parse it into JSON or other formats.
Sample parsers for form and json will be available soon in the samples.
Example :
res = {
conn,
send,
sendfile,
sendredirect,
statuscode,
headers,
addheader
}
The http connection socket. Please refer to NodeMCU's API for more details
Send payload in response and close connection after. The payload is sent in one chunk and length should not exceed 1460 bytes. If payload is bigger than 1460, please use res.sendfile instead.
Example:
local content = "{message: \"Hello world\"}"
res:send(content)
Send static file in response and close connection after. The payload is sent into multiple chunks of 1460 bytes, and should be used to process all static content.
Example:
res:sendfile("static/404-not-found.html")
Redirect user to another URL
Example:
res:sendredirect("/registration_success.html")
Sets the response http statuscode.
Example:
res.statuscode = 102
Contains the response headers. Use for read-only. To add or edit response headers, rather use res.addheader
Add or edit response header.
Example:
res.addheader("Content-Type", "application/json")
Available plugins are:
- auth_api_key : implementation for an Api-Key header-based authentication
- routes_auto : automatic routing using your /static and /routes sub-folders (recommended)
- routes_custom : to perform advanced routing
This plugin will intercept all requests and look for an X-Api-Key header OR an &api-key parameter in querystring.
Valid options for this plugin are:
- apikey: the desired apikey to secure
- includes: a uri prefix to which auth will be enabled (will exclude all others)
- excludes: a uri prefix to which auth will be bypassed (will include all others)
server:use("auth_api_key.lc", {apikey = "1234-abcd", includes = "/api"})
The following responses can be expected :
- 400 BAD-REQUEST if neither the X-Api-Key header nor the api-key parameter were provided
- 401 UNAUTHORIZED if the provided value does not match the one in the options {apikey = "1234-abcd"}
- Forward to next handler if everything went well
The plugin will automatically parse the request url and lookup for the corresponding files depending on their name.
Two kinds of content are supported :
Your webpages, css, images, and static content should be stored as static/filename.ext onto the NodeMCU filesystem.
For instance:
static/index.html
static/style.css
static/logo.png
static/script.js
Static files will be routed to http://host/
For instance http://host/logo.png will load the static/logo.png file
Your webpages, css, images, and static content should be stored as static/filename.ext.gz onto the NodeMCU filesystem.
For instance:
static/index.html.gz
static/style.css.gz
static/logo.png.gz
static/script.js.gz
Static Gzip files will be routed to http://host/
For instance http://host/logo.png will load the static/logo.png.gz file
Your API scripts should be stored as routes/path.method.lc (example: routes/foo.post.lc, routes/bar.get.lc ...) and should hold the following function:
return function(req, res)
-- your code here
res:addheader("Content-Type", "application/json; charset=utf-8")
res:send("{foo:\"bar\"}")
-- end of your code
end
The scripts will be available under the following uri: host/api/path
For instance:
routes/foo.get.lc <=> [GET] http://host/api/foo
routes/bar.post.lc <=> [POST] http://host/api/bar
Don't forget to take a look at the req and res API.
Samples are available into the sample/ subfolder
This plugin uses a node.js like route handler.
Declarations are made this way:
local router = require 'router'
router.get("/computers", "routes/computers.get.lc")
router.post("/user/register", "routes/register.get.lc")
router.delete("/user/employee", "routes/employee-revoke.delete.lc")
return router.handler
Save your own script with your own routes and load it using server:use()
This project is licensed under The MIT License (MIT).
Copyright (c) 2015 Loïc Ortola
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Any form of contribution is welcome: Issues, Pull-Requests, Feature requests.
Twitter: @Loicortola