Crow C++ Framework

repository·master·Indexed 26 days ago

https://github.com/crowcpp/crow

A fast, easy-to-use C++ microframework for building HTTP and WebSocket web services. Crow features Flask-like routing, type-safe handlers, and built-in support for JSON and Mustache templating. It supports C++17 and provides options for single-header integration via crow_all.h or standard CMake installation.

Tokens
15.5K
Snippets
47
Records
101
Agent score
88%

What's inside Crow

  1. Understand Crow JSON value types

    master

    Crow's JSON support uses two primary types: crow::json::rvalue (read-only) and crow::json::wvalue (write/mutable). These types can hold the following values:

    • False / True: from bool
    • Number: double (Floating_point), int (Signed_integer), or unsigned int (Unsigned_integer)
    • String: from std::string
    • List: from std::vector
    • Object: from crow::json::wvalue or crow::json::rvalue (allows key-value pairs)
  2. Run a Crow application as a Systemd service

    master

    To ensure your Crow application runs automatically on system startup and restarts upon failure, you can create a Systemd service unit file.

    1. Create a new file in /etc/systemd/system/ with a .service extension (e.g., crowthing.service).
    2. Populate the file with the configuration below, ensuring you replace /absolute/path/to/your/executable with the actual path to your compiled Crow binary.
    3. Set the appropriate permissions using chmod 640.
    4. Use systemctl to manage the service (e.g., enable to run at startup, start to run it immediately).
    # 1. Create the service file
    # Edit /etc/systemd/system/crowthing.service with the following content:
    
    [Unit]
    Description=My revolutionary Crow application
    
    Wants=network.target
    After=syslog.target network-online.target
    
    [Service]
    Type=simple
    ExecStart=/absolute/path/to/your/executable
    Restart=on-failure
    RestartSec=10
    KillMode=process
    
    [Install]
    WantedBy=multi-user.target
    
    # 2. Set permissions
    chmod 640 /etc/systemd/system/crowthing.service
    
    # 3. Manage the service
    systemctl enable crowthing.service
    systemctl start crowthing.service
  3. Implement Token Authentication (Bearer)

    master

    Token authentication involves the client presenting a token in the Authorization header, typically prefixed with Bearer .

    To implement this in Crow:

    1. Extract the Authorization header using req.get_header_value("Authorization").
    2. Strip the Bearer prefix (the first 7 characters).
    3. Verify the resulting token string (e.g., by checking a database or verifying a JWT signature).

    Note: The substring index may change depending on the keyword used (e.g., Bearer is 7 characters).

  4. Generate crow_all.h (Single Header)

    master

    For small or single-file projects, you can generate a single crow_all.h header.

    1. Navigate to the scripts directory in the Crow repository.
    2. Run the merge script: ./merge_all.py ../include crow_all.h

    Customizing the header: You can include (-i) or exclude (-e) specific middlewares by name, separated by commas. Example to exclude the cookie parser: ./merge_all.py ../include crow_all.h -e cookie_parser

    ./merge_all.py ../include crow_all.h
  5. Serve static files implicitly

    master

    Crow can automatically serve files located in a specific directory when a client requests a matching URL path. By default, Crow looks for a directory named static and serves files via the /static/ endpoint.

    You can customize these settings by defining the following macros before including Crow headers:

    • CROW_STATIC_DIRECTORY: The directory on the server's file system.
    • CROW_STATIC_ENDPOINT: The URL pattern used to access the files (e.g., /alternative_endpoint/<path>).
    #define CROW_STATIC_DIRECTORY "alternative_directory/"
    #define CROW_STATIC_ENDPOINT "/alternative_endpoint/<path>"
  6. Create a WebSocket route in Crow

    master

    To implement WebSockets, use the CROW_WEBSOCKET_ROUTE(app, "/url") macro. This macro allows you to chain event handlers that respond to different stages of the WebSocket lifecycle.

    Available event handlers (in order of execution):

    • onaccept: Triggered during the handshake. Must return a boolean. If false is returned, the connection is terminated.
    • onopen: Triggered when the connection is successfully opened.
    • onmessage: Triggered when a message is received. Provides the message content and a bool indicating if the data is binary.
    • onerror: Triggered when an error occurs.
    • onclose: Triggered when the connection is closed, providing a reason and a status code.

    Security Note: By default, Crow allows unmasked messages (violating protocol specs). For production, add #define CROW_ENFORCE_WS_SPEC to your source code to enforce the protocol.

    CROW_WEBSOCKET_ROUTE(app, "/ws")
        .onopen([&](crow::websocket::connection& conn){
                do_something();
                })
        .onclose([&](crow::websocket::connection& conn, const std::string& reason, uint16_t){
                do_something();
                })
        .onmessage([&](crow::websocket::connection& /*conn*/, const std::string& data, bool is_binary){
                    if (is_binary)
                        do_something(data);
                    else
                        do_something_else(data);
                });
  7. Use Crow project templates

    master

    Several third-party template repositories are available to help bootstrap Crow projects with different build systems and dependency managers:

    • crow_template: A GitHub template repository that uses CPM to include Crow and Catch2 for testing.
    • corax-template: A template featuring Make/Compile/Clean scripts, a Libs folder for external libraries (with Crow pre-configured), and clang-format rules.
    • cpp-backend-template: A GitHub template using CMake as the build system, vcpkg as the package manager, clang-format for code style, and built-in Docker support.
  8. Get started with Crow (Hello World)

    master

    To create a basic web server with Crow, instantiate crow::SimpleApp, define routes using the CROW_ROUTE macro, and start the server using .port(), .multithreaded(), and .run().

    #include "crow.h"
    
    int main()
    {
        crow::SimpleApp app;
    
        CROW_ROUTE(app, "/")([](){
            return "Hello world";
        });
    
        app.port(18080).multithreaded().run();
    }
  9. Use Local Middleware for Specific Routes or Blueprints

    master

    By default, middleware is global. To restrict middleware to specific handlers or blueprints, your middleware struct must inherit from crow::ILocalMiddleware.

    Execution Order: Global middleware is run first, followed by the enabled local middleware for the current handler. In both cases, they follow the order specified in the crow::App definition.

    To apply local middleware to a route, use .CROW_MIDDLEWARES(app, MiddlewareName). To apply it to a blueprint, use bp.CROW_MIDDLEWARES(app, MW1, MW2).

    // 1. Define the local middleware
    struct LocalMiddleware : crow::ILocalMiddleware
    {
        struct context {};
        void before_handle(crow::request& req, crow::response& res, context& ctx) {}
        void after_handle(crow::request& req, crow::response& res, context& ctx) {}
    };
    
    // 2. Apply to a specific route
    CROW_ROUTE(app, "/with_middleware")
    .CROW_MIDDLEWARES(app, LocalMiddleware)
    ([]() {
        return "Hello world!";
    });
    
    // 3. Apply to a blueprint
    Blueprint bp("with_middleware");
    bp.CROW_MIDDLEWARES(app, FistLocalMiddleware, SecondLocalMiddleware);
  10. Load and render Mustache templates

    master

    To use templates in a route, you must load a crow::mustache::template_t object and then render it with a context.

    Loading Templates

    • From a file: crow::mustache::load("path/to/template.html"). The path is relative to your templates directory. Note that paths are sanitized by default; use crow::mustache::load_unsafe() to bypass sanitization.
    • From a string: crow::mustache::compile("my mustache {{value}}").
    • Without mustache processing: crow::mustache::load_text("path/to/template.html").

    Rendering

    • With context: page.render(ctx) returns a crow::returnable object (setting the Content-Type header automatically).
    • Without context: page.render().
    • As a raw string: page.render_string() returns a simple std::string instead of a crow::returnable object.
  11. Implement Middleware in Crow

    master

    Middleware allows you to inspect or alter requests before and after the handler is called. To implement a middleware, you must define a struct containing three members:

    1. A context struct: Used for storing data local to the request.
    2. A before_handle method: Executed before the handler.
    3. An after_handle method: Executed after the handler.

    Important: If res.end() is called within a middleware, no further handlers or middleware will run, except for the after_handle methods of middleware that have already been visited.

    struct AdminAreaGuard
    {
        struct context
        {};
    
        void before_handle(crow::request& req, crow::response& res, context& ctx)
        {
            if (req.remote_ip_address != ADMIN_IP)
            {
                res.code = 403;
                res.end();
            }
        }
    
        void after_handle(crow::request& req, crow::response& res, context& ctx)
        {}
    };