Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Readme

This val shows how to break up your HTTP val into three vals:

I have these vals in a folder. Unfortunately, folders are not publicly shareable, which is why I listed all the vals above. The Val Town full-screen editor makes it a lot easier to work with multiple vals at once.

The trickiest and most interesting part of this particular demo is how we import just the zod type in the frontend which avoids the error if we were to import any real value from that shared file. In this sense, it's not a truly safe shared file.

Open questions

  1. I don't know why zod types aren't working when imported via esm.sh
  2. I don't know how we would get zod validation working on the frontend without reimporting zod from esm.sh (which would then lose us types or require us to duplicate the zod code)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { z } from "npm:zod@3.21.4";
import { UserSchema } from "./zod_demo_shared";
async function server(request: Request): Promise<Response> {
if (request.method === "POST" && new URL(request.url).pathname === "/register") {
try {
const body = await request.json();
const validatedUser = UserSchema.parse(body);
// Here you would typically save the user to a database
// For this demo, we'll just return a success message
return new Response(JSON.stringify({ message: "User registered successfully!" }), {
headers: { "Content-Type": "application/json" },
});
} catch (error) {
if (error instanceof z.ZodError) {
return new Response(JSON.stringify({ errors: error.errors }), {
status: 400,
headers: { "Content-Type": "application/json" },
});
}
return new Response("Internal Server Error", { status: 500 });
}
}
return new Response(
`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zod Demo</title>
<style>${css}</style>
</head>
<body>
<div id="root"></div>
<script type="module" src="https://esm.town/v/stevekrouse/zod_demo_frontend"></script>
</body>
</html>
`,
{
headers: { "Content-Type": "text/html" },
},
);
}
const css = `
body {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
form div {
margin-bottom: 10px;
}
label {
display: block;
margin-bottom: 5px;
}
input {
width: 100%;
padding: 5px;
}
.error {
color: red;
font-size: 0.8em;
}
.server-response {
margin-top: 20px;
padding: 10px;
background-color: #f0f0f0;
border: 1px solid #ddd;
}
`;
export default server;
stevekrouse-zod_demo_http.web.val.run
August 23, 2024