API Client
Use venjs.api.connect() to call external REST APIs. In a real project the API call lives in logic/ and the page component in components/ imports it.
venjs.api.connect(url, options)
Performs a fetch and returns the parsed JSON body. Throws an Error when the response is not OK.
| Option | Default | Description |
|---|---|---|
method | "GET" | HTTP method. |
headers | { "Content-Type": "application/json" } | Merged with your headers. |
body | — | If an object, it is JSON.stringify-ed automatically. |
any fetch option | — | Spread into the fetch config. |
const res = await venjs.api.connect("https://api.example.com/users/1", {
method: "GET",
mode: "cors"
});Error("HTTP 404: ..."). Always try/catch.venjs.api.query(key, fetcher, options)
Caches a fetcher's result keyed by key. Within the TTL the cached value is returned without re-running fetcher.
| Option | Default | Description |
|---|---|---|
ttl | 30000 | Time-to-live in milliseconds. |
force | false | When true, bypass the cache and re-fetch. |
const users = await venjs.api.query("all-users", () =>
venjs.api.connect("/api/users"), { ttl: 60000 });venjs.api.invalidate(key)
Deletes a single cache entry so the next query re-fetches.
venjs.api.invalidate("all-users");venjs.api.clearCache()
Empties the entire cache.
Real-life example: fetch users from an external API
A Home page with a button that fetches users from an external REST API. The API logic is isolated in logic/users.js and the UI lives in components/home.js.
File structure
venjs/
components/
home.js # HomePage — button + user list UI
logic/
users.js # fetchUsers() — venjs.api.connect() calllogic/users.js
This file contains only the API logic. It uses venjs.api.query to cache the result for 60 seconds so repeated button clicks don't spam the server.
export const fetchUsers = async () => {
const result = await venjs.api.query("external-users", () =>
venjs.api.connect("https://jsonplaceholder.typicode.com/users")
);
return result;
};components/home.js
The component imports fetchUsers, shows a button, and renders the list with loading/error states.
import { fetchUsers } from "../logic/users.js";
const HomePage = () => {
const users = venjs.signal([]);
const loading = venjs.signal(false);
const error = venjs.signal("");
const load = async () => {
loading.value = true;
error.value = "";
try {
const data = await fetchUsers();
users.value = Array.isArray(data) ? data : [];
} catch (err) {
error.value = "Failed to load users: " + err.message;
} finally {
loading.value = false;
}
};
return venjs.div({ class: "page" }, [
venjs.h1({ class: "page-title" }, "Users"),
venjs.button({
onclick: load,
disabled: loading.value
}, loading.value ? "Loading..." : "Fetch users"),
error.value ? venjs.p({ class: "status error" }, error.value) : null,
users.value.length ? venjs.ul({ class: "user-list" }, users.value.map(u =>
venjs.li({ class: "user-item" }, [
venjs.strong({}, u.name),
venjs.span({}, " — " + u.email)
])
)) : venjs.p({ class: "status" }, "No users loaded yet.")
]);
};
window.HomePage = HomePage;Real-life example: POST data to an external API
Sending form data to an external endpoint. The component collects inputs, the logic file posts them.
logic/contact.js
export const submitContact = async (name, email, message) => {
const result = await venjs.api.connect("https://api.example.com/contact", {
method: "POST",
body: { name, email, message }
});
return result;
};components/contact.js
import { submitContact } from "../logic/contact.js";
const ContactPage = () => {
const name = venjs.signal("");
const email = venjs.signal("");
const message = venjs.signal("");
const status = venjs.signal("");
const loading = venjs.signal(false);
const submit = async () => {
loading.value = true;
status.value = "";
try {
await submitContact(name.value, email.value, message.value);
status.value = "Message sent successfully!";
name.value = "";
email.value = "";
message.value = "";
} catch (err) {
status.value = "Error: " + err.message;
} finally {
loading.value = false;
}
};
return venjs.div({ class: "page" }, [
venjs.h1({ class: "page-title" }, "Contact Us"),
venjs.input({
label: "Name",
value: name.value,
oninput: (e) => (name.value = e.target.value)
}),
venjs.input({
label: "Email",
type: "email",
value: email.value,
oninput: (e) => (email.value = e.target.value)
}),
venjs.input({
label: "Message",
value: message.value,
oninput: (e) => (message.value = e.target.value)
}),
venjs.button({
onclick: submit,
disabled: loading.value
}, loading.value ? "Sending..." : "Send message"),
status.value ? venjs.p({ class: "status" }, status.value) : null
]);
};
window.ContactPage = ContactPage;