From 64feb1cdbda684a20c7b318b59505caec3f82f55 Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Thu, 4 Jan 2024 00:09:47 -0700 Subject: [PATCH] chore: extend http example, update docs and test (#24) --- .github/workflows/ci.yml | 2 +- README.md | 33 +++++++++++++++++++++++++++++++-- examples/basic.zig | 29 +++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0dce929..edbe82a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: TEST=$(extism call zig-out/bin/basic-example.wasm http_get --allow-host '*') echo $TEST - echo $TEST | grep '"userId": 1' + echo $TEST | grep 'user=1' TEST=$(extism call zig-out/bin/basic-example.wasm greet --config user=Benjamin) echo $TEST diff --git a/README.md b/README.md index 0309401..b6dce0b 100644 --- a/README.md +++ b/README.md @@ -271,7 +271,7 @@ extism call ./zig-out/bin/my-plugin.wasm log_stuff --log-level=debug ## HTTP -Sometimes it is useful to let a plug-in [make HTTP calls](https://pkg.go.dev/github.com/extism/go-pdk#HTTPRequest.Send). [See this example](example/http.go) +Sometimes it is useful to let a plug-in [make HTTP calls]. [see: Extism HTTP library](src/http.zig) ```zig const http = extism_pdk.http; @@ -290,8 +290,37 @@ export fn http_get() i32 { const res = plugin.request(req, null) catch unreachable; defer res.deinit(); + if (res.status != 200) { + plugin.setError("request failed"); + return @as(i32, res.status); + } + + // get the bytes for the response body + const body = res.body(allocator) catch unreachable; + // => { "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false } + const Todo = struct { + userId: u32, + id: u32, + title: []const u8, + completed: bool, + }; + const todo = std.json.parseFromSlice(Todo, allocator, body, .{}) catch |err| { + plugin.setError(std.fmt.allocPrint(allocator, "parse error: {any}", .{err}) catch unreachable); + return 1; + }; + defer todo.deinit(); + + // format a string with the todo data + const t = todo.value; + const tmpl = "[id={d}] '{s}' by user={d} is complete: {any}\n"; + const args = .{ t.id, t.title, t.userId, t.completed }; + const output = std.fmt.allocPrint(allocator, tmpl, args) catch unreachable; + + // allocate space for the output data + const outMem = plugin.allocateBytes(output); + // `outputMemory` provides a zero-copy way to write plugin data back to the host - plugin.outputMemory(res.memory); + plugin.outputMemory(outMem); return 0; } diff --git a/examples/basic.zig b/examples/basic.zig index e98ff1e..5687596 100644 --- a/examples/basic.zig +++ b/examples/basic.zig @@ -70,8 +70,34 @@ export fn http_get() i32 { const res = plugin.request(req, null) catch unreachable; defer res.deinit(); + if (res.status != 200) { + plugin.setError("request failed"); + return @as(i32, res.status); + } + + // get the bytes for the res body + const body = res.body(allocator) catch unreachable; + // => { "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false } + const Todo = struct { + userId: u32, + id: u32, + title: []const u8, + completed: bool, + }; + const todo = std.json.parseFromSlice(Todo, allocator, body, .{}) catch |err| { + plugin.setError(std.fmt.allocPrint(allocator, "parse error: {any}", .{err}) catch unreachable); + return 1; + }; + defer todo.deinit(); + + const t = todo.value; + const tmpl = "[id={d}] '{s}' by user={d} is complete: {any}\n"; + const args = .{ t.id, t.title, t.userId, t.completed }; + const output = std.fmt.allocPrint(allocator, tmpl, args) catch unreachable; + const outMem = plugin.allocateBytes(output); + // `outputMemory` provides a zero-copy way to write plugin data back to the host - plugin.outputMemory(res.memory); + plugin.outputMemory(outMem); return 0; } @@ -104,7 +130,6 @@ export fn add() i32 { const params = std.json.parseFromSlice(Add, allocator, input, std.json.ParseOptions{}) catch unreachable; const sum = Sum{ .sum = params.value.a + params.value.b }; - const output = std.json.stringifyAlloc(allocator, sum, std.json.StringifyOptions{}) catch unreachable; plugin.output(output); return 0;