mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 15:14:08 +00:00
endpoints example: better web i/f
This commit is contained in:
parent
bc07f3393b
commit
29169149db
3 changed files with 197 additions and 36 deletions
|
@ -23,8 +23,8 @@ pub fn init(
|
|||
.path = user_path,
|
||||
.get = getUser,
|
||||
.post = postUser,
|
||||
.put = null,
|
||||
.delete = null,
|
||||
.put = putUser,
|
||||
.delete = deleteUser,
|
||||
});
|
||||
list_endpoint = zap.SimpleEndpoint.init(.{
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,18 @@
|
|||
border: 2px solid #cdb4db;
|
||||
padding: 15px;
|
||||
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 {
|
||||
background-color: #ffafcc;
|
||||
|
@ -37,32 +49,46 @@
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
table {
|
||||
background-color:#181818;
|
||||
}
|
||||
th {
|
||||
color: #B06060;
|
||||
padding: 15px;
|
||||
}
|
||||
td {
|
||||
color: #B0B0B0;
|
||||
}
|
||||
</style>
|
||||
<html>
|
||||
<body>
|
||||
<div class="center">
|
||||
<p><a href="/user/1">Show example user 1</a></p>
|
||||
<p><a href="/user/2">Show example user 2</a></p>
|
||||
<p><a href="/list">Show ALL users</a></p>
|
||||
<form >
|
||||
<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 >
|
||||
<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>
|
||||
<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;">
|
||||
<label style="margin-bottom: 10px;">Log Output:</label>
|
||||
<a id="logtoggler" onclick="toggleLog();" href="#">(hide)</a>
|
||||
<div class="center">
|
||||
<textarea id="log" style="width:80%; height: 18rem; display:block;"></textarea>
|
||||
<textarea id="log"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
|
@ -87,11 +113,11 @@
|
|||
eL.scrollTop = eL.scrollHeight;
|
||||
}
|
||||
|
||||
function sendJSON(data, slug) {
|
||||
function sendJSON(data, slug, method="POST") {
|
||||
json = JSON.stringify(data);
|
||||
log("SENDING: " + json);
|
||||
const response = fetch(slug, {
|
||||
method: "POST",
|
||||
method: method,
|
||||
body: json,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
|
@ -107,14 +133,80 @@
|
|||
first_name: first_name,
|
||||
last_name: last_name,
|
||||
}
|
||||
sendJSON(data, "/user")
|
||||
sendJSON(data, "/user", "POST")
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
log("SUCESS: " + JSON.stringify(data));
|
||||
getUserList();
|
||||
})
|
||||
.catch((error) => {
|
||||
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>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,6 +2,7 @@ const std = @import("std");
|
|||
|
||||
alloc: std.mem.Allocator = undefined,
|
||||
users: std.AutoHashMap(usize, InternalUser) = undefined,
|
||||
count: usize = 0,
|
||||
|
||||
pub const Self = @This();
|
||||
|
||||
|
@ -14,6 +15,7 @@ const InternalUser = struct {
|
|||
};
|
||||
|
||||
pub const User = struct {
|
||||
id: usize = 0,
|
||||
first_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
|
||||
/// completed, so we take copies of the names
|
||||
pub fn addByName(self: *Self, first: ?[]const u8, last: ?[]const u8) !usize {
|
||||
var created = try self.alloc.alloc(InternalUser, 1);
|
||||
var user = created[0];
|
||||
user.id = self.users.count() + 1;
|
||||
// TODO: get rid of the temp allocation here
|
||||
var temp = try self.alloc.alloc(InternalUser, 1);
|
||||
defer self.alloc.free(temp);
|
||||
var user = temp[0];
|
||||
self.count = self.count + 1;
|
||||
user.id = self.count;
|
||||
user.firstnamelen = 0;
|
||||
user.lastnamelen = 0;
|
||||
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 {
|
||||
if (self.users.get(id)) |pUser| {
|
||||
self.alloc.free(pUser);
|
||||
return self.users.remove(id);
|
||||
}
|
||||
return false;
|
||||
return self.users.remove(id);
|
||||
}
|
||||
|
||||
pub fn get(self: *Self, id: usize) ?User {
|
||||
if (self.users.get(id)) |pUser| {
|
||||
return .{
|
||||
.id = pUser.id,
|
||||
.first_name = pUser.firstnamebuf[0..pUser.firstnamelen],
|
||||
.last_name = pUser.lastnamebuf[0..pUser.lastnamelen],
|
||||
};
|
||||
|
@ -63,16 +65,22 @@ pub fn get(self: *Self, id: usize) ?User {
|
|||
return null;
|
||||
}
|
||||
|
||||
pub fn update(self: *Self, id: usize, first: ?[]const u8, last: ?[]const u8) bool {
|
||||
if (self.users.get(id)) |pUser| {
|
||||
pUser.firstnamelen = 0;
|
||||
pUser.lastnamelen = 0;
|
||||
pub fn update(
|
||||
self: *Self,
|
||||
id: usize,
|
||||
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| {
|
||||
std.mem.copy(u8, pUser.firstnamebuf[0..], firstname);
|
||||
pUser.firstnamelen = firstname.len;
|
||||
}
|
||||
if (last) |lastname| {
|
||||
std.mem.copy(u8, pUser.lastname[0..], lastname);
|
||||
std.mem.copy(u8, pUser.lastnamebuf[0..], lastname);
|
||||
pUser.lastnamelen = lastname.len;
|
||||
}
|
||||
return true;
|
||||
|
@ -104,6 +112,7 @@ const JsonUserIterator = struct {
|
|||
pub fn next(this: *This) ?User {
|
||||
if (this.it.next()) |pUser| {
|
||||
return User{
|
||||
.id = pUser.id,
|
||||
.first_name = pUser.firstnamebuf[0..pUser.firstnamelen],
|
||||
.last_name = pUser.lastnamebuf[0..pUser.lastnamelen],
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue