mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 15:14:08 +00:00
more sane endpoints example
This commit is contained in:
parent
3fa538081e
commit
c8f9a18dc0
5 changed files with 82 additions and 50 deletions
45
README.md
45
README.md
|
@ -33,9 +33,8 @@ Here's what works:
|
||||||
- **[hello_json](examples/hello_json/hello_json.zig)**: serves you json
|
- **[hello_json](examples/hello_json/hello_json.zig)**: serves you json
|
||||||
dependent on HTTP path
|
dependent on HTTP path
|
||||||
- **[endpoints](examples/endpoints/)**: a simple JSON REST API example featuring
|
- **[endpoints](examples/endpoints/)**: a simple JSON REST API example featuring
|
||||||
a `/users` endpoint for PUTting/DELETE-ing/GET-ting/POST-ing users and a
|
a `/users` endpoint for PUTting/DELETE-ing/GET-ting/POST-ing and listing
|
||||||
`/list` endpoint returning the entire user list on GET, together with a static
|
users, together with a static HTML and JavaScript frontend to play with.
|
||||||
HTML and JavaScript frontend to play around with.
|
|
||||||
|
|
||||||
I'll continue wrapping more of facil.io's functionality and adding stuff to zap
|
I'll continue wrapping more of facil.io's functionality and adding stuff to zap
|
||||||
to a point where I can use it as the JSON REST API backend for real research
|
to a point where I can use it as the JSON REST API backend for real research
|
||||||
|
@ -421,11 +420,10 @@ pub fn main() !void {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Endpoints.init(allocator, "/user", "/list");
|
Endpoints.init(allocator, "/users");
|
||||||
|
|
||||||
// add endpoints
|
// add endpoint
|
||||||
try listener.addEndpoint(Endpoints.getUserEndpoint());
|
try listener.addEndpoint(Endpoints.getUserEndpoint());
|
||||||
try listener.addEndpoint(Endpoints.getUserListEndpoint());
|
|
||||||
|
|
||||||
// fake some users
|
// fake some users
|
||||||
var uid: usize = undefined;
|
var uid: usize = undefined;
|
||||||
|
@ -454,34 +452,26 @@ const zap = @import("zap");
|
||||||
const Users = @import("users.zig");
|
const Users = @import("users.zig");
|
||||||
const User = Users.User;
|
const User = Users.User;
|
||||||
|
|
||||||
// the Endpoints
|
// the Endpoint
|
||||||
|
|
||||||
pub const Self = @This();
|
pub const Self = @This();
|
||||||
|
|
||||||
var alloc: std.mem.Allocator = undefined;
|
var alloc: std.mem.Allocator = undefined;
|
||||||
var endpoint: zap.SimpleEndpoint = undefined;
|
var endpoint: zap.SimpleEndpoint = undefined;
|
||||||
var list_endpoint: zap.SimpleEndpoint = undefined;
|
|
||||||
var users: Users = undefined;
|
var users: Users = undefined;
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
a: std.mem.Allocator,
|
a: std.mem.Allocator,
|
||||||
user_path: []const u8,
|
user_path: []const u8,
|
||||||
userlist_path: []const u8,
|
|
||||||
) void {
|
) void {
|
||||||
users = Users.init(a);
|
users = Users.init(a);
|
||||||
alloc = a;
|
alloc = a;
|
||||||
endpoint = zap.SimpleEndpoint.init(.{
|
endpoint = zap.SimpleEndpoint.init(.{
|
||||||
.path = user_path,
|
.path = user_path,
|
||||||
.get = getUser,
|
.get = getUser,
|
||||||
.post = null,
|
.post = postUser,
|
||||||
.put = null,
|
.put = putUser,
|
||||||
.delete = null,
|
.delete = deleteUser,
|
||||||
});
|
|
||||||
list_endpoint = zap.SimpleEndpoint.init(.{
|
|
||||||
.path = userlist_path,
|
|
||||||
.get = listUsers,
|
|
||||||
.post = null,
|
|
||||||
.put = null,
|
|
||||||
.delete = null,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,10 +483,6 @@ pub fn getUserEndpoint() *zap.SimpleEndpoint {
|
||||||
return &endpoint;
|
return &endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getUserListEndpoint() *zap.SimpleEndpoint {
|
|
||||||
return &list_endpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn userIdFromPath(path: []const u8) ?usize {
|
fn userIdFromPath(path: []const u8) ?usize {
|
||||||
if (path.len >= endpoint.settings.path.len + 2) {
|
if (path.len >= endpoint.settings.path.len + 2) {
|
||||||
if (path[endpoint.settings.path.len] != '/') {
|
if (path[endpoint.settings.path.len] != '/') {
|
||||||
|
@ -508,9 +494,12 @@ fn userIdFromPath(path: []const u8) ?usize {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
fn getUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
||||||
_ = e;
|
|
||||||
if (r.path) |path| {
|
if (r.path) |path| {
|
||||||
|
// /users
|
||||||
|
if (path.len == e.settings.path.len) {
|
||||||
|
return listUsers(e, r);
|
||||||
|
}
|
||||||
if (userIdFromPath(path)) |id| {
|
if (userIdFromPath(path)) |id| {
|
||||||
if (users.get(id)) |user| {
|
if (users.get(id)) |user| {
|
||||||
if (zap.stringify(user, .{})) |json| {
|
if (zap.stringify(user, .{})) |json| {
|
||||||
|
@ -521,13 +510,13 @@ pub fn getUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listUsers(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
fn listUsers(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
||||||
_ = e;
|
_ = e;
|
||||||
var l: std.ArrayList(User) = std.ArrayList(User).init(alloc);
|
var l: std.ArrayList(User) = std.ArrayList(User).init(alloc);
|
||||||
if (users.list(&l)) {} else |_| {
|
if (users.list(&l)) {} else |_| {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (zap.stringifyArrayList(std.ArrayList(User, &l, .{})) |maybe_json| {
|
if (zap.stringifyArrayList(User, &l, .{})) |maybe_json| {
|
||||||
if (maybe_json) |json| {
|
if (maybe_json) |json| {
|
||||||
_ = r.sendJson(json);
|
_ = r.sendJson(json);
|
||||||
}
|
}
|
||||||
|
@ -535,5 +524,7 @@ pub fn listUsers(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -3,19 +3,17 @@ const zap = @import("zap");
|
||||||
const Users = @import("users.zig");
|
const Users = @import("users.zig");
|
||||||
const User = Users.User;
|
const User = Users.User;
|
||||||
|
|
||||||
// the Endpoints
|
// the Endpoint
|
||||||
|
|
||||||
pub const Self = @This();
|
pub const Self = @This();
|
||||||
|
|
||||||
var alloc: std.mem.Allocator = undefined;
|
var alloc: std.mem.Allocator = undefined;
|
||||||
var endpoint: zap.SimpleEndpoint = undefined;
|
var endpoint: zap.SimpleEndpoint = undefined;
|
||||||
var list_endpoint: zap.SimpleEndpoint = undefined;
|
|
||||||
var users: Users = undefined;
|
var users: Users = undefined;
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
a: std.mem.Allocator,
|
a: std.mem.Allocator,
|
||||||
user_path: []const u8,
|
user_path: []const u8,
|
||||||
userlist_path: []const u8,
|
|
||||||
) void {
|
) void {
|
||||||
users = Users.init(a);
|
users = Users.init(a);
|
||||||
alloc = a;
|
alloc = a;
|
||||||
|
@ -26,13 +24,6 @@ pub fn init(
|
||||||
.put = putUser,
|
.put = putUser,
|
||||||
.delete = deleteUser,
|
.delete = deleteUser,
|
||||||
});
|
});
|
||||||
list_endpoint = zap.SimpleEndpoint.init(.{
|
|
||||||
.path = userlist_path,
|
|
||||||
.get = listUsers,
|
|
||||||
.post = null,
|
|
||||||
.put = null,
|
|
||||||
.delete = null,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getUsers() *Users {
|
pub fn getUsers() *Users {
|
||||||
|
@ -43,10 +34,6 @@ pub fn getUserEndpoint() *zap.SimpleEndpoint {
|
||||||
return &endpoint;
|
return &endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getUserListEndpoint() *zap.SimpleEndpoint {
|
|
||||||
return &list_endpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn userIdFromPath(path: []const u8) ?usize {
|
fn userIdFromPath(path: []const u8) ?usize {
|
||||||
if (path.len >= endpoint.settings.path.len + 2) {
|
if (path.len >= endpoint.settings.path.len + 2) {
|
||||||
if (path[endpoint.settings.path.len] != '/') {
|
if (path[endpoint.settings.path.len] != '/') {
|
||||||
|
@ -59,8 +46,11 @@ fn userIdFromPath(path: []const u8) ?usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
fn getUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
|
||||||
_ = e;
|
|
||||||
if (r.path) |path| {
|
if (r.path) |path| {
|
||||||
|
// /users
|
||||||
|
if (path.len == e.settings.path.len) {
|
||||||
|
return listUsers(e, r);
|
||||||
|
}
|
||||||
if (userIdFromPath(path)) |id| {
|
if (userIdFromPath(path)) |id| {
|
||||||
if (users.get(id)) |user| {
|
if (users.get(id)) |user| {
|
||||||
if (zap.stringify(user, .{})) |json| {
|
if (zap.stringify(user, .{})) |json| {
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<p><a href="/list">Show JSON for all users</a></p>
|
<p><a href="/users">Show JSON for all users</a></p>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding:20px; margin-top: 1rem;">
|
<div style="padding:20px; margin-top: 1rem;">
|
||||||
<label style="margin-bottom: 10px;">Log Output:</label>
|
<label style="margin-bottom: 10px;">Log Output:</label>
|
||||||
|
@ -155,7 +155,7 @@
|
||||||
first_name: first_name,
|
first_name: first_name,
|
||||||
last_name: last_name,
|
last_name: last_name,
|
||||||
}
|
}
|
||||||
sendJSON(data, "/user", "POST")
|
sendJSON(data, "/users", "POST")
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
log("SUCESS: " + JSON.stringify(data));
|
log("SUCESS: " + JSON.stringify(data));
|
||||||
|
@ -167,7 +167,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteUser(id) {
|
function deleteUser(id) {
|
||||||
fetch("/user/" + id, { method: "DELETE", } )
|
fetch("/users/" + id, { method: "DELETE", } )
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
log("SUCESS: " + JSON.stringify(data));
|
log("SUCESS: " + JSON.stringify(data));
|
||||||
|
@ -186,7 +186,7 @@
|
||||||
first_name: firstname,
|
first_name: firstname,
|
||||||
last_name: lastname,
|
last_name: lastname,
|
||||||
}
|
}
|
||||||
sendJSON(data, "/user/" + id, "PUT")
|
sendJSON(data, "/users/" + id, "PUT")
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
log("SUCESS: " + JSON.stringify(data));
|
log("SUCESS: " + JSON.stringify(data));
|
||||||
|
@ -242,7 +242,7 @@
|
||||||
|
|
||||||
|
|
||||||
function getUserList() {
|
function getUserList() {
|
||||||
fetch("/list", { method: "GET", } )
|
fetch("/users", { method: "GET", } )
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
log("SUCESS: " + JSON.stringify(data));
|
log("SUCESS: " + JSON.stringify(data));
|
||||||
|
|
|
@ -15,11 +15,10 @@ pub fn main() !void {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Endpoints.init(allocator, "/user", "/list");
|
Endpoints.init(allocator, "/users");
|
||||||
|
|
||||||
// add endpoints
|
// add endpoint
|
||||||
try listener.addEndpoint(Endpoints.getUserEndpoint());
|
try listener.addEndpoint(Endpoints.getUserEndpoint());
|
||||||
try listener.addEndpoint(Endpoints.getUserListEndpoint());
|
|
||||||
|
|
||||||
// fake some users
|
// fake some users
|
||||||
var uid: usize = undefined;
|
var uid: usize = undefined;
|
||||||
|
|
52
wrk/other_measurements.md
Normal file
52
wrk/other_measurements.md
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# other measurements
|
||||||
|
|
||||||
|
## zap wrk 'example' with and without logging
|
||||||
|
|
||||||
|
**NO** performance regressions observable:
|
||||||
|
|
||||||
|
With `logging=true`:
|
||||||
|
|
||||||
|
```
|
||||||
|
[nix-shell:~/code/github.com/renerocksai/zap]$ ./wrk/measure.sh zig > out 2> /dev/null
|
||||||
|
|
||||||
|
[nix-shell:~/code/github.com/renerocksai/zap]$ cat out
|
||||||
|
========================================================================
|
||||||
|
zig
|
||||||
|
========================================================================
|
||||||
|
Running 10s test @ http://127.0.0.1:3000
|
||||||
|
4 threads and 400 connections
|
||||||
|
Thread Stats Avg Stdev Max +/- Stdev
|
||||||
|
Latency 343.91us 286.75us 18.37ms 95.58%
|
||||||
|
Req/Sec 162.61k 3.61k 174.96k 76.75%
|
||||||
|
Latency Distribution
|
||||||
|
50% 302.00us
|
||||||
|
75% 342.00us
|
||||||
|
90% 572.00us
|
||||||
|
99% 697.00us
|
||||||
|
6470789 requests in 10.01s, 0.96GB read
|
||||||
|
Requests/sec: 646459.59
|
||||||
|
Transfer/sec: 98.03MB
|
||||||
|
```
|
||||||
|
|
||||||
|
With `logging=false`:
|
||||||
|
|
||||||
|
```
|
||||||
|
[nix-shell:~/code/github.com/renerocksai/zap]$ ./wrk/measure.sh zig
|
||||||
|
Listening on 0.0.0.0:3000
|
||||||
|
========================================================================
|
||||||
|
zig
|
||||||
|
========================================================================
|
||||||
|
Running 10s test @ http://127.0.0.1:3000
|
||||||
|
4 threads and 400 connections
|
||||||
|
Thread Stats Avg Stdev Max +/- Stdev
|
||||||
|
Latency 336.10us 122.28us 14.67ms 88.55%
|
||||||
|
Req/Sec 159.82k 7.71k 176.75k 56.00%
|
||||||
|
Latency Distribution
|
||||||
|
50% 310.00us
|
||||||
|
75% 343.00us
|
||||||
|
90% 425.00us
|
||||||
|
99% 699.00us
|
||||||
|
6359415 requests in 10.01s, 0.94GB read
|
||||||
|
Requests/sec: 635186.96
|
||||||
|
Transfer/sec: 96.32MB
|
||||||
|
```
|
Loading…
Add table
Reference in a new issue