Apidog

Nền tảng phát triển API hợp tác tất cả trong một

Thiết kế API

Tài liệu API

Gỡ lỗi API

Giả lập API

Kiểm thử API tự động

Cách Sử Dụng Zig để Xây Dựng REST API

中村 拓也

中村 拓也

Updated on tháng 4 2, 2025

Zig là một ngôn ngữ lập trình hiện đại được thiết kế để mạnh mẽ, tối ưu và dễ bảo trì. Với trọng tâm vào hiệu suất, kiểm soát rõ ràng việc cấp phát bộ nhớ và các tính năng tại thời điểm biên dịch, Zig là sự lựa chọn tuyệt vời cho việc xây dựng các ứng dụng hiệu suất cao, bao gồm các API REST cần xử lý tải lớn với mức sử dụng tài nguyên tối thiểu.

Trong hướng dẫn này, chúng ta sẽ khám phá cách tận dụng Zig để tạo ra một API REST không chỉ chức năng mà còn "siêu nhanh." Chúng ta sẽ đi qua việc thiết lập một dự án, triển khai chức năng API cốt lõi và tối ưu hóa nó cho hiệu suất tốt nhất. Cuối cùng, bạn sẽ có một nền tảng vững chắc để xây dựng các dịch vụ web hiệu suất cao bằng Zig.

💡
Trong khi nhiều nhà phát triển quen thuộc với Postman như một công cụ Kiểm tra API, tôi muốn giới thiệu đến bạn Apidog, một lựa chọn mạnh mẽ cung cấp một nền tảng phát triển API hoàn chỉnh.

Apidog kết hợp tài liệu API, thiết kế, kiểm tra và gỡ lỗi vào một quy trình làm việc liền mạch, làm cho nó hoàn hảo cho việc kiểm tra API Zig hiệu suất cao của chúng ta.

button

Thiết lập môi trường phát triển Zig của bạn

Trước khi chúng ta bắt đầu lập trình, hãy đảm bảo bạn có mọi thứ cần thiết để phát triển với Zig:

Cài đặt Zig: Tải xuống phiên bản mới nhất từ ziglang.org hoặc sử dụng một trình quản lý gói:

# Trên macOS với Homebrew
brew install zig

# Trên Linux với apt
sudo apt install zig

Xác minh cài đặt:

zig version

Cấu trúc dự án

Hãy tạo một cấu trúc dự án sạch sẽ:

mkdir zig-rest-api
cd zig-rest-api
zig init-exe

Điều này tạo ra một dự án Zig cơ bản với một tệp src/main.zig. Chúng ta sẽ mở rộng cấu trúc này:

zig-rest-api/
├── src/
│   ├── main.zig
│   ├── server.zig
│   ├── router.zig
│   ├── handlers/
│   │   ├── users.zig
│   │   └── products.zig
│   └── models/
│       ├── user.zig
│       └── product.zig
├── build.zig
└── README.md

Triển khai máy chủ HTTP

Đầu tiên, hãy tạo một máy chủ HTTP cơ bản. Thư viện chuẩn của Zig cung cấp các primitive mạng, nhưng nó không bao gồm một máy chủ HTTP đầy đủ. Chúng ta sẽ sử dụng gói zhttp tuyệt vời.

Thêm phụ thuộc này vào build.zig của bạn:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const zhttp = b.dependency("zhttp", .{});
    
    const exe = b.addExecutable(.{
        .name = "zig-rest-api",
        .root_source_file = .{ .path = "src/main.zig" },
        .target = target,
        .optimize = optimize,
    });
    
    exe.addModule("zhttp", zhttp.module("zhttp"));
    
    b.installArtifact(exe);
}

Giờ hãy triển khai máy chủ của chúng ta trong src/server.zig:

const std = @import("std");
const zhttp = @import("zhttp");
const Allocator = std.mem.Allocator;

pub const Server = struct {
    server: zhttp.Server,
    allocator: Allocator,

    pub fn init(allocator: Allocator, port: u16) !Server {
        return Server{
            .server = try zhttp.Server.init(allocator, .{
                .address = "0.0.0.0",
                .port = port,
            }),
            .allocator = allocator,
        };
    }

    pub fn deinit(self: *Server) void {
        self.server.deinit();
    }

    pub fn start(self: *Server) !void {
        std.log.info("Máy chủ lắng nghe trên cổng {d}", .{self.server.port});
        try self.server.start();
    }
};

Thêm Router và xử lý yêu cầu

Tại src/router.zig, hãy tạo một router đơn giản:

const std = @import("std");
const zhttp = @import("zhttp");
const Allocator = std.mem.Allocator;

pub const Router = struct {
    routes: std.StringHashMap(HandlerFn),
    allocator: Allocator,

    pub const HandlerFn = fn(zhttp.Request, *zhttp.Response) anyerror!void;

    pub fn init(allocator: Allocator) Router {
        return Router{
            .routes = std.StringHashMap(HandlerFn).init(allocator),
            .allocator = allocator,
        };
    }

    pub fn deinit(self: *Router) void {
        self.routes.deinit();
    }

    pub fn addRoute(self: *Router, path: []const u8, handler: HandlerFn) !void {
        try self.routes.put(try self.allocator.dupe(u8, path), handler);
    }

    pub fn handleRequest(self: *Router, req: zhttp.Request, res: *zhttp.Response) !void {
        const handler = self.routes.get(req.path) orelse {
            res.status = .not_found;
            try res.send("Không tìm thấy");
            return;
        };

        try handler(req, res);
    }
};

Xử lý JSON

Hãy tạo các hàm tiện ích để làm việc với JSON:

// src/json_utils.zig
const std = @import("std");

pub fn parseJson(comptime T: type, json_str: []const u8, allocator: std.mem.Allocator) !T {
    var tokens = std.json.TokenStream.init(json_str);
    return try std.json.parse(T, &tokens, .{
        .allocator = allocator,
        .ignore_unknown_fields = true,
    });
}

pub fn stringify(value: anytype, allocator: std.mem.Allocator) ![]const u8 {
    return std.json.stringifyAlloc(allocator, value, .{});
}

Xây dựng các Handler API

Giờ hãy tạo một handler cho tài nguyên người dùng trong src/handlers/users.zig:

const std = @import("std");
const zhttp = @import("zhttp");
const json_utils = @import("../json_utils.zig");

const User = struct {
    id: usize,
    name: []const u8,
    email: []const u8,
};

// Lưu trữ trong bộ nhớ cho ví dụ
var users = std.ArrayList(User).init(std.heap.page_allocator);

pub fn getUsers(req: zhttp.Request, res: *zhttp.Response) !void {
    const json = try json_utils.stringify(users.items, req.allocator);
    res.headers.put("Content-Type", "application/json") catch unreachable;
    try res.send(json);
}

pub fn getUserById(req: zhttp.Request, res: *zhttp.Response) !void {
    // Trích xuất ID từ các tham số đường dẫn URL
    const id_str = req.params.get("id") orelse {
        res.status = .bad_request;
        try res.send("Thiếu tham số ID");
        return;
    };
    
    const id = try std.fmt.parseInt(usize, id_str, 10);
    
    // Tìm người dùng có ID phù hợp
    for (users.items) |user| {
        if (user.id == id) {
            const json = try json_utils.stringify(user, req.allocator);
            res.headers.put("Content-Type", "application/json") catch unreachable;
            try res.send(json);
            return;
        }
    }
    
    res.status = .not_found;
    try res.send("Người dùng không tồn tại");
}

pub fn createUser(req: zhttp.Request, res: *zhttp.Response) !void {
    const body = try req.body();
    var user = try json_utils.parseJson(User, body, req.allocator);
    
    // Tạo một ID mới
    user.id = users.items.len + 1;
    
    try users.append(user);
    
    res.status = .created;
    res.headers.put("Content-Type", "application/json") catch unreachable;
    const json = try json_utils.stringify(user, req.allocator);
    try res.send(json);
}

Đưa tất cả vào một thể thống nhất

Giờ, hãy cập nhật src/main.zig của chúng ta để tích hợp mọi thứ:

const std = @import("std");
const Server = @import("server.zig").Server;
const Router = @import("router.zig").Router;
const users = @import("handlers/users.zig");

pub fn main() !void {
    // Tạo một bộ phân phối arena
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    const allocator = arena.allocator();

    var router = Router.init(allocator);
    defer router.deinit();

    // Đăng ký các tuyến
    try router.addRoute("/api/users", users.getUsers);
    try router.addRoute("/api/users/{id}", users.getUserById);
    try router.addRoute("/api/users", users.createUser);

    var server = try Server.init(allocator, 8080);
    defer server.deinit();

    // Thiết lập handler yêu cầu
    server.server.setRequestHandler(handler);

    // Bắt đầu máy chủ
    try server.start();
}

fn handler(req: zhttp.Request, res: *zhttp.Response) !void {
    std.log.info("{s} {s}", .{@tagName(req.method), req.path});
    try router.handleRequest(req, res);
}

Tối ưu hóa hiệu suất

Zig cung cấp một số tính năng giúp API của chúng ta trở nên siêu nhanh:

  1. Trừu tượng không tốn chi phí: Cách tiếp cận của Zig đảm bảo rằng các trừu tượng không gây thêm chi phí.
  2. Lập trình meta tại thời điểm biên dịch: Chúng ta có thể thực hiện công việc tại thời điểm biên dịch thay vì tại thời điểm thực thi.
  3. Quản lý bộ nhớ thủ công: Bằng cách kiểm soát các cấp phát, chúng ta tránh được các khoảng dừng trong việc thu gom rác.
  4. Các bộ cấp phát arena: Rất thích hợp cho bộ nhớ theo yêu cầu mà có thể nhanh chóng được giải phóng tất cả cùng một lúc.
  5. Hàm nội tuyến: Các đường dẫn quan trọng có thể được nội tuyến để loại bỏ chi phí gọi hàm.

Hãy tối ưu hóa router của chúng ta:

// Thêm thuộc tính nội tuyến vào các hàm quan trọng
pub inline fn handleRequest(self: *Router, req: zhttp.Request, res: *zhttp.Response) !void {
    // Mã hiện có...
}

Và tối ưu hóa handler yêu cầu của chúng ta với một nhóm luồng:

const ThreadPool = struct {
    threads: []std.Thread,
    
    pub fn init(thread_count: usize) !ThreadPool {
        var threads = try std.heap.page_allocator.alloc(std.Thread, thread_count);
        
        for (threads) |*thread, i| {
            thread.* = try std.Thread.spawn(.{}, workerFn, .{i});
        }
        
        return ThreadPool{ .threads = threads };
    }
    
    fn workerFn(id: usize) void {
        // Xử lý các yêu cầu đến
        while (true) {
            // Lấy yêu cầu từ hàng đợi và xử lý
        }
    }
};

Kết luận

Trong hướng dẫn này, chúng tôi đã khám phá cách tận dụng các tính năng tập trung vào hiệu suất của Zig để xây dựng một API REST hiệu suất cao. Bằng cách tận dụng quản lý bộ nhớ thủ công của Zig, các tính năng tại thời điểm biên dịch và các trừu tượng không tốn chi phí, chúng tôi đã tạo ra một máy chủ API vừa mạnh mẽ vừa siêu nhanh.

Chúng tôi đã đề cập đến:

  • Thiết lập môi trường phát triển Zig
  • Xây dựng một máy chủ HTTP cơ bản
  • Tạo một router để xử lý các điểm cuối API
  • Triển khai tuần tự và khôi phục JSON
  • Thêm các handler điểm cuối API
  • Tối ưu hóa cho hiệu suất

Nền tảng này cung cấp cho bạn các công cụ để xây dựng các API sẵn sàng cho sản xuất trong Zig mà vượt trội hơn so với những cái viết bằng nhiều ngôn ngữ khác. Khi bạn tiếp tục phát triển với Zig, hãy khám phá thêm các tính năng nâng cao như comptime, xử lý lỗi và biên dịch chéo để nâng cao hơn nữa các ứng dụng của bạn.