fjord/README.md
2025-11-09 11:11:15 +01:00

99 lines
2.6 KiB
Markdown

# HTTP 1/1 server library
## Routing rules
- Static first routing
- Path variables defined with `:foo`
- Example: `/odin/:version/download`
- Wild card routing not implemented
## Compile time user errors included
When defining the server you can pass a custom error type for the server.
All the handler function will, of course, need to return these in as a pair with a response.
## Memory allocation
The server will free the context temp allocators memory after the handler is run, thus, you are free
to use `context.temp_allocator` within your handlers and expect the memory to be freed after.
This becomes useful when you want to pass the response back to the server but is also ergonomic
if you find yourself in need of a temp allocator in your handlers.
## Example
```odin
package main
import "core:log"
import "core:net"
import "core:strings"
import fjord "fjord"
import http "fjord/http"
// Handler for GET /hello/:name
hello_handler :: proc(request: ^http.Request) -> (http.Response, Error) {
name := request.path_variables["name"]
body := strings.concatenate(
{"<h1>Hello, ", name, "!</h1>"},
context.temp_allocator,
)
response := http.make_response(
.Ok,
transmute([]byte)body,
.Html,
context.temp_allocator,
)
return response, nil
}
// Handler for GET /users/:id/posts/:post_id
user_post_handler :: proc(request: ^http.Request) -> (http.Response, Error) {
user_id := request.path_variables["id"]
post_id := request.path_variables["post_id"]
body := strings.concatenate(
{"<p>User ", user_id, " - Post ", post_id, "</p>"},
context.temp_allocator,
)
response := http.make_response(
.Ok,
transmute([]byte)body,
.Html,
context.temp_allocator,
)
return response, nil
}
UserError :: enum {
DatabaseError,
ValidationError,
}
main :: proc() {
context.logger = log.create_console_logger(.Info)
defer log.destroy_console_logger(context.logger)
endpoint := net.Endpoint {
address = net.IP4_Address{127, 0, 0, 1},
port = 8080,
}
server: fjord.Server(UserError)
fjord.server_init(&server, endpoint, context.allocator)
defer fjord.server_destroy(&server)
fjord.server_add_route(&server, .GET, {"hello", ":name"}, hello_handler)
fjord.server_add_route(&server, .GET, {"users", ":id", "posts", ":post_id"}, user_post_handler)
log.infof("Server listening on http://127.0.0.1:%d", endpoint.port)
fjord.listen_and_serve(&server)
}
```
## Dev
Run the test suite to check functionality, curl is a required dependancy for the test suite to work.
```bash
odin test .
```