Skip to main content

Server-Side Functions

Server-side functions provide direct backend access within Next.js API routes and server components without client-side state management overhead.

Overview

Intrig generates server-side functions that run in Node.js environments, offering:

  • Direct API access without client-side state complexity
  • Automatic configuration using environment variables
  • Type-safe operations with full TypeScript support
  • Error handling optimized for server environments
  • No state management - each function call is independent

Function Types

Intrig generates two types of server functions for each API operation:

Action Functions (High-level)

Action functions provide simplified interfaces with automatic error handling and response parsing.

// app/api/users/route.ts
import { createUser, updateUser, deleteUser } from '@intrig/next/userApi/users/createUser/server';
import { updateUser as updateUserFunc } from '@intrig/next/userApi/users/updateUser/server';
import { deleteUser as deleteUserFunc } from '@intrig/next/userApi/users/deleteUser/server';

export async function POST(request: Request) {
const userData = await request.json();

try {
const newUser = await createUser(userData);
return Response.json(newUser, { status: 201 });
} catch (error) {
return Response.json({ error: error.message }, { status: 400 });
}
}

export async function PUT(request: Request) {
const { id, ...updates } = await request.json();

try {
const updatedUser = await updateUserFunc({ id, ...updates });
return Response.json(updatedUser);
} catch (error) {
return Response.json({ error: error.message }, { status: 400 });
}
}

export async function DELETE(request: Request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');

try {
await deleteUserFunc({ id });
return Response.json({ success: true });
} catch (error) {
return Response.json({ error: error.message }, { status: 400 });
}
}

Execute Functions (Low-level)

Execute functions provide access to raw response data and headers for advanced use cases.

// app/users/[id]/page.tsx
import { executeGetUser } from '@intrig/next/userApi/users/getUser/server';
import { executeGetUserPosts } from '@intrig/next/userApi/users/getUserPosts/server';

export default async function UserPage({ params }: { params: { id: string } }) {
try {
// Parallel data fetching with raw response access
const [userResponse, postsResponse] = await Promise.all([
executeGetUser({ id: params.id }),
executeGetUserPosts({ userId: params.id })
]);

return (
<div>
<UserProfile
user={userResponse.data}
lastModified={userResponse.headers['last-modified']}
/>
<UserPosts
posts={postsResponse.data}
totalCount={postsResponse.headers['x-total-count']}
/>
</div>
);
} catch (error) {
return <ErrorPage error={error} />;
}
}

Usage Patterns

API Route Implementation

// app/api/users/search/route.ts
import { searchUsers } from '@intrig/next/userApi/users/searchUsers/server';

export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const query = searchParams.get('q');
const limit = parseInt(searchParams.get('limit') || '10');

if (!query) {
return Response.json({ error: 'Query parameter required' }, { status: 400 });
}

try {
const results = await searchUsers({
query,
limit: Math.min(limit, 50) // Prevent excessive results
});

return Response.json(results);
} catch (error) {
console.error('Search error:', error);
return Response.json(
{ error: 'Search failed' },
{ status: 500 }
);
}
}

Server Component Data Fetching

// app/dashboard/page.tsx
import { getCurrentUser, getUserStats } from '@intrig/next/userApi/users/getCurrentUser/server';
import { getUserStats as getStatsFunc } from '@intrig/next/userApi/users/getUserStats/server';
import { getRecentOrders } from '@intrig/next/orderApi/orders/getRecentOrders/server';

export default async function DashboardPage() {
try {
const user = await getCurrentUser();

// Fetch user-specific data in parallel
const [stats, recentOrders] = await Promise.all([
getStatsFunc({ userId: user.id }),
getRecentOrders({ userId: user.id, limit: 5 })
]);

return (
<div>
<h1>Welcome back, {user.name}!</h1>
<DashboardStats stats={stats} />
<RecentActivity orders={recentOrders} />
</div>
);
} catch (error) {
return <div>Unable to load dashboard. Please try again.</div>;
}
}

Comprehensive Error Handling

// app/api/users/route.ts
import { createUser } from '@intrig/next/userApi/users/createUser/server';
import { z } from 'zod';

const createUserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().min(18).optional(),
});

export async function POST(request: Request) {
try {
const body = await request.json();

// Validate input
const validatedData = createUserSchema.parse(body);

// Call server function
const user = await createUser(validatedData);

return Response.json(user, { status: 201 });
} catch (error) {
// Handle validation errors
if (error instanceof z.ZodError) {
return Response.json(
{
error: 'Validation failed',
details: error.errors
},
{ status: 400 }
);
}

// Handle API errors
if (error.status) {
return Response.json(
{ error: error.message },
{ status: error.status }
);
}

// Handle unexpected errors
console.error('Unexpected error:', error);
return Response.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}

Basic Server Function Imports

// From consolidated server export
import { getUser, executeGetUser } from '@intrig/next/userApi/users/getUser/server';

// Or directly from function file
import { getUser, executeGetUser } from '@intrig/next/userApi/users/getUser/getUser';

Type Imports

// Parameter types (shared with client)
import type { GetUserParams } from '@intrig/next/userApi/users/getUser/GetUser.params';

// Response types
import type { User } from '@intrig/next/userApi/components/schemas/User';
import type { CreateUserRequest } from '@intrig/next/userApi/components/schemas/CreateUserRequest';

Multiple Function Imports

// Multiple operations from same controller
import {
getUser,
createUser,
updateUser,
deleteUser
} from '@intrig/next/userApi/users/getUser/server';

// Or individual imports for clarity
import { getUser } from '@intrig/next/userApi/users/getUser/server';
import { createUser } from '@intrig/next/userApi/users/createUser/server';
import { updateUser } from '@intrig/next/userApi/users/updateUser/server';

Server-side functions provide the foundation for robust, scalable Next.js applications by offering direct backend access while maintaining type safety and error handling best practices.