8000 Tags · zigzap/zap · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Tags: zigzap/zap

Tags

v0.10.1

Toggle v0.10.1's commit message
__Rebased Zap's logging on Zig's std.log__

Zap's logging is now based on zig's `std.log`.

You can set a custom log level just for Zap in your Zig projects like
this:

```ts
pub const std_options: std.Options = .{
    // general log level
    .log_level = .info,
    .log_scope_levels = &[_]std.log.ScopeLevel{
        // log level specific to zap
        .{ .scope = .zap, .level = .debug },
    },
};
```

Low-level access to facil.io's logging facilities is provided by
`zap.Logging`.

v0.10.0

Toggle v0.10.0's commit message
**What's new in ZAP?**

- Upgraded to Zig 0.14!
- Breaking Changes for `zap.Endpoint`
- New `zap.App`!
- Updated README
- Contributions!

After a break, I'm about to work a lot more with Zap, and in preparation made a few improvements which might also work in favor of newcomers.

BTW newcomers: please, also check out these other, pure-zig (which Zap is not) HTTP server projects:

- [httpz](https://github.com/karlseguin/http.zig) : Pure Zig! Close to Zap's model. Performance = good!
- [jetzig](https://github.com/jetzig-framework/jetzig) : Comfortably develop modern web applications quickly, using http.zig under the hood
- [zzz](https://github.com/tardy-org/zzz) : Super promising, super-fast, especially for IO-heavy tasks, io_uring support - need I say more?

I can't wait for the day that Zap becomes obsolete. It would be a very good sign for the Zig HTTP server space!

**Breaking Changes for zap.Endpoint**

These breaking changes are meant to be improvements.

- no `@fieldParentPtr`: Endpoints now directly get their `@This()` pointer passed into their methods
- request handlers are allowed to return errors!
- the `.error_strategy` decides if errors are logged to console or reported as HTML to the client (for debugging in the browser)
- no "Settings":
    - `path` and `error_strategy` are required for Endpoints
    - all http method handlers must be present, but of course may be empty
    - all of the above are checked at comptime, with meaningful compile error messages
- you register your custom Endpoint instances directly with the
  `zap.Endpoint.Listener`, no need to provide an `.endpoint()` method.

It's best illustrated by example of `error.zig` (of the updated `endpoints` example) which creates the `ErrorEndpoint`:

```zig
//!
//! An ErrorEndpoint
//!
const std = @import("std");
const zap = @import("zap");

/// A simple endpoint listening on the /error route that causes an error on GET
/// requests, which gets logged to the response (=browser) by default
pub const ErrorEndpoint = @this();

path: []const u8 = "/error",
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,

pub fn get(_: *ErrorEndpoint, _: zap.Request) !void {
    return error.@"Oh-no!";
}

// unused:
pub fn post(_: *ErrorEndpoint, _: zap.Request) !void {}
pub fn put(_: *ErrorEndpoint, _: zap.Request) !void {}
pub fn delete(_: *ErrorEndpoint, _: zap.Request) !void {}
pub fn patch(_: *ErrorEndpoint, _: zap.Request) !void {}
pub fn options(_: *ErrorEndpoint, _: zap.Request) !void {}
```

All relevant examples have been updated accordingly.

**The New `zap.App`**

In a way, `zap.App` takes the `zap.Endpoint` concept one step further: instead of having only per-endpoint instance data (fields of your Endpoint struct), endpoints in a `zap.App` easily share a global 'App Context'.

In addition to the global App Context, all Endpoint request handlers also receive an arena allocator for easy, care-free allocations. There is one arena allocator per thread, and arenas are reset after each request.

Just like regular / legacy `zap.Endpoints`, returning errors from request handlers is OK. It's decided on a per-endpoint basis how errors are dealt with, via the `ErrorStrategy` enum field.

Here is a complete `zap.App` example:

```zig
//!
//! Part of the Zap examples.
//!
//! Build me with `zig build     app_basic`.
//! Run   me with `zig build run-app_basic`.
//!
const std = @import("std");
const Allocator = std.mem.Allocator;

const zap = @import("zap");

// The global Application Context
const MyContext = struct {
    db_connection: []const u8,

    pub fn init(connection: []const u8) MyContext {
        return .{
            .db_connection = connection,
        };
    }
};

// A very simple endpoint handling only GET requests
const SimpleEndpoint = struct {

    // zap.App.Endpoint Interface part
    path: []const u8,
    error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,

    // data specific for this endpoint
    some_data: []const u8,

    pub fn init(path: []const u8, data: []const u8) SimpleEndpoint {
        return .{
            .path = path,
            .some_data = data,
        };
    }

    // handle GET requests
    pub fn get(e: *SimpleEndpoint, arena: Allocator, context: *MyContext, r: zap.Request) !void {
        const thread_id = std.Thread.getCurrentId();

        r.setStatus(.ok);

        // look, we use the arena allocator here -> no need to free the response_text later!
        // and we also just `try` it, not worrying about errors
        const response_text = try std.fmt.allocPrint(
            arena,
            \\Hello!
            \\context.db_connection: {s}
            \\endpoint.data: {s}
            \\arena: {}
            \\thread_id: {}
            \\
        ,
            .{ context.db_connection, e.some_data, arena.ptr, thread_id },
        );
        try r.sendBody(response_text);
        std.time.sleep(std.time.ns_per_ms * 300);
    }

    // empty stubs for all other request methods
    pub fn post(_: *SimpleEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
    pub fn put(_: *SimpleEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
    pub fn delete(_: *SimpleEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
    pub fn patch(_: *SimpleEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
    pub fn options(_: *SimpleEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
};

const StopEndpoint = struct {
    path: []const u8,
    error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,

    pub fn get(_: *StopEndpoint, _: Allocator, context: *MyContext, _: zap.Request) !void {
        std.debug.print(
            \\Before I stop, let me dump the app context:
            \\db_connection='{s}'
            \\
            \\
        , .{context.*.db_connection});
        zap.stop();
    }

    pub fn post(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
    pub fn put(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
    pub fn delete(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
    pub fn patch(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
    pub fn options(_: *StopEndpoint, _: Allocator, _: *MyContext, _: zap.Request) !void {}
};

pub fn main() !void {
    // setup allocations
    var gpa: std.heap.GeneralPurposeAllocator(.{
        // just to be explicit
        .thread_safe = true,
    }) = .{};
    defer std.debug.print("\n\nLeaks detected: {}\n\n", .{gpa.deinit() != .ok});
    const allocator = gpa.allocator();

    // create an app context
    var my_context = MyContext.init("db connection established!");

    // create an App instance
    const App = zap.App.Create(MyContext);
    var app = try App.init(allocator, &my_context, .{});
    defer app.deinit();

    // create the endpoints
    var my_endpoint = SimpleEndpoint.init("/test", "some endpoint specific data");
    var stop_endpoint: StopEndpoint = .{ .path = "/stop" };
    //
    // register the endpoints with the app
    try app.register(&my_endpoint);
    try app.register(&stop_endpoint);

    // listen on the network
    try app.listen(.{
        .interface = "0.0.0.0",
        .port = 3000,
    });
    std.debug.print("Listening on 0.0.0.0:3000\n", .{});

    std.debug.print(
        \\ Try me via:
        \\ curl http://localhost:3000/test
        \\ Stop me via:
        \\ curl http://localhost:3000/stop
        \\
    , .{});

    // start worker threads -- only 1 process!!!
    zap.start(.{
        .threads = 2,
        .workers = 1,
    });
}
```

**Updated README**

- restructured the examples section a bit
- got rid of all the microbenchmark stuff
- shout-outs to great Zap alternatives (http.zig, Jetzig, zzz)

**Contributions!**

Special thanks to:

- Victor Moin (vctrmn): Fix deprecated warning in facil.io #154
- Joshua B. (OsakiTsukiko): updated .gitignore, Endpoint improvements
- Thom Dickson (cosmicboots): Add type checking to simple_router's handle_func #125

**What's coming up...?**

I am contemplating upgrading the underlying facil.io library to the new and improved version 0.8!

Thanks for reading and helping out 😊!

v0.9.1

Toggle v0.9.1's commit message
__**Bugfix for Middleware.EnpointHandler checkPath logic**__

I introduced a bug by wrongly trying to de-morgan the logic.

Thx @andr3h3nriqu3s11 for submitting issue #136 <#136>

I reverted the commit.

v0.9.0

Toggle v0.9.0's commit message
__**Small API Refactors**__

This is a small update from recent PRs with little breaking changes in
`zap.Mustache` and `zap.Middleware.EndpointHandler`. Thanks for the
great contributions! See the changelog below.

**Also: we now use zig fetch!**

This greatly simplifies the instructions in the README and release
notes.

__**Breaking Changes:**__

Mustache:
- renamed `zap.Mustache.MustacheLoadArgs` to `zap.Mustache.LoadArgs`
- `zap.Mustache.BuildResult` is a public type now

Middleware:
- `zap.Middleware.EndpointHandler` now takes more than one option:

```ts
/// Options used to change the behavior of an `EndpointHandler`
pub const EndpointHandlerOptions = struct {
    /// If `true`, the handler will stop handing requests down the chain if the
    /// endpoint processed the request.
    breakOnFinish: bool = true,

    /// If `true`, the handler will only execute against requests that match
    /// the endpoint's `path` setting.
    checkPath: bool = false,
};
```

I updated the docs and zig-master branch, too.

__**Changelog:**__

Rene Schallner (5):
      Merge pull request #117 from cosmicboots/mustache-build
      doc: getHeader need lowercase keys
      Merge pull request #120 from cosmicboots/endpoint-middleware
      Merge pull request #127 from iacore/patch-1
      docs, announceybot: switch to using zig fetch

Thom Dickson (4):
      include BuildResult in public Mustache API
      rename MustacheLoadArgs to LoadArgs
      Create options for EndpointHandler
      update docs and examples for endpoint middleware

iacore (1):
      update docs for zap.start

v0.8.0

Toggle v0.8.0's commit message
__Update to Zig 0.13__

With the help of our awesome contributers, we have a new release:

- Zap is now officially based on Zig 0.13.0!
- Thx to Lois Pearson, we now have `mimetypeRegister` and `mimetypeClear`
- Thx to geemili, we don't need to link facil.io in our build.zigs anymore
- Thx to Sören Michaels, `methodAsEnum` supports the `HEAD` method.
- ... and more, see the changelog below

**Note:** there now is a `zig-master` branch that gets updated with breaking changes of Zig master on a somewhat regular basis. Please feel free to send PRs.

Many thanks again to everyone who helped out:

Giuseppe Cesarano (1):
      fix: _debug typo in startWithLogging

Joe Koop (1):
      update http.zig to rfc9110 using MDN as a reference

Lord Asdi (1):
      fix: use std.process.getEnvVarOwned instead of std.posix.getenv

Louis Pearson (8):
      fix: last_modifed -> last_modified
      fix: docserver: server wasm with correct mimetype
      feat: Wrap mimetypeRegister and mimetypeClear
      fix: move getHeaderCommon to zap.zig
      feat: add parseAccept
      feat: make example for parseAccept
      fix: simplify accept header api somewhat
      feat: pre-allocate enough space for accept items

Michael Wendt (1):
      feat: remove deprecated path

Rene Schallner (18):
      Update hello_json.zig
      fix docserver invocation from build.zig
      proposed change to parseAccept API
      make zap master build with zig master
      update zig version
      updated zig-master check in CI
      update badge in README
      corrected release templates

Sören Michaels (1):
      feat: add HEAD Method to `methodAsEnum`

geemili (1):
      feat: streamline depending on zap by linking facil.io to module

v0.7.0

Toggle v0.7.0's commit message
__Update to Zig 0.12__

With the help of our awesome contributers, we have a new release:

- zap is now officially based on Zig 0.12.0!
- tests have been updated to use the latest `std.http` client
- @desttinghim added `getHeaderCommon` to `zap.Request`
- @leroycep improved error return traces in `zap.Request.sendError()`
- @dasimmet and @dweiller fixed the use of @fieldParentPtr to the new style
- @xflow-systems improved the write function of websockets

Users of `sendError()`: the API has changed! The doc comment has been updated. The new way of using it is:

```ts
r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505);
```

The new version outputs much nicer error traces.

**Note:** there will likely be a `zig-master` branch in the future that gets updated with breaking changes of Zig master. For sanity reasons, it will not be called `zig-0.13.0` but `zig-master`. I'll update the README accordingly then.

**Note 2:** I merged PRs and fixed the tests while waiting for my plane to board, then finished on the plane. If I might have rushed it and oopsied something up, I'll apologize and follow up with a bugfix release.

One open issue is using openssl on macOS, especially with openssl in custom locations, like homebrew-installed versions. If anyone wants to look into that: PRs are welcome 😊!

Many thanks again to everyone who helped out!

v0.6.0

Toggle v0.6.0's commit message
__Breaking change in zap.Router__

Latest zig master does not allow for multiple copies of the same anonymous type anymore. This broke zap.RequestHandler used by zap.Router.

So I rewrote zap.Router and zap.RequestHandler is gone.

To keep the APIs identical for both zig versions, I applied the rewrite patch also to the zig 0.11.0 (master) branch.

- [simple_router example](https://github.com/zigzap/zap/blob/master/examples/simple_router/simple_router.zig)
- [zap.Router documentation](https://zigzap.org/zap/#zap.router)

From a user perspective not much changed:

- for unbound route handlers, use `zap.Router.handle_route_unbound`.
- use `zap.Router.on_request_handler()` to get the request function to pass to a Listener.

**Note:** the 0.12.0 branch is currently broken with regard to tests due to changes in `std.http`.

__**Changelog**__ in alphabetical order:

GitHub Action (1):
      Update README

Rene Schallner (2):
      trying to add mastercheck badge to README
      re-write of zap.Router, fix #83

v0.5.1

Toggle v0.5.1's commit message
__Request.methodAsEnum() and Windows build error message__

This is a small update of recent PRs. Thanks for the great contributions!

See the changelog below for individual contributions.

- `zap.Request.methodAsEnum()` returns HTTP method as enum or .UNKNOWN
    - the reason the method is not an enum by default is to avoid the
      string comparisons on every request when we might not need them
- build attempts on Windows now produce a meaningful error message
- `zap.Request` now supports `getParamSlice()` and `getParamSlices()`
    which return optional string slices of the raw query string.
    - PRO: no allocation
    - CON: no decoding: "hello+zap" will not be decoded into "hello zap"
    - if you need decoding, you can still use `getParamStr()`.

I updated the docs and zig-0.12.0 branch, too, as with all recent and future releases.

__**Changelog**__ in alphabetical order:

Froxcey (4):
      Use std.http.Method for Request.method
      Use custom method enum
      Provide Windows error message
      Use debug.err and exit 1 for windows fail message

Joe Liotta (1):
      fixed unneeded optional unwrap in hello_json

Rene Schallner (8):
      Update README.md to point out even more prominently the zig master situation
      Merge pull request #72 from Chiissu/master
      Merge pull request #75 from Chiissu/windows-errmsg
      access raw query params w/o allocator, close #40
      cosmetics
      Merge pull request #79 from joeypas/master
      fix workflow to detect failing builds of individual samples
      in http.methodToEnum use std.meta.stringToEnum
      performance: revert r.method enum back to ?[]const u8
          (new http.Method enum is available via r.methodAsEnum())
      use methodAsEnum() in Endpoint, and in json example

v0.5.0

Toggle v0.5.0's commit message
__Introducing: zap.Router__

Thanks to StringNick, we now have `zap.Router` with handler closures support!

See the `simple_router` example. `zap.Router` is missing doc comments, so if anyone wants to step up, please feel free to send a PR against the `zig-0.12.0` my way.

BTW: Documentation (built on zig-0.12.0 branch) is now live at: <https://zigzap.org/zap>

Doc update PRs are welcome. I am especially excited about the _guides_ feature: <https://zigzap.org/zap/#G;>

__**Introduced:**__

- `zap.Router`: the router itself
- `zap.RequestHandler : a nice way to capture "self" pointers of containers of request functions.
- `simple_router`: example demonstrating the above

Thanks again to StringNick!

I updated the zig-0.12.0 branch, too, as with all recent and future releases.

v0.4.0

Toggle v0.4.0's commit message
__Breaking API Cleanup__

**Documentation (built on zig-0.12.0 branch) is now live at: <https://zigzap.org/zap>**

Doc update PRs are welcome. I am especially excited about the _guides_ feature: <https://zigzap.org/zap/#G;>

So, I spent a few days with a first pass of cleaning up Zap's API, informed by using it in production for over half a year now.

**__Refactored:__**

- no more type names starting with `Simple`.
    - zap.SimpleEndpoint -> zap.Endpoint
    - zap.SimpleRequest -> zap.Request
    - zap.SimpleHttpListener -> zap.HttpListener
    - ...
- zap.Endpoint : zap.Endpoint, zap.Endpoint.Authenticating
    - zap.Endpoint.Listener.register() // was: zap.EndpointListener.addEndpoint
- zap.Auth : zap.Auth.Basic, zap.Auth.BearerSingle, ...
- zap.Mustache : stayed the same
- zap.Request : refactored into its own file, along with supporting types and functions (e.g. http params related)
    - added setContentTypeFromFilename thx @hauleth.
- zap.Middleware: no more MixContexts
    - (zig structs are fine)
    - check example
- zap.fio : facilio C FFI stuff does not pollute zap namespace anymore
    - it is still available via `zap.fio`.
- allocators are always first-ish param: either first or after self
- more docstrings

All examples and tests have been updated. Also, check out the documentation (work in progress).
0