DEV Community

Alex Spinov
Alex Spinov

Posted on

SvelteKit Has a Free API You Should Know About

SvelteKit ships with a built-in API layer that's both elegant and powerful. If you're building full-stack apps, SvelteKit's server-side features eliminate the need for a separate backend.

Load Functions — The Heart of SvelteKit

Every route can have a +page.server.js that loads data before rendering:

// src/routes/posts/+page.server.js
export async function load({ url, fetch }) {
  const page = url.searchParams.get("page") || 1
  const posts = await db.post.findMany({
    skip: (page - 1) * 10,
    take: 10,
    orderBy: { createdAt: "desc" }
  })
  const total = await db.post.count()

  return { posts, total, page: Number(page) }
}
Enter fullscreen mode Exit fullscreen mode
<!-- src/routes/posts/+page.svelte -->
<script>
  export let data
</script>

{#each data.posts as post}
  <article>
    <h2><a href="/posts/{post.slug}">{post.title}</a></h2>
    <p>{post.excerpt}</p>
  </article>
{/each}
Enter fullscreen mode Exit fullscreen mode

Form Actions — Mutations Made Simple

SvelteKit handles form submissions with progressive enhancement:

// src/routes/posts/new/+page.server.js
import { fail, redirect } from "@sveltejs/kit"

export const actions = {
  default: async ({ request }) => {
    const formData = await request.formData()
    const title = formData.get("title")
    const content = formData.get("content")

    if (!title || title.length < 3) {
      return fail(400, { title, content, error: "Title must be 3+ chars" })
    }

    const post = await db.post.create({ data: { title, content } })
    throw redirect(303, `/posts/${post.slug}`)
  }
}
Enter fullscreen mode Exit fullscreen mode
<!-- src/routes/posts/new/+page.svelte -->
<script>
  import { enhance } from "$app/forms"
  export let form
</script>

<form method="POST" use:enhance>
  <input name="title" value={form?.title ?? ""} />
  {#if form?.error}<p class="error">{form.error}</p>{/if}
  <textarea name="content">{form?.content ?? ""}</textarea>
  <button>Publish</button>
</form>
Enter fullscreen mode Exit fullscreen mode

API Routes (Server Endpoints)

Create pure API endpoints with +server.js:

// src/routes/api/posts/+server.js
import { json } from "@sveltejs/kit"

export async function GET({ url }) {
  const limit = Number(url.searchParams.get("limit") || 10)
  const posts = await db.post.findMany({ take: limit })
  return json(posts)
}

export async function POST({ request }) {
  const body = await request.json()
  const post = await db.post.create({ data: body })
  return json(post, { status: 201 })
}

export async function DELETE({ url }) {
  const id = url.searchParams.get("id")
  await db.post.delete({ where: { id } })
  return new Response(null, { status: 204 })
}
Enter fullscreen mode Exit fullscreen mode

Hooks — Global Request Processing

SvelteKit hooks intercept every request:

// src/hooks.server.js
export async function handle({ event, resolve }) {
  // Auth check
  const session = event.cookies.get("session")
  if (session) {
    event.locals.user = await getUserFromSession(session)
  }

  // Rate limiting
  const ip = event.getClientAddress()
  if (isRateLimited(ip)) {
    return new Response("Too many requests", { status: 429 })
  }

  const response = await resolve(event)
  response.headers.set("X-Frame-Options", "DENY")
  return response
}
Enter fullscreen mode Exit fullscreen mode

Streaming with Promises

Return promises to stream data:

// src/routes/dashboard/+page.server.js
export async function load() {
  return {
    quickStats: await getQuickStats(),
    // This streams — page renders immediately with quickStats
    heavyReport: getHeavyReport() // No await = streams!
  }
}
Enter fullscreen mode Exit fullscreen mode
<script>
  export let data
</script>

<h1>Dashboard</h1>
<QuickStats stats={data.quickStats} />

{#await data.heavyReport}
  <p>Loading report...</p>
{:then report}
  <HeavyReport {report} />
{/await}
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • Load functions fetch data server-side with automatic typing
  • Form actions handle mutations with progressive enhancement
  • +server.js files create pure API endpoints
  • Hooks intercept all requests for auth, logging, rate limiting
  • Streaming with promises for instant page loads
  • Zero-JS forms work without client-side JavaScript

Dive into SvelteKit docs for the full guide.


Building web scrapers or data pipelines? Check out my Apify actors for ready-made solutions, or email spinov001@gmail.com for custom development.

Top comments (0)