Guide - HTTP Server
This guide walks you through all steps of setting up an HTTP server Onyx, writing some routes on it, and then deploying it to Wasmer Edge using WCGI.
Setting up the Project
First, you need create a new folder for this project, and initialize that folder as an Onyx project. See the package manager explainer for more details.
mkdir my-http-server
cd my-http-server
onyx package init
Then you need to add the HTTP server package to this project, and synchronize changes to install the package.
# Add the package
onyx package add http-server
# Synchronize changes
onyx package sync
Once the package is successfully fetched, you can start writing some code!
Writing the code
You can now write the code for your server.
Begin by creating a main.onyx
file that will house your code.
In this file, you first need to load your packages and use the http
package.
#load "./lib/packages"
// Include everything from the core library.
use core {*}
// Include the http package, and specifically use some common symbols.
use http
use http.server { Request, Response, route }
Now you write a simple main
function that will create a TCP HTTP server,
with one route for getting the "/"
endpoint.
main :: () {
// Create a router that will route the traffic.
router := http.server.router();
// Register a handler for 'GET /'.
router->get("/", (req: &Request, res: &Response) {
// Respond with HTML
res->html("HTTP Server in Onyx!
");
// Set status to 200
res->status(200);
// Mark the response as completed
res->end();
});
// Create a TCP server out of your router.
app := http.server.tcp(&router);
// Serve on port 8000.
app->serve(8000);
}
That is everything you need to create a simple HTTP server that will respond to a GET
request on /
with "<h1>HTTP Server in Onyx!<h1>"
.
You could define more routes in this way, using router->get
or router->post
,
but there is a better way described shortly.
Running your server
To run your server, you can either use the builtin Onyx runtime, or Wasmer with WASIX support. These are the only two options for now, as there no other runtimes with fully networking support.
In a later section, you can make this web server use WCGI, so it can be deployed anywhere.
To run using the Onyx runtime (if it is installed), simply run the following command.
$ onyx run main.onyx
[Info][Http-Server] Serving on port 8000
To run using Wasmer and WASIX, you need to compile your server to a WASM binary, then
run it with wasmer
.
$ # Adding '-r wasi' to target WASI, and '-DWASIX' to add WASIX extensions.
$ onyx build main.onyx -r wasi -DWASIX
$ wasmer run --net out.wasm
[Info][Http-Server] Serving on port 8000
To test your server, you can visit localhost:8000 in your browser. Or, make a request using cURL.
$ curl http://localhost:8000
<h1>HTTP Server in Onyx!<h1>
Rewriting your code
The server you have is perfectly functional, and you could keep adding more routes to it
in the same way as above. However, with all of this code in main
, it doesn't
scale terribly well.
An alternative way to register routes is to use Onyx's procedure tags feature to label certain procedures as request handlers. Then, the router can automatically find them and register them!
Here is how this works. First, you move the request handler from before into a new
global procedure, and add a #tag
to it.
// Tag the procedure with a `route` structure, so it can be found by the router.
#tag route.{ .GET, "/" }
index :: (req: &Request, res: &Response) {
// Respond with HTML
res->html("HTTP Server in Onyx!
");
// Set status to 200
res->status(200);
// Mark the response as completed
res->end();
}
Now in main
, you can remove the router->get()
call and replace it with router->collect_routes()
.
This procedure will find all route
tags in all packages in the code base.
main :: () {
// Create a router that will route the traffic.
router := http.server.router();
// Collect routes from all packages.
router->collect_routes();
// Create a TCP server out of your router.
app := http.server.tcp(&router);
// Serve on port 8000.
app->serve(8000);
}
You can test the server in the same way as before.
$ onyx run main.onyx
[Info][Http-Server] Serving on port 8000
$ curl http://localhost:8000
<h1>HTTP Server in Onyx!<h1>
Deploying to Wasmer Edge
To deploy to Wasmer Edge, you need to first convert the code to use the Common Gateway Interface (CGI) protocol instead of being a TCP server.
Simply, replace the http.server.tcp
call with http.server.cgi
.
main :: () {
// Create a router that will route the traffic.
router := http.server.router();
// Collect routes from all packages.
router->collect_routes();
// Respond using the CGI protocol
http.server.cgi(&router);
}
Then compile the code to a WebAssembly module targeting the WASI runtime.
$ onyx build main.onyx -r wasi -o my-http-server.wasm
To deploy to Wasmer Edge, create a wasmer.toml
file that contains the following.
Replace <your-namespace>
and <your-package-name>
with your details.
[package]
name = "<your-namespace>/<your-package-name>"
version = "0.1.0"
description = "My first HTTP server"
license = "MIT"
[[module]]
name = "server"
source = "my-http-server.wasm"
abi = "wasi"
[[command]]
name = "server"
module = "server"
runner = "https://webc.org/runner/wcgi"
[command.annotations.wasi]
env = ["SCRIPT_NAME=rust_wcgi"]
[command.annotations.wcgi]
dialect = "rfc-3875"
Also, create an app.yaml
file with the following contents.
---
kind: wasmer.io/App.v0
name: <your-app-name>
package: <your-namespace>/<your-package-name>
Then use Wasmer CLI to deploy it.
$ wasmer deploy
Follow the instructions from the Wasmer to test your deployment.
Next Steps
If you want to keep building up your HTTP server, you can look at more examples in the HTTP Server package.