DEV Community

Alex Spinov
Alex Spinov

Posted on

Qwik Has a Free API You Should Know About

Qwik takes a radical approach to web performance: zero JavaScript hydration. Its resumability model and server-side APIs make it one of the fastest frameworks available.

Resumability — No Hydration

Qwik serializes component state to HTML. When the user interacts, only the needed code loads:

import { component$, useSignal } from "@builder.io/qwik"

export const Counter = component$(() => {
  const count = useSignal(0)

  return (
    <div>
      <p>Count: {count.value}</p>
      <button onClick$={() => count.value++}>
        Increment
      </button>
    </div>
  )
})
// onClick$ handler downloads ONLY when clicked — not at page load!
Enter fullscreen mode Exit fullscreen mode

Server Loaders — Data Fetching

import { component$ } from "@builder.io/qwik"
import { routeLoader$ } from "@builder.io/qwik-city"

export const useProducts = routeLoader$(async ({ query, env }) => {
  const page = Number(query.get("page") || 1)
  const apiKey = env.get("API_KEY")

  const res = await fetch(`https://api.store.com/products?page=${page}`, {
    headers: { Authorization: `Bearer ${apiKey}` }
  })
  return res.json()
})

export default component$(() => {
  const products = useProducts()

  return (
    <div>
      {products.value.map(p => (
        <div key={p.id}>
          <h3>{p.name}</h3>
          <p>${p.price}</p>
        </div>
      ))}
    </div>
  )
})
Enter fullscreen mode Exit fullscreen mode

Server Actions — Mutations

import { component$ } from "@builder.io/qwik"
import { routeAction$, zod$, z, Form } from "@builder.io/qwik-city"

export const useCreatePost = routeAction$(
  async (data, { fail }) => {
    const post = await db.post.create({ data })
    if (!post) return fail(500, { message: "Failed to create" })
    return { success: true, id: post.id }
  },
  zod$({
    title: z.string().min(3),
    content: z.string().min(10)
  })
)

export default component$(() => {
  const action = useCreatePost()

  return (
    <Form action={action}>
      <input name="title" />
      {action.value?.fieldErrors?.title && (
        <p>{action.value.fieldErrors.title}</p>
      )}
      <textarea name="content" />
      <button type="submit">
        {action.isRunning ? "Saving..." : "Create"}
      </button>
      {action.value?.success && <p>Post created!</p>}
    </Form>
  )
})
Enter fullscreen mode Exit fullscreen mode

API Endpoints

// src/routes/api/users/index.tsx
import type { RequestHandler } from "@builder.io/qwik-city"

export const onGet: RequestHandler = async ({ json, query }) => {
  const limit = Number(query.get("limit") || 10)
  const users = await db.user.findMany({ take: limit })
  json(200, users)
}

export const onPost: RequestHandler = async ({ json, parseBody }) => {
  const body = await parseBody()
  const user = await db.user.create({ data: body })
  json(201, user)
}

export const onDelete: RequestHandler = async ({ json, query }) => {
  const id = query.get("id")
  await db.user.delete({ where: { id } })
  json(200, { deleted: true })
}
Enter fullscreen mode Exit fullscreen mode

Middleware

// src/routes/layout.tsx
import type { RequestHandler } from "@builder.io/qwik-city"

export const onRequest: RequestHandler = async ({ next, cookie, sharedMap }) => {
  const token = cookie.get("session")?.value
  if (token) {
    const user = await verifyToken(token)
    sharedMap.set("user", user)
  }
  await next()
}
Enter fullscreen mode Exit fullscreen mode

useTask$ — Server/Client Effects

import { component$, useTask$, useSignal } from "@builder.io/qwik"
import { isServer } from "@builder.io/qwik/build"

export default component$(() => {
  const data = useSignal(null)

  useTask$(async ({ track }) => {
    if (isServer) {
      // Runs on server during SSR
      data.value = await fetchFromDB()
    }
  })

  return <pre>{JSON.stringify(data.value, null, 2)}</pre>
})
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • Resumability — zero hydration, instant interactivity
  • routeLoader$ for server-side data fetching
  • routeAction$ for type-safe mutations with Zod
  • API endpoints with onGet/onPost/onDelete handlers
  • Middleware for auth and request processing
  • Lazy loading at the event handler level

Explore Qwik docs for the complete API.


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)