I am trying to create a basic web app. It is not responding in the browser.
const std = @import("std");
const routes = @import("routes.zig");
const posix = std.posix;
const c = @cImport({
@cInclude("sys/socket.h");
});
const Allocator = std.mem.Allocator;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
std.debug.print("Starting Zyflow Zig application...\n", .{});
// Start HTTP server
// Note: This is a simplified example. In production, you'd use Jetzig framework
// For now, we'll create a basic HTTP server structure
std.debug.print("Starting HTTP server...\n", .{});
try startServer(allocator);
}
fn startServer(allocator: Allocator) !void {
std.debug.print("Initializing Io...\n", .{});
// âś… Concrete Io implementation
var threaded: std.Io.Threaded = .init(allocator);
defer threaded.deinit();
const io = threaded.io(); // <- this is the std.Io value you pass around
std.debug.print("Parsing IP address...\n", .{});
const address: std.Io.net.IpAddress = try std.Io.net.IpAddress.parseIp4("127.0.0.1", 8080);
std.debug.print("Starting to listen on address...\n", .{});
var server = try address.listen(io, .{
.reuse_address = true,
});
defer server.deinit(io);
std.debug.print("Server listening on http://127.0.0.1:8080\n", .{});
while (true) {
var stream = server.accept(io) catch |err| {
std.debug.print("Error accepting connection: {}\n", .{err});
continue;
};
defer stream.close(io);
// Handle request in a simple way
// In production, use Jetzig's routing system
var buffer: [4096]u8 = undefined;
var reader = stream.reader(io, &buffer);
// Read HTTP request - readSliceShort reads available data
// This should work for both nc and curl
const bytes_read = reader.interface.readSliceShort(&buffer) catch {
continue;
};
if (bytes_read == 0) {
continue;
}
const request = buffer[0..bytes_read];
const response = routes.handleRequest(allocator, request) catch |err| {
std.debug.print("Error handling request: {}\n", .{err});
const error_response = try std.fmt.allocPrint(
allocator,
"HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nInternal Server Error",
.{},
);
defer allocator.free(error_response);
var write_buffer: [4096]u8 = undefined;
var writer = stream.writer(io, &write_buffer);
writer.interface.writeAll(error_response) catch {};
writer.interface.flush() catch {};
continue;
};
defer allocator.free(response);
// Write response
var write_buffer: [8192]u8 = undefined;
var writer = stream.writer(io, &write_buffer);
// Write response in chunks if larger than buffer
var remaining = response;
while (remaining.len > 0) {
const chunk_size = @min(remaining.len, write_buffer.len);
const chunk = remaining[0..chunk_size];
writer.interface.writeAll(chunk) catch {
break;
};
remaining = remaining[chunk_size..];
}
// Flush to ensure all data is sent
writer.interface.flush() catch {};
// Connection will be closed by defer stream.close(io)
}
}
routes.zig
const std = @import("std");
const Allocator = std.mem.Allocator;
pub fn handleRequest(
allocator: Allocator,
request: []const u8,
) ![]const u8 {
// Simple HTTP request parsing
const request_str = try std.fmt.allocPrint(allocator, "{s}", .{request});
defer allocator.free(request_str);
// Extract method and path (simplified HTTP parsing)
// Look for "GET /path" or "POST /path" patterns
if (std.mem.startsWith(u8, request, "GET /")) {
// Match "GET /" or "GET / HTTP" or "GET / HTTP/1.1" etc.
return handleIndex(allocator);
}
// 404 Not Found
return try createResponse(allocator, 404, "text/html", "<html><body><h1>404 Not Found</h1></body></html>");
}
/// Index route with Hotwire Turbo support
fn handleIndex(allocator: Allocator) ![]const u8 {
const html =
\\<!DOCTYPE html>
\\<html>
\\<head>
\\ <title>Zyflow Zig</title>
\\ <script src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8/dist/turbo.es2017-esm.js" type="module"></script>
\\ <style>
\\ body { font-family: Arial, sans-serif; margin: 40px; }
\\ .nav { margin-bottom: 20px; }
\\ .nav a { margin-right: 20px; padding: 10px; background: #007bff; color: white; text-decoration: none; border-radius: 4px; }
\\ .nav a:hover { background: #0056b3; }
\\ </style>
\\</head>
\\<body>
\\ <h1>Zyflow Zig - Low Code Application</h1>
\\ <div class="nav">
\\ <a href="/zig-query">Zig Query Route</a>
\\ <a href="/js-query">QuickJS Query Route</a>
\\ </div>
\\ <div id="content">
\\ <p>Welcome to Zyflow Zig! This is a low-code application built with:</p>
\\ <ul>
\\ <li>Zig programming language</li>
\\ <li>PostgreSQL with connection pooling</li>
\\ <li>QuickJS for JavaScript execution</li>
\\ <li>Zmpl templates (when using Jetzig)</li>
\\ <li>Hotwire Turbo for modern web interactions</li>
\\ </ul>
\\ </div>
\\</body>
\\</html>
;
return try createResponse(allocator, 200, "text/html", html);
}
fn createResponse(allocator: Allocator, status: u16, content_type: []const u8, body: []const u8) ![]const u8 {
const status_text = switch (status) {
200 => "OK",
404 => "Not Found",
else => "Unknown",
};
return try std.fmt.allocPrint(
allocator,
"HTTP/1.1 {d} {s}\r\nContent-Type: {s}\r\nContent-Length: {d}\r\nConnection: close\r\n\r\n{s}",
.{ status, status_text, content_type, body.len, body },
);
}