Talk to the server
API endpoints live next to your pages, in src/api. A page fetches them like any other URL.
Add an endpoint
Create src/api/greeting.ts:
import { Api, api, get } from "@palinx/core";
@api("/greeting")
export default class Greeting extends Api {
@get("/")
show() {
return Response.json({ message: "Hello from the server" });
}
}@api("/greeting") mounts the class at /api/greeting; palinx adds the /api prefix. @get("/") makes show() answer GET requests there. A handler returns a standard Response.
With bun run dev running, the terminal counts the endpoint:
Routes: 2 pages, 1 APIand http://localhost:2500/api/greeting returns:
{"message":"Hello from the server"}Fetch it from the page
// There is no index.ts any more. `px dev` starts the server, and it finds
// this page because the file lives in src/routes/.
import { Route, html, signal } from "@palinx/core";
export default class Home extends Route {
private count = signal(0);
+ private message = signal("Loading...");
+ // Runs in the browser once the page is on screen.
+ async onMount() {
+ const res = await fetch("/api/greeting");
+ const body = await res.json();
+ this.message.set(body.message);
+ }
+
render() {
return html`
<h1>hello</h1>
+ <p>The server says: ${this.message()}</p>
<p>Clicked ${this.count()} times</p>
<button @click=${() => this.count.set(this.count() + 1)}>Click me</button>
`;
}
}onMount() runs in the browser once the page is on screen, so it's the place to fetch your own API. It can be async. The result goes into a signal, and the page updates when it arrives.
Help your editor with the decorators
@api and @get are legacy (experimental) TypeScript decorators. Palinx compiles them itself, so the app runs without any config, but your editor will flag them until you add a tsconfig.json:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"experimentalDecorators": true
},
"include": ["src"]
}experimentalDecorators is the setting that matters; the rest matches what the minimal template ships.
Run it
http://localhost:2500 shows The server says: Loading... briefly, then:
The server says: Hello from the serverThe counter still works.
How it works
The page is first rendered on the server with the signal's starting value. In the browser, onMount() requests /api/greeting, and the endpoint answers with JSON. An endpoint is just a class whose decorated methods answer requests; API endpoints covers other methods, parameters, request bodies and errors.
Next: Share logic with a service.