API routes: +server.js
Not every address should return an HTML page. A mobile app or a script on another site needs data as JSON. Such addresses — API routes — are described in SvelteKit in a +server.js file: it exports functions named after HTTP methods.
Answering GET
Create the folder src/routes/api/posts and the file +server.js in it:
// src/routes/api/posts/+server.js
import { json } from '@sveltejs/kit';
import { getPosts } from '$lib/server/posts.js';
export function GET() {
return json(getPosts());
}Open http://localhost:5173/api/posts — the browser shows the array of posts as JSON. The json function creates a Response object with the right Content-Type header. You can also return a plain new Response('text') — it is the standard object from the Fetch API.
Query parameters
The function receives an event object with the fields url, params, request. Let us add search by the ?q= string:
// src/routes/api/posts/+server.js
import { json } from '@sveltejs/kit';
import { getPosts } from '$lib/server/posts.js';
export function GET({ url }) {
const q = url.searchParams.get('q') ?? '';
const posts = getPosts().filter((post) => post.title.toLowerCase().includes(q.toLowerCase()));
return json(posts);
}The address /api/posts?q=runes returns only the post "What runes are".
Receiving data: POST
A POST function in the same file accepts JSON and creates a post:
// src/routes/api/posts/+server.js (add next to GET)
import { error } from '@sveltejs/kit';
import { addPost } from '$lib/server/posts.js';
export async function POST({ request }) {
const { title, body } = await request.json();
if (!title) {
error(400, 'A title is required');
}
const post = { slug: title.toLowerCase().replaceAll(' ', '-'), title, body };
addPost(post);
return json(post, { status: 201 });
}You can check it from the browser console on a page of the site:
// browser console at http://localhost:5173
const response = await fetch('/api/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'Third post', body: 'Text' })
});
console.log(response.status, await response.json());The console shows code 201 and the created post, and after a reload /blog has a new item in the list.
Page or API
+server.js and +page.svelte can live in the same folder: for a browser GET request with the Accept: text/html header SvelteKit serves the page, other requests go to +server.js. For clarity, APIs are usually kept in a separate src/routes/api folder.
Common mistake
Naming the functions in lowercase: export function get(). SvelteKit looks for an export named exactly after the method in capital letters — GET, POST, PUT, PATCH, DELETE. Otherwise the request gets a 405 error.