Mojo is a language that combines the readability of Python with the speed of C++.
It's useful for different things, from low-level code that's close to hardware, via the Back-End API design, to the world of Front-End and the Web. Mojo is powerful enough to scale across the entire modern stack. The language has also been designed with AI and Machine Learning in mind — so it will be particularly useful for AI developers and Data Scientists.
Mojo is still young though. The ecosystem has been missing the tools for everyday software development, like networking or basic HTTP operations.
This is where Lightbug 🔥🐝 flies in.
Lightbug 🔥🐝 is a simple HTTP framework written in pure Mojo, with no external dependencies by default. It's meant to serve as a foundation for more complex projects and allows you to develop Web services like APIs, set up basic routing, or even serve HTML pages with Mojo, while taking advantage of the features of this language, like static typing and great performance.
To get started, simply install Mojo and Git, then clone the Lightbug Github repo:
git clone https://github.com/saviorand/lightbug_http.git
Once it's cloned, switch to the directory in your command line:
cd lightbug_http
Then run the server (yes, that's the Mojo file extension! 🔥):
mojo lightbug.🔥
You should see the following line printed to the console:
🔥🐝 Lightbug is listening on 0.0.0.0:8080
Ready to accept connections...
Now, you can start making requests to your server or try opening localhost:8080
or 0.0.0.0:8080
in the browser — you should see the intro screen. Welcome to the Web, Mojo-style! Now, let's get to some real coding.
While Lightbug is still young, the core functionality people expect to be able to develop for the modern Web is already there.
Note that since there's no package manager yet, you should simply include lightbug_http
as a subfolder inside your own project. This will work as a Mojo package and will allow you to import tools like web primitives, servers, and more from Lightbug.
For example, add this to the top of your file to import the server:
from lightbug_http.sys.server import SysServer
This will import a server implementation in pure Mojo. If you want to use the Python implementation, import the PythonServer
instead. It will work in the same manner.
To make an HTTP service, simply make a struct that satisfies the HTTPService
trait, meaning it has a func
method with the following signature:
trait HTTPService:
fn func(self, req: HTTPRequest) raises -> HTTPResponse:
...
This uses the built-in primitives to take in an HTTPRequest
, execute any custom logic you write in Mojo or Python, and return an HTTPResponse
object with some data back to the API consumer.
Let's make a service that prints all requests sent to 0.0.0.0:8080
to the console. To do this, create a file called my_awesome_service.🔥
, and paste the following:
from lightbug_http import *
@value
struct Printer(HTTPService):
fn func(self, req: HTTPRequest) raises -> HTTPResponse:
let body = req.body_raw
print(String(body))
return OK(body)
fn main() raises:
var server = SysServer()
let handler = Printer()
server.listen_and_serve("0.0.0.0:8080", handler)
Run mojo my_awesome_service.🔥
, and send the request to 0.0.0.0:8080
from your favorite API clients, like Insomnia or Bruno. You should see some details about the request printed to the console.
Congrats! You're officially a Mojo web developer now 🔥.
In the example, we initialize a variable called handler
with let
(meaning it cannot be re-assigned) and pass it to listen_and_serve
as a second parameter for clarity.
Adding a @value
decorator is optional: if you're an advanced Mojician, you can add an __init__
constructor method instead. It will work the same; @value
just generates this and other useful methods automatically.
struct Printer(HTTPService):
fn __init__(inout self):
print("Printer initialized!")
fn func(self, req: HTTPRequest) raises -> HTTPResponse:
let body = req.body_raw
print(String(body))
return OK(body)
You might say, but that's just one route! Modern APIs require much more than that.
Lightbug can also do some basic routing as well:
@value
struct ExampleRouter(HTTPService):
fn func(self, req: HTTPRequest) raises -> HTTPResponse:
let body = req.body_raw
let uri = req.uri()
if uri.path() == "/":
print("I'm on the index path!")
if uri.path() == "/first":
print("I'm on /first!")
elif uri.path() == "/second":
print("I'm on /second!")
return OK(body)
Add this to your my_awesome_service.🔥
, and pass it as a handler to the server:
fn main() raises:
var server = SysServer()
let handler = ExampleRouter()
server.listen_and_serve("0.0.0.0:8080", handler)
You can now open your browser and go to localhost:8080/first
, localhost:8080/second
to see the changes.
This functionality should give you a basis to develop your own apps, libraries, and services that make use of HTTP, while taking advantage of the flexibility and customization options that a lightweight framework/toolkit that is the lightbug_http
can provide.
We plan on making routing, as well as other tasks like authoring and generating APIs from an OpenAPI specification, designing your data model, and building web applications even more enjoyable in the future by building lightbug_api
and lightbug_web
packages. Check out our Roadmap for details.
That's it for an introduction to Lightbug 🔥🐝! Hope it was useful.
This is an open-source, non-commercial community project.
Please star ⭐ our Github repo, join the Discord, and check out how to contribute with your code, so we can make it even better for the fellow Mojicians.
Til’ next time!