1- # lightbug_api showcase — metaprogramming ergonomics demo
1+ # lightbug_api — quick-start example
22# ─────────────────────────────────────────────────────────────────────────────
3- # Run: mojo lightbug.mojo
4- # Test: curl http://localhost:8080/
5- # curl http://localhost:8080/items
3+ # Run: pixi run mojo lightbug.mojo
4+ # Test: curl http://localhost:8080/items
65# curl http://localhost:8080/items/42
7- # curl "http://localhost:8080/items/42?verbose=true"
86# curl -X POST http://localhost:8080/items \
97# -H 'Content-Type: application/json' \
108# -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
169# curl http://localhost:8080/notes
1710# curl http://localhost:8080/notes/1
1811# ─────────────────────────────────────────────────────────────────────────────
@@ -23,7 +16,7 @@ from lightbug_api.response import Response
2316from lightbug_http.http.json import JsonSerializable, JsonDeserializable
2417
2518
26- # ----------------------------------------------------------------- data types
19+ # ── Models ────────────────────────────────────────────────────────────────────
2720
2821@fieldwise_init
2922struct Item (JsonSerializable , Movable , Defaultable ):
@@ -32,9 +25,7 @@ struct Item(JsonSerializable, Movable, Defaultable):
3225 var price : Float64
3326
3427 fn __init__ (out self ):
35- self .id = 0
36- self .name = " "
37- self .price = 0.0
28+ self .id = 0 ; self .name = " " ; self .price = 0.0
3829
3930
4031@fieldwise_init
@@ -43,18 +34,7 @@ struct CreateItemRequest(JsonDeserializable, Movable, Defaultable):
4334 var price : Float64
4435
4536 fn __init__ (out self ):
46- self .name = " "
47- self .price = 0.0
48-
49-
50- @fieldwise_init
51- struct StatusResponse (JsonSerializable , Movable , Defaultable ):
52- var status : String
53- var version : String
54-
55- fn __init__ (out self ):
56- self .status = " "
57- self .version = " "
37+ self .name = " " ; self .price = 0.0
5838
5939
6040@fieldwise_init
@@ -63,60 +43,35 @@ struct Note(JsonSerializable, Movable, Defaultable):
6343 var text : String
6444
6545 fn __init__ (out self ):
66- self .id = 0
67- self .text = " "
68-
69-
70- # ------------------------------------------------------------------ handlers
71- # Handlers that need full control (non-200 status, redirects, plain text) keep
72- # the HandlerResponse return type. Handlers that just return a model use the
73- # model type directly — the framework auto-serialises as JSON 200 OK.
46+ self .id = 0 ; self .text = " "
7447
75- fn index (ctx : Context) raises -> HandlerResponse:
76- return Response.text(" Welcome to lightbug_api 🔥" )
7748
49+ # ── Handlers — return your model directly, no Response.json() needed ──────────
7850
79- # ── Before (old style) ───────────────────────────────────────────────────────
80-
81- fn list_items (ctx : Context) raises -> Item: # ← returns Item directly
51+ fn list_items (ctx : Context) raises -> Item:
8252 return Item(1 , " Widget" , 9.99 )
8353
8454
85- fn get_item (ctx : Context) raises -> Item: # ← returns Item directly
86- var id = ctx.param(" id" , 0 )
87- var verbose = ctx.query(" verbose" , False )
88- if verbose:
89- print (" GET /items/" , id , " (verbose mode)" )
55+ fn get_item (ctx : Context) raises -> Item:
56+ var id = ctx.param(" id" , 0 )
9057 return Item(id , String(" Item " , id ), 9.99 )
9158
9259
9360fn create_item (ctx : Context) raises -> HandlerResponse:
94- # Still HandlerResponse — needs 201 Created status code
95- var body = ctx.json[CreateItemRequest]()
96- var created = Item(100 , body.name, body.price)
97- return Response.created(created)
61+ var body = ctx.json[CreateItemRequest]()
62+ return Response.created(Item(100 , body.name, body.price)) # 201 Created
9863
9964
100- fn update_item (ctx : Context) raises -> Item: # ← returns Item directly
65+ fn update_item (ctx : Context) raises -> Item:
10166 var body = ctx.json[CreateItemRequest]()
102- var id = ctx.param(" id" , 0 )
103- return Item(id , body.name, body.price)
67+ return Item(ctx.param(" id" , 0 ), body.name, body.price)
10468
10569
10670fn delete_item (ctx : Context) raises -> HandlerResponse:
107- # Still HandlerResponse — needs 204 No Content
108- var id = ctx.param(" id" , 0 )
109- print (" Deleting item" , id )
110- return Response.no_content()
111-
71+ return Response.no_content() # 204 No Content
11272
113- fn health (ctx : Context) raises -> StatusResponse: # ← returns StatusResponse directly
114- return StatusResponse(" ok" , " 1.0.0" )
11573
116-
117- # ── Resource / controller pattern ────────────────────────────────────────────
118- # Group CRUD handlers in a struct; `resource[Notes]("notes")` registers all
119- # five standard routes under /notes in one call.
74+ # ── Resource controller — one struct registers all five CRUD routes ────────────
12075
12176struct Notes (Resource ):
12277 @ staticmethod
@@ -134,40 +89,23 @@ struct Notes(Resource):
13489
13590 @ staticmethod
13691 fn update (ctx : Context) raises -> HandlerResponse:
137- var id = ctx.param(" id" , 0 )
138- return Response.json(Note(id , " updated" ))
92+ return Response.json(Note(ctx.param(" id" , 0 ), " updated" ))
13993
14094 @ staticmethod
14195 fn destroy (ctx : Context) raises -> HandlerResponse:
14296 return Response.no_content()
14397
14498
145- # --------------------------------------------------------------------- main
99+ # ── App ───────────────────────────────────────────────────────────────────────
146100
147101fn main () raises :
148102 var app = App(
149- # Plain-text response — HandlerResponse (unchanged)
150- GET(" /" , index),
151-
152- # Typed return — framework auto-serialises Item as JSON 200 OK
153103 GET [Item, list_items](" /items" ),
154104 GET [Item, get_item](" /items/{id} " ),
155-
156- # 201 Created — still HandlerResponse (needs explicit status)
157105 POST(" /items" , create_item),
158-
159- # Typed return
160106 PUT [Item, update_item](" /items/{id} " ),
161-
162- # 204 No Content — still HandlerResponse
163107 DELETE(" /items/{id} " , delete_item),
164108
165- mount(" v1" ,
166- # Typed return inside a mount
167- GET [StatusResponse, health](" status" ),
168- ),
169-
170- # Resource controller — five routes registered in one line
171- resource[Notes](" notes" ),
109+ resource[Notes](" notes" ), # GET /notes, GET /notes/{id}, POST, PUT, DELETE
172110 )
173111 app.run()
0 commit comments