Skip to content
This repository was archived by the owner on May 12, 2026. It is now read-only.

Commit 9273dd4

Browse files
committed
wip refactoring
1 parent c8b84bf commit 9273dd4

5 files changed

Lines changed: 795 additions & 158 deletions

File tree

lightbug.mojo

Lines changed: 111 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,133 @@
1-
from lightbug_api import (
2-
App,
3-
BaseRequest,
4-
FromReq,
5-
Router,
6-
HandlerResponse,
7-
JSONType,
8-
)
9-
from lightbug_http import HTTPRequest, HTTPResponse, OK
1+
# lightbug_api showcase
2+
# ─────────────────────────────────────────────────────────────────────────────
3+
# Run: mojo lightbug.mojo
4+
# Test: curl http://localhost:8080/
5+
# curl http://localhost:8080/items
6+
# curl http://localhost:8080/items/42
7+
# curl http://localhost:8080/items/42?verbose=true
8+
# curl -X POST http://localhost:8080/items \
9+
# -H 'Content-Type: application/json' \
10+
# -d '{"name":"Widget","price":9.99}'
11+
# curl -X PUT http://localhost:8080/items/42 \
12+
# -H 'Content-Type: application/json' \
13+
# -d '{"name":"Updated","price":19.99}'
14+
# curl -X DELETE http://localhost:8080/items/42
15+
# curl http://localhost:8080/v1/status
16+
# ─────────────────────────────────────────────────────────────────────────────
1017

18+
from lightbug_api import App, Router, HandlerResponse
19+
from lightbug_api.context import Context
20+
from lightbug_api.response import Response
21+
from lightbug_http.http.json import Json, JsonSerializable, JsonDeserializable
1122

12-
fn printer(req: HTTPRequest) raises -> HandlerResponse:
13-
print("Got a request on ", req.uri.path, " with method ", req.method)
14-
return OK(req.body_raw)
1523

16-
fn hello(req: HTTPRequest) raises -> HandlerResponse:
17-
return OK("Hello 🔥!")
24+
# ----------------------------------------------------------------- data types
1825

26+
@fieldwise_init
27+
struct Item(JsonSerializable, Movable, Defaultable):
28+
"""An item returned in API responses."""
1929

20-
fn nested(req: HTTPRequest) raises -> HandlerResponse:
21-
print("Handling route:", req.uri.path)
22-
# Returning a string will get marshaled to a proper `OK` response
23-
return req.uri.path
30+
var id: Int
31+
var name: String
32+
var price: Float64
2433

34+
fn __init__(out self):
35+
self.id = 0
36+
self.name = ""
37+
self.price = 0.0
2538

26-
struct Payload(FromReq):
27-
var request: HTTPRequest
28-
var json: JSONType
29-
var a: Int
3039

31-
def __init__(out self, request: HTTPRequest, json: JSONType):
32-
self.a = 1
33-
self.request = request.copy()
34-
self.json = json.copy()
40+
@fieldwise_init
41+
struct CreateItemRequest(JsonDeserializable, Movable, Defaultable):
42+
"""JSON body expected for POST /items."""
3543

36-
def __init__(out self, *, copy: Self):
37-
self.a = copy.a
38-
self.request = copy.request.copy()
39-
self.json = copy.json.copy()
44+
var name: String
45+
var price: Float64
4046

41-
def __str__(self) -> String:
42-
return String(self.a)
47+
fn __init__(out self):
48+
self.name = ""
49+
self.price = 0.0
4350

44-
def from_request(mut self, req: HTTPRequest) raises -> Self:
45-
self.a = 2
46-
return self.copy()
4751

52+
@fieldwise_init
53+
struct StatusResponse(JsonSerializable, Movable, Defaultable):
54+
var status: String
55+
var version: String
4856

49-
fn custom_request_payload(req: HTTPRequest) raises -> HandlerResponse:
50-
var payload = Payload(request=req, json=JSONType())
51-
payload = payload.from_request(req)
52-
print(payload.a)
57+
fn __init__(out self):
58+
self.status = ""
59+
self.version = ""
5360

54-
# Returning a JSON as the response, this is a very limited placeholder for now
55-
var json_response = JSONType()
56-
json_response["a"] = String(payload.a)
57-
return json_response^
5861

62+
# ------------------------------------------------------------------ handlers
63+
64+
fn index(ctx: Context) raises -> HandlerResponse:
65+
"""GET / — plain-text welcome message."""
66+
return Response.text("Welcome to lightbug_api 🔥")
67+
68+
69+
fn list_items(ctx: Context) raises -> HandlerResponse:
70+
"""GET /items — return a hard-coded list as JSON."""
71+
# In a real app you'd query a database here.
72+
return Response.json(Item(1, "Widget", 9.99))
73+
74+
75+
fn get_item(ctx: Context) raises -> HandlerResponse:
76+
"""GET /items/{id} — return one item by ID."""
77+
var id = ctx.path_param("id", "unknown")
78+
var verbose = ctx.query("verbose", "false")
79+
80+
if verbose == "true":
81+
print("GET /items/", id, " (verbose mode)")
82+
83+
# Demonstrate that a bare Json value also works as HandlerResponse.
84+
return Json(Item(42, String("Item ", id), 9.99))
85+
86+
87+
fn create_item(ctx: Context) raises -> HandlerResponse:
88+
"""POST /items — deserialize JSON body, return 201 Created."""
89+
var body = ctx.json[CreateItemRequest]()
90+
var created = Item(100, body.name, body.price)
91+
return Response.created(created)
92+
93+
94+
fn update_item(ctx: Context) raises -> HandlerResponse:
95+
"""PUT /items/{id} — update an item."""
96+
var id = ctx.path_param("id", "0")
97+
var body = ctx.json[CreateItemRequest]()
98+
return Response.json(Item(42, body.name, body.price))
99+
100+
101+
fn delete_item(ctx: Context) raises -> HandlerResponse:
102+
"""DELETE /items/{id} — delete an item, return 204 No Content."""
103+
var id = ctx.path_param("id", "0")
104+
print("Deleting item", id)
105+
return Response.no_content()
106+
107+
108+
fn health(ctx: Context) raises -> HandlerResponse:
109+
"""GET /v1/status — health check mounted under the v1 sub-router."""
110+
return Response.json(StatusResponse("ok", "1.0.0"))
111+
112+
113+
# --------------------------------------------------------------------- main
59114

60115
fn main() raises:
61116
var app = App()
62117

63-
app.get("/", hello)
64-
65-
app.get("custom/", custom_request_payload)
118+
# Root
119+
app.get("/", index)
66120

67-
app.post("/", printer)
121+
# Items resource — all HTTP verbs
122+
app.get("/items", list_items)
123+
app.get("/items/{id}", get_item)
124+
app.post("/items", create_item)
125+
app.put("/items/{id}", update_item)
126+
app.delete("/items/{id}", delete_item)
68127

69-
var nested_router = Router("nested")
70-
nested_router.get(path="all/echo/", handler=nested)
71-
app.add_router(nested_router^)
128+
# Sub-router mounted at /v1
129+
var v1 = Router("v1")
130+
v1.get("status", health)
131+
app.add_router(v1^)
72132

73-
app.start_server()
133+
app.run()

lightbug_api/__init__.mojo

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,93 @@
11
from lightbug_http import HTTPRequest, HTTPResponse, Server
2+
from lightbug_api.context import Context
3+
from lightbug_api.response import Response
24
from lightbug_api.routing import (
35
BaseRequest,
46
FromReq,
7+
Handler,
8+
HandlerResponse,
9+
PathPattern,
10+
RouteMatch,
511
RootRouter,
612
Router,
7-
HandlerResponse,
8-
JSONType,
9-
Handler,
1013
)
1114

1215

1316
struct App:
17+
"""The top-level application — register routes then call ``run()``.
18+
19+
Example::
20+
21+
fn main() raises:
22+
var app = App()
23+
24+
app.get("/", index)
25+
app.get("/users/{id}", get_user)
26+
app.post("/users", create_user)
27+
app.delete("/users/{id}", delete_user)
28+
29+
var api = Router("v1")
30+
api.get("status", health)
31+
app.add_router(api^) # mounts at /v1/status
32+
33+
app.run()
34+
"""
35+
1436
var router: RootRouter
1537

1638
def __init__(out self) raises:
1739
self.router = RootRouter()
1840

41+
# ------------------------------------------ route registration
42+
1943
def get(mut self, path: String, handler: Handler) raises:
44+
"""Register a GET handler."""
2045
self.router.get(path, handler)
2146

2247
def post(mut self, path: String, handler: Handler) raises:
48+
"""Register a POST handler."""
2349
self.router.post(path, handler)
2450

51+
def put(mut self, path: String, handler: Handler) raises:
52+
"""Register a PUT handler."""
53+
self.router.put(path, handler)
54+
55+
def delete(mut self, path: String, handler: Handler) raises:
56+
"""Register a DELETE handler."""
57+
self.router.delete(path, handler)
58+
59+
def patch(mut self, path: String, handler: Handler) raises:
60+
"""Register a PATCH handler."""
61+
self.router.patch(path, handler)
62+
63+
def options(mut self, path: String, handler: Handler) raises:
64+
"""Register an OPTIONS handler."""
65+
self.router.options(path, handler)
66+
67+
def head(mut self, path: String, handler: Handler) raises:
68+
"""Register a HEAD handler."""
69+
self.router.head(path, handler)
70+
2571
def add_router(mut self, var router: Router) raises -> None:
72+
"""Mount a sub-router under its path fragment."""
2673
self.router.add_router(router^)
2774

75+
# ------------------------------------------ start server
76+
77+
def run(mut self, host: String = "0.0.0.0", port: Int = 8080) raises:
78+
"""Start the HTTP server.
79+
80+
Args:
81+
host: Bind address (default ``0.0.0.0``).
82+
port: TCP port (default ``8080``).
83+
"""
84+
var server = Server()
85+
server.listen_and_serve(String(host, ":", port), self.router)
86+
2887
def start_server(mut self, address: String = "0.0.0.0:8080") raises:
88+
"""Start the HTTP server.
89+
90+
Deprecated: use ``run(host, port)`` instead.
91+
"""
2992
var server = Server()
3093
server.listen_and_serve(address, self.router)

0 commit comments

Comments
 (0)