const std = @import("std"); const httpz = @import(".deps/http.zig/src/httpz.zig"); const models = @import("db/models.zig"); const ztime = @import(".deps/time.zig"); const utils = @import("utils.zig"); const budget = @import("routes/budget.zig"); const auth = @import("routes/auth.zig"); const user = @import("routes/user.zig"); const trans = @import("routes/transactions.zig"); const dash = @import("routes/dashboard.zig"); const note = @import("routes/shared_note.zig"); const Db = @import("db/db.zig").Db; var db: ?Db = null; pub fn getDb() *Db { return &db.?; } pub fn startHttpServer() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); // db = try Db.init(allocator, null); // defer db.deinit(); var args = try std.process.argsWithAllocator(allocator); // skip program name _ = args.skip(); while (args.next()) |arg| { if (std.mem.eql(u8, arg, "--db_path")) { const path = args.next(); // std.debug.print("Got path: {any}", .{path}); if (path) |db_path| { db = try Db.init(allocator, db_path, null); } else { std.log.err("Db path not provided after arg", .{}); return; } } if (std.mem.eql(u8, arg, "--make-migration")) { if (db == null) { std.log.err("Cannot migrate, provide db path first", .{}); return; } try db.?.wipeAndMigrateDb(); } } if (db == null) { db = try Db.init(allocator, null, null); } defer db.?.deinit(); var server = try httpz.Server().init(allocator, .{ .port = 8081 }); // overwrite the default notFound handler server.notFound(notFound); // overwrite the default error handler server.errorHandler(errorHandler); var router = server.router(); router.post("/auth/login", user.login); router.post("/auth/signup", user.signup); // router.get("/user/:id", user.getUser); router.put("/user", user.putUser); // router.delete("/user/:id", user.deleteUser); router.get("/shared_notes/:limit", note.getSharedNotes); router.put("/shared_notes", note.putSharedNote); router.post("/shared_notes", note.postSharedNote); // router.get("/budget/:id", budget.getBudget); // router.put("/budget", budget.putBudget); // router.post("/budget", budget.postBudget); router.put("/budget_category", budget.putBudgetCategory); router.post("/budget_category", budget.postBudgetCategory); router.post("/transactions", trans.postTransaction); router.put("/transactions", trans.putTransaction); router.get("/dashboard", dash.getDashboard); std.debug.print("Starting http server listening on port {}\n", .{8081}); // start the server in the current thread, blocking. try server.listen(); } fn notFound(_: *httpz.Request, res: *httpz.Response) !void { res.status = 404; // you can set the body directly to a []u8, but note that the memory // must be valid beyond your handler. Use the res.arena if you need to allocate // memory for the body. res.body = "Not Found"; } // note that the error handler return `void` and not `!void` fn errorHandler(req: *httpz.Request, res: *httpz.Response, err: anyerror) void { res.status = 500; res.body = "Internal Server Error"; std.log.warn("httpz: unhandled exception for request: {s}\nErr: {}", .{ req.url.raw, err }); } pub fn returnError(message: ?[]const u8, comptime statusCode: u16, res: *httpz.Response) void { comptime { if (statusCode > 500 or statusCode < 200) { @compileError("Failed responses must have status codes between 200 and 500"); } } res.status = statusCode; res.json(.{ .success = false, .message = message }, .{}) catch |err| { std.log.warn("Couldnt create error body: {}", .{err}); res.body = "{ \"success\": false"; }; } pub fn returnData(data: anytype, res: *httpz.Response) !void { const body = utils.structConcatFields(data, .{ .success = true }); res.status = 200; try res.json(body, .{}); }