aboutsummaryrefslogtreecommitdiff
path: root/src/http/handler/context.zig
blob: 4e55446645b756b648780227233f4d7185853765 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
const std = @import("std");
const Response = @import("../Response.zig");
const Route = @import("../Route.zig");
const Parameter = @import("../Parameter.zig");
const Interface = @import("Interface.zig");

pub fn Context(comptime r: anytype) type {
    return struct {
        pub const route = Route.fromAny(r);
        pub const Params = Parameter.Struct(route);

        pub const Request = struct {
            base_request: *std.http.Server.Request,
            params: Params,
            arena: std.mem.Allocator,
            gpa: std.mem.Allocator,
            io: std.Io,

            /// Parses the body of the request and returns type `T`.
            /// The arena allocator will be used to do the parsing.
            pub fn json(self: @This(), T: type) !T {
                var buffer: [1024]u8 = undefined;
                var reader = std.json.Reader.init(self.arena, self.base_request.readerExpectNone(&buffer));
                return std.json.parseFromTokenSourceLeaky(T, self.arena, &reader, .{});
            }
        };

        const badRequest = struct {
            pub fn badRequest(_: Request) Response {
                return .with(.bad_request, .string("method does not exist"));
            }
        }.badRequest;

        get: *const fn (Request) Response = badRequest,
        post: *const fn (Request) Response = badRequest,
        delete: *const fn (Request) Response = badRequest,
        head: *const fn (Request) Response = badRequest,
        put: *const fn (Request) Response = badRequest,
        connect: *const fn (Request) Response = badRequest,
        options: *const fn (Request) Response = badRequest,
        trace: *const fn (Request) Response = badRequest,
        patch: *const fn (Request) Response = badRequest,

        pub fn handle(
            self: *const @This(),
            gpa: std.mem.Allocator,
            arena: std.mem.Allocator,
            io: std.Io,
            request: *std.http.Server.Request,
        ) Response {
            const req: Request = .{
                .base_request = request,
                .arena = arena,
                .gpa = gpa,
                .io = io,
                .params = Parameter.parse(Params, &route, request.head.target),
            };

            return (switch (request.head.method) {
                .GET => self.get,
                .POST => self.post,
                .DELETE => self.delete,
                .HEAD => self.head,
                .PUT => self.put,
                .CONNECT => self.connect,
                .OPTIONS => self.options,
                .TRACE => self.trace,
                .PATCH => self.patch,
            })(req);
        }

        pub fn interface(self: *const @This()) Interface {
            return .from(self, route);
        }
    };
}