1
0
Fork 0
mirror of https://github.com/zigzap/zap.git synced 2025-10-20 23:24:09 +00:00

endpoints example: better web i/f

This commit is contained in:
Rene Schallner 2023-01-15 01:23:04 +01:00
parent bc07f3393b
commit 29169149db
3 changed files with 197 additions and 36 deletions

View file

@ -23,8 +23,8 @@ pub fn init(
.path = user_path, .path = user_path,
.get = getUser, .get = getUser,
.post = postUser, .post = postUser,
.put = null, .put = putUser,
.delete = null, .delete = deleteUser,
}); });
list_endpoint = zap.SimpleEndpoint.init(.{ list_endpoint = zap.SimpleEndpoint.init(.{
.path = userlist_path, .path = userlist_path,
@ -107,3 +107,63 @@ fn postUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
} }
} }
} }
fn putUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
_ = e;
if (r.path) |path| {
if (userIdFromPath(path)) |id| {
if (users.get(id)) |_| {
if (r.body) |body| {
var stream = std.json.TokenStream.init(body);
var maybe_user: ?User = std.json.parse(
User,
&stream,
.{ .allocator = alloc },
) catch null;
if (maybe_user) |u| {
defer std.json.parseFree(
User,
u,
.{ .allocator = alloc },
);
if (users.update(id, u.first_name, u.last_name)) {
if (zap.stringify(.{
.status = "OK",
.id = id,
}, .{})) |json| {
_ = r.sendJson(json);
}
} else {
if (zap.stringify(.{
.status = "ERROR",
.id = id,
}, .{})) |json| {
_ = r.sendJson(json);
}
}
}
}
}
}
}
}
fn deleteUser(e: *zap.SimpleEndpoint, r: zap.SimpleRequest) void {
_ = e;
if (r.path) |path| {
if (userIdFromPath(path)) |id| {
if (users.delete(id)) {
if (zap.stringify(.{ .status = "OK", .id = id }, .{})) |json| {
_ = r.sendJson(json);
}
} else {
if (zap.stringify(.{
.status = "ERROR",
.id = id,
}, .{})) |json| {
_ = r.sendJson(json);
}
}
}
}
}

View file

@ -23,6 +23,18 @@
border: 2px solid #cdb4db; border: 2px solid #cdb4db;
padding: 15px; padding: 15px;
margin-top: 10px; margin-top: 10px;
width: 80%;
height: 18rem;
}
form {
border: 2px solid #cdb4db;
border-radius: 12px;
padding: 15px;
margin-top: 10px;
font-size: 1em;
width: 80%;
text-align: center;
justify-content: center;
} }
button { button {
background-color: #ffafcc; background-color: #ffafcc;
@ -37,32 +49,46 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
table {
background-color:#181818;
}
th {
color: #B06060;
padding: 15px;
}
td {
color: #B0B0B0;
}
</style> </style>
<html> <html>
<body> <body>
<div class="center"> <div class="center">
<p><a href="/user/1">Show example user 1</a></p> <form >
<p><a href="/user/2">Show example user 2</a></p> <div>
<p><a href="/list">Show ALL users</a></p> <label>First name:</label><br>
<input id="first_name"></input>
</div>
<div>
<label>Last name:</label><br>
<input id="last_name"></input>
</div>
<div >
<button type="button" onclick="onNewUser();">Add new user!</button>
</div>
</form>
</div>
<div class="center">
<table id="usertable">
</table>
</div>
<div class="center">
<p><a href="/list">Show JSON for all users</a></p>
</div> </div>
<form style="text-align:center">
<div>
<label>First name:</label><br>
<input id="first_name"></input>
</div>
<div>
<label>Last name:</label><br>
<input id="last_name"></input>
</div>
<div class="center">
<button type="button" onclick="onNewUser();">Add new user!</button>
</div>
</form>
<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>
<a id="logtoggler" onclick="toggleLog();" href="#">(hide)</a> <a id="logtoggler" onclick="toggleLog();" href="#">(hide)</a>
<div class="center"> <div class="center">
<textarea id="log" style="width:80%; height: 18rem; display:block;"></textarea> <textarea id="log"></textarea>
</div> </div>
</div> </div>
<script> <script>
@ -87,11 +113,11 @@
eL.scrollTop = eL.scrollHeight; eL.scrollTop = eL.scrollHeight;
} }
function sendJSON(data, slug) { function sendJSON(data, slug, method="POST") {
json = JSON.stringify(data); json = JSON.stringify(data);
log("SENDING: " + json); log("SENDING: " + json);
const response = fetch(slug, { const response = fetch(slug, {
method: "POST", method: method,
body: json, body: json,
headers: { headers: {
"Content-Type": "application/json; charset=UTF-8" "Content-Type": "application/json; charset=UTF-8"
@ -107,14 +133,80 @@
first_name: first_name, first_name: first_name,
last_name: last_name, last_name: last_name,
} }
sendJSON(data, "/user") sendJSON(data, "/user", "POST")
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
log("SUCESS: " + JSON.stringify(data)); log("SUCESS: " + JSON.stringify(data));
getUserList();
}) })
.catch((error) => { .catch((error) => {
log("Error posting data"); log("Error posting data");
});} });
}
function deleteUser(id) {
fetch("/user/" + id, { method: "DELETE", } )
.then((response) => response.json())
.then((data) => {
log("SUCESS: " + JSON.stringify(data));
getUserList();
})
.catch((error) => {
log("Error posting data");
});
}
function addHeaderCell(tr, text) {
var th = document.createElement('TH');
th.innerHTML = text;
tr.appendChild(th);
}
function showTable(users) {
var t = document.getElementById("usertable");
var new_t = document.createElement("TABLE");
var header = new_t.createTHead();
var tr = header.insertRow();
// insertCell creates TD, we want TH
addHeaderCell(tr, 'id');
addHeaderCell(tr, 'first name');
addHeaderCell(tr, 'last name');
addHeaderCell(tr, 'action');
console.log("showTable()");
console.log(users);
// add the data rows
for(var i=0; i<users.length; i++) {
var row = new_t.insertRow();
var c1 = row.insertCell();
c1.innerHTML = users[i].id;
var c2 = row.insertCell();
c2.innerHTML = users[i].first_name;
var c3 = row.insertCell();
c3.innerHTML = users[i].last_name;
var c4 = row.insertCell();
c4.innerHTML = '<button type="button" onclick="deleteUser(' + users[i].id + ');">del</button>';
}
console.log("before replace");
t.innerHTML = new_t.innerHTML;
console.log("after replace");
}
function getUserList() {
fetch("/list", { method: "GET", } )
.then((response) => response.json())
.then((data) => {
log("SUCESS: " + JSON.stringify(data));
showTable(data);
})
.catch((error) => {
log("Error posting data");
});
}
function init() {
getUserList();
}
init();
</script> </script>
</body> </body>
</html> </html>

View file

@ -2,6 +2,7 @@ const std = @import("std");
alloc: std.mem.Allocator = undefined, alloc: std.mem.Allocator = undefined,
users: std.AutoHashMap(usize, InternalUser) = undefined, users: std.AutoHashMap(usize, InternalUser) = undefined,
count: usize = 0,
pub const Self = @This(); pub const Self = @This();
@ -14,6 +15,7 @@ const InternalUser = struct {
}; };
pub const User = struct { pub const User = struct {
id: usize = 0,
first_name: []const u8, first_name: []const u8,
last_name: []const u8, last_name: []const u8,
}; };
@ -28,9 +30,12 @@ pub fn init(a: std.mem.Allocator) Self {
/// the request will be freed (and reused by facilio) when it's /// the request will be freed (and reused by facilio) when it's
/// completed, so we take copies of the names /// completed, so we take copies of the names
pub fn addByName(self: *Self, first: ?[]const u8, last: ?[]const u8) !usize { pub fn addByName(self: *Self, first: ?[]const u8, last: ?[]const u8) !usize {
var created = try self.alloc.alloc(InternalUser, 1); // TODO: get rid of the temp allocation here
var user = created[0]; var temp = try self.alloc.alloc(InternalUser, 1);
user.id = self.users.count() + 1; defer self.alloc.free(temp);
var user = temp[0];
self.count = self.count + 1;
user.id = self.count;
user.firstnamelen = 0; user.firstnamelen = 0;
user.lastnamelen = 0; user.lastnamelen = 0;
if (first) |firstname| { if (first) |firstname| {
@ -46,16 +51,13 @@ pub fn addByName(self: *Self, first: ?[]const u8, last: ?[]const u8) !usize {
} }
pub fn delete(self: *Self, id: usize) bool { pub fn delete(self: *Self, id: usize) bool {
if (self.users.get(id)) |pUser| { return self.users.remove(id);
self.alloc.free(pUser);
return self.users.remove(id);
}
return false;
} }
pub fn get(self: *Self, id: usize) ?User { pub fn get(self: *Self, id: usize) ?User {
if (self.users.get(id)) |pUser| { if (self.users.get(id)) |pUser| {
return .{ return .{
.id = pUser.id,
.first_name = pUser.firstnamebuf[0..pUser.firstnamelen], .first_name = pUser.firstnamebuf[0..pUser.firstnamelen],
.last_name = pUser.lastnamebuf[0..pUser.lastnamelen], .last_name = pUser.lastnamebuf[0..pUser.lastnamelen],
}; };
@ -63,16 +65,22 @@ pub fn get(self: *Self, id: usize) ?User {
return null; return null;
} }
pub fn update(self: *Self, id: usize, first: ?[]const u8, last: ?[]const u8) bool { pub fn update(
if (self.users.get(id)) |pUser| { self: *Self,
pUser.firstnamelen = 0; id: usize,
pUser.lastnamelen = 0; first: ?[]const u8,
last: ?[]const u8,
) bool {
var user: ?InternalUser = self.users.get(id);
if (user) |*pUser| {
pUser.*.firstnamelen = 0;
pUser.*.lastnamelen = 0;
if (first) |firstname| { if (first) |firstname| {
std.mem.copy(u8, pUser.firstnamebuf[0..], firstname); std.mem.copy(u8, pUser.firstnamebuf[0..], firstname);
pUser.firstnamelen = firstname.len; pUser.firstnamelen = firstname.len;
} }
if (last) |lastname| { if (last) |lastname| {
std.mem.copy(u8, pUser.lastname[0..], lastname); std.mem.copy(u8, pUser.lastnamebuf[0..], lastname);
pUser.lastnamelen = lastname.len; pUser.lastnamelen = lastname.len;
} }
return true; return true;
@ -104,6 +112,7 @@ const JsonUserIterator = struct {
pub fn next(this: *This) ?User { pub fn next(this: *This) ?User {
if (this.it.next()) |pUser| { if (this.it.next()) |pUser| {
return User{ return User{
.id = pUser.id,
.first_name = pUser.firstnamebuf[0..pUser.firstnamelen], .first_name = pUser.firstnamebuf[0..pUser.firstnamelen],
.last_name = pUser.lastnamebuf[0..pUser.lastnamelen], .last_name = pUser.lastnamebuf[0..pUser.lastnamelen],
}; };