Integrations
Next.js
Integrate Corsair with Next.js App Router and Pages Router
Next.js
Corsair integrates seamlessly with Next.js App Router and Pages Router.
Installation
npm install corsair
npx corsair init --framework nextApp Router Setup
API Route
Create the Corsair API route:
import { corsair } from '@/lib/corsair'
export async function POST(req: Request) {
return corsair.handle(req)
}
export const runtime = 'nodejs'Client Setup
Configure the client provider:
'use client'
import { CorsairProvider, createCorsairClient } from 'corsair/client'
const corsairClient = createCorsairClient({
apiUrl: '/api/corsair',
})
export function Providers({ children }: { children: React.ReactNode }) {
return <CorsairProvider client={corsairClient}>{children}</CorsairProvider>
}Wrap your app:
import { Providers } from './providers'
export default function RootLayout({ children }) {
return (
<html>
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}Server Components
Use Corsair in Server Components:
import { corsair } from '@/lib/corsair'
export default async function PostsPage() {
const posts = await corsair.query('all published posts with authors')
return (
<div>
{posts.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>By {post.author.name}</p>
</article>
))}
</div>
)
}Client Components
Use hooks in Client Components:
'use client'
import { useCorsairMutation } from 'corsair/client'
export function CreatePost() {
const { mutate: createPost, isPending } = useCorsairMutation('create post')
return (
<form
onSubmit={e => {
e.preventDefault()
const formData = new FormData(e.currentTarget)
createPost({
title: formData.get('title'),
content: formData.get('content'),
})
}}
>
<input name="title" />
<textarea name="content" />
<button disabled={isPending}>Create</button>
</form>
)
}Server Actions
Use Corsair with Server Actions:
'use server'
import { corsair } from '@/lib/corsair'
import { revalidatePath } from 'next/cache'
export async function createPost(formData: FormData) {
const post = await corsair.mutate('create post', {
title: formData.get('title'),
content: formData.get('content'),
})
revalidatePath('/posts')
return post
}Use in components:
import { createPost } from './actions'
export function CreatePost() {
return (
<form action={createPost}>
<input name="title" />
<textarea name="content" />
<button>Create</button>
</form>
)
}Streaming
Stream data with Suspense:
import { Suspense } from 'react'
import { corsair } from '@/lib/corsair'
async function Posts() {
const posts = await corsair.query('all posts')
return <PostList posts={posts} />
}
export default function PostsPage() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Posts />
</Suspense>
)
}Middleware
Add authentication middleware:
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/api/corsair')) {
const session = request.cookies.get('session')
if (!session) {
return new NextResponse('Unauthorized', { status: 401 })
}
}
return NextResponse.next()
}Environment Variables
DATABASE_URL="postgresql://..."
NEXT_PUBLIC_API_URL="/api/corsair"Pages Router (Legacy)
For Pages Router, set up similarly:
import { corsair } from '@/lib/corsair'
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' })
}
return corsair.handle(req, res)
}