zap

repository·master·Indexed 25 days ago

https://github.com/zigzap/zap

A Zig wrapper for facil.io, a high-performance C micro-framework for web applications. It provides an evented design to solve the C10K problem, supporting HTTP/1.1, WebSockets, and custom network protocols. Features include a soft dynamic type system (FIOBJ), various authenticators (BearerSingle, BearerMulti, Basic), and a global application context for managing endpoints and error handling.

Tokens
5.8K
Snippets
12
Records
28
Agent score
85%

What's inside zap

  1. Authenticate requests manually in `on_request`

    master
    You can perform authentication inside your on_request callback by using an Authenticator. All Authenticator types provide the authenticateRequest(r: zap.Request) function, which returns true if the request is authenticated and false otherwise. If authentication fails, you should manually set the status to .unauthorized and return an error response.
  2. Use the FIOBJ extension as a standalone library

    master

    The FIOBJ (facil.io Object) extension provides soft dynamic types and can be used independently of the facil.io core library.

    To use FIOBJ without the full facil.io core, follow these steps:

    1. Copy all files from the lib/facil/fiobj/ directory into your project.
    2. Copy the fio.h header file from the facil.io core library into your project.
    3. Include fiobj.h in your source code to access the API.
  3. Manage unused facil.io modules

    master

    The facil.io library is modular. If you want to reduce the source footprint, you can remove unused modules from the lib/facil folder.

    Examples of removable modules:

    • facil/http: Remove if you are not writing an HTTP application.
    • Redis modules: Remove if your application does not require Redis connectivity.

    Note: It is generally recommended to leave unused code alone to avoid future dependency issues, as the compiler can often optimize the footprint via makefile instructions.

  4. Configure the boilerplate build with Makefile

    master

    The project uses a makefile to manage the build process. You can customize the build by modifying the following variables in the makefile:

    • MAIN_ROOT: Update this if you rename the project folder.
    • MAIN_SUBFOLDERS: Use this to include sub-folders in the build (e.g., adding foo/bar will include src/foo/bar).
  5. Add facil.io to an existing project

    master

    Since facil.io is a source code library, you can integrate it into existing projects using one of the following methods:

    Method 1: Manual Source Copy

    Use the make libdump command to export all relevant library files into a single folder named libdump. You can then copy these files into your project structure.

    Method 2: Separate Compilation

    You can compile the library independently using the make lib command.

    Method 3: CMake Submodule

    1. Add the repository as a git submodule: git submodule add https://github.com/boazsegev/facil.io.git
    2. Add the following line to your CMakeLists.txt: add_subdirectory(facil.io)
  6. Handle errors in ZAP request callbacks

    master

    ZAP request callback functions (like on_request) are designed to return void rather than !void. This design choice forces developers to explicitly handle all potential errors within the callback, preventing silent failures or unexpected error responses in production.

    To use error-returning logic (e.g., using try) inside a callback, you must wrap the call in a catch block within the main callback function. This allows you to decide how to react to the error, such as logging it or returning a specific error response to the client.

    fn on_request_with_errors(r: zap.HttpRequest) !void {
        // do all the try stuff here
    }
    
    // THIS IS WHAT YOU PASS TO THE LISTENER / ENDPONT / ...
    fn on_request(r: zap.HttpRequest) void {
        on_request_with_errors(r) catch |err| {
            // log the error or use:
            // note: returnWithErrorStackTrace() is currently vaporware
            return r.returnWithErrorStackTrace(err);
        };
    }
  7. Start a new project with facil.io

    master

    To initialize a new project using the facil.io framework, use the provided scaffolding script. This script creates a new directory, downloads a stable branch, adds boilerplate code, and prepares the build environment by running make clean.

    $ bash <(curl -s https://raw.githubusercontent.com/boazsegev/facil.io/master/scripts/new/app) appname
  8. Initialize and start a zap.App

    master

    The lifecycle of a zap.App involves:

    1. zap.App.Create(Context): Generates the App type.
    2. App.init(io, gpa, context, opts): Initializes the singleton app instance.
    3. App.register(endpoint): Adds endpoints to the app.
    4. App.listen(settings): Starts the HTTP listener.
    5. App.deinit(): Cleans up resources and destroys endpoints.
  9. Implement a basic HTTP server with facil.io

    master

    To create an HTTP server, include http.h, define a callback function for handling requests (of type http_s *), and use http_listen to bind to a port. Finally, call facil_run to start the event loop.

    Common tasks within the request handler include:

    • Setting cookies with http_set_cookie.
    • Setting headers with http_set_header.
    • Sending a response body with http_send_body.
    • Using fiobj_str_new to create dynamic string objects for headers or data.
    #include "http.h" /* the HTTP facil.io extension */
    
    // We'll use this callback in `http_listen`, to handles HTTP requests
    void on_request(http_s *request);
    
    // These will contain pre-allocated values that we will use often
    FIOBJ HTTP_X_DATA;
    
    // Listen to HTTP requests and start facil.io
    int main(int argc, char const **argv) {
      // allocating values we use often
      HTTP_X_DATA = fiobj_str_new("X-Data", 6);
      // listen on port 3000 and any available network binding (NULL == 0.0.0.0)
      http_listen("3000", NULL, .on_request = on_request, .log = 1);
      // start the server
      facil_run(.threads = 1);
      // deallocating the common values
      fiobj_free(HTTP_X_DATA);
    }
    
    // Easy HTTP handling
    void on_request(http_s *request) {
      http_set_cookie(request, .name = "my_cookie", .name_len = 9, .value = "data",
                      .value_len = 4);
      http_set_header(request, HTTP_HEADER_CONTENT_TYPE,
                      http_mimetype_find("txt", 3));
      http_set_header(request, HTTP_X_DATA, fiobj_str_new("my data", 7));
      http_send_body(request, "Hello World!\r\n", 14);
    }