Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
menu
  1. Home
  2. /Web Development
  3. /Nextjs
  4. /Request Response Objects
Your Progress0%
0 of 70 completed

NextJS Topics

Getting Started

  • What is Next.js?
  • Next.js vs React - Key Differences
  • Creating Your First Next.js 15 Project
  • Next.js Project Structure Explained
  • App Router vs Pages Router

Routing Fundamentals

  • File-Based Routing Basics
  • Creating Pages with page.tsx
  • Dynamic Routes and Route Parameters
  • Catch-All and Optional Catch-All Routes
  • Route Groups for Organization
  • Parallel Routes
  • Intercepting Routes

Layouts and Pages

  • Understanding Layouts
  • Root Layout and Global Configuration
  • Nested Layouts
  • Templates vs Layouts
  • Loading States with loading.tsx
  • Error Handling with error.tsx

Server and Client Components

  • Understanding Server Components
  • Client Components with 'use client'
  • When to Use Server vs Client Components
  • Component Composition Patterns
  • Passing Props Between Server and Client
  • Server Component Patterns and Best Practices

Data Fetching

  • Fetching Data in Server Components
  • Parallel and Sequential Data Fetching
  • Data Fetching Patterns and Strategies
  • Caching and Revalidation
  • Revalidate and Cache Tags
  • Handling Loading and Error States in Data Fetching

Navigation and Links

  • Link Component Basics
  • useRouter Hook for Programmatic Navigation
  • usePathname and useSearchParams Hooks
  • Active Links and Navigation States
  • Redirects and Navigation Guards

Styling in Next.js

  • CSS Modules in Next.js
  • Tailwind CSS Setup and Configuration
  • Global Styles and CSS Variables
  • Next.js Font Optimization

Images and Media

  • Next.js Image Component Basics
  • Image Optimization and Best Practices
  • Working with Static Assets

Forms and Data Mutations

  • Understanding Server Actions
  • Form Handling with Server Actions
  • Form Validation and Error Handling
  • useFormStatus and useFormState Hooks
  • Revalidating Data After Mutations
  • Optimistic Updates

Metadata and SEO

  • Static Metadata Configuration
  • Dynamic Metadata Generation
  • Open Graph and Social Media Cards
  • Sitemap and Robots.txt

API Routes and Route Handlers

  • Route Handlers Introduction
  • GET and POST Request Handlers
  • Dynamic API Routes
  • Request and Response Objects
  • API Error Handling and Status Codes

Middleware and Advanced Features

  • Introduction to Middleware
  • Authentication with Middleware
  • Environment Variables and Configuration
  • Streaming and Suspense
  • Not Found and Global Error Pages

Deployment and Optimization

  • Understanding Static and Dynamic Rendering
  • generateStaticParams for Static Generation
  • Build and Production Optimization
  • Deploying to Vercel
  • Alternative Deployment Options
  • Performance Monitoring and Analytics

Real-World Projects

  • Project 1: E-commerce Product Catalog
  • Project 2: Dashboard with Authentication

Request and Response Objects

Working with headers, cookies, and HTTP features

Route Handlers use standard Web Request and Response APIs, making your code portable and familiar. Next.js extends these with NextRequest and NextResponse for convenience features like cookies, redirects, and rewrites. Master request/response objects and you'll handle headers, authentication, content types, and streaming with confidence!

Request Object

Web Request API Basics

app/api/info/route.ts
export async function GET(request: Request) {
  // Request properties
  console.log('Method:', request.method);           // 'GET'
  console.log('URL:', request.url);                 // Full URL
  console.log('Headers:', request.headers);         // Headers object
  
  // Parse URL
  const url = new URL(request.url);
  console.log('Pathname:', url.pathname);           // '/api/info'
  console.log('Search:', url.search);               // '?key=value'
  console.log('Host:', url.host);                   // 'localhost:3000'
  
  // Read headers
  const contentType = request.headers.get('content-type');
  const authorization = request.headers.get('authorization');
  const userAgent = request.headers.get('user-agent');
  
  return Response.json({
    method: request.method,
    url: request.url,
    contentType,
    userAgent,
  });
}

// ✅ Standard Web Request
// ✅ Portable to any runtime
// ✅ Familiar API

Reading Request Headers

app/api/auth/verify/route.ts
export async function GET(request: Request) {
  // Get single header
  const authorization = request.headers.get('authorization');
  
  if (!authorization) {
    return Response.json(
      { error: 'Authorization header required' },
      { status: 401 }
    );
  }
  
  // Parse Bearer token
  const token = authorization.replace('Bearer ', '');
  
  // Verify token
  try {
    const payload = await verifyToken(token);
    return Response.json({ user: payload });
  } catch (error) {
    return Response.json(
      { error: 'Invalid token' },
      { status: 401 }
    );
  }
}

// Common headers:
// - 'authorization': Auth credentials
// - 'content-type': Body type
// - 'accept': Accepted response types
// - 'user-agent': Client info
// - 'referer': Source page
// - 'cookie': Cookies string

// ✅ headers.get(name) - case-insensitive
// ✅ Returns null if not found
// ✅ Always validate before use

Reading Request Body

app/api/data/route.ts
export async function POST(request: Request) {
  // Method 1: JSON body
  const jsonBody = await request.json();
  console.log('JSON:', jsonBody);
  
  // Method 2: Form data
  const formData = await request.formData();
  console.log('Form field:', formData.get('fieldName'));
  
  // Method 3: Plain text
  const textBody = await request.text();
  console.log('Text:', textBody);
  
  // Method 4: Array buffer (binary)
  const buffer = await request.arrayBuffer();
  console.log('Buffer size:', buffer.byteLength);
  
  // Method 5: Blob
  const blob = await request.blob();
  console.log('Blob type:', blob.type);
  
  return Response.json({ success: true });
}

// ⚠️ Body can only be read ONCE
// Choose the right method for content-type:
// - application/json → request.json()
// - multipart/form-data → request.formData()
// - text/plain → request.text()
// - application/octet-stream → request.arrayBuffer()

// ✅ Each method is async
// ✅ Body stream consumed after reading

Request Body Streaming

app/api/upload/stream/route.ts
export async function POST(request: Request) {
  const reader = request.body?.getReader();
  
  if (!reader) {
    return Response.json(
      { error: 'No request body' },
      { status: 400 }
    );
  }
  
  let totalBytes = 0;
  
  while (true) {
    const { done, value } = await reader.read();
    
    if (done) break;
    
    totalBytes += value.length;
    console.log(`Received ${totalBytes} bytes`);
    
    // Process chunk...
  }
  
  return Response.json({
    message: 'Upload complete',
    totalBytes,
  });
}

// ✅ Stream large uploads
// ✅ Process data in chunks
// ✅ Memory efficient

NextRequest - Extended Request

NextRequest Features

app/api/info/route.ts
import { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  // NextRequest extends Request with:
  
  // 1. Cookies helper
  const sessionCookie = request.cookies.get('session');
  console.log('Session:', sessionCookie?.value);
  
  // 2. URL helpers
  console.log('Next URL:', request.nextUrl.pathname);
  console.log('Search params:', request.nextUrl.searchParams.get('key'));
  
  // 3. Geo location (when deployed)
  console.log('Country:', request.geo?.country);
  console.log('City:', request.geo?.city);
  console.log('Latitude:', request.geo?.latitude);
  
  // 4. IP address
  console.log('IP:', request.ip);
  
  // 5. All standard Request properties still available
  console.log('Headers:', request.headers.get('user-agent'));
  
  return Response.json({
    pathname: request.nextUrl.pathname,
    ip: request.ip,
    country: request.geo?.country,
  });
}

// ✅ NextRequest = Request + Next.js features
// ✅ Use when you need cookies/geo/IP
// ✅ Otherwise, Request is fine

Reading Cookies with NextRequest

app/api/auth/session/route.ts
import { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  // Get single cookie
  const session = request.cookies.get('session');
  
  if (!session) {
    return Response.json(
      { error: 'Not authenticated' },
      { status: 401 }
    );
  }
  
  console.log('Cookie name:', session.name);   // 'session'
  console.log('Cookie value:', session.value); // Token string
  
  // Get all cookies
  const allCookies = request.cookies.getAll();
  console.log('All cookies:', allCookies);
  
  // Check if cookie exists
  const hasSession = request.cookies.has('session');
  
  // Verify session
  const user = await verifySession(session.value);
  
  return Response.json({ user });
}

// ✅ request.cookies.get(name) - single cookie
// ✅ request.cookies.getAll() - all cookies
// ✅ request.cookies.has(name) - check existence
// ✅ Returns { name, value } object

NextURL Helpers

app/api/url-info/route.ts
import { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  // NextURL is parsed URL with helpers
  const { nextUrl } = request;
  
  // Path info
  console.log('Pathname:', nextUrl.pathname);       // '/api/url-info'
  console.log('Search:', nextUrl.search);           // '?key=value'
  console.log('Hash:', nextUrl.hash);               // '#section'
  
  // Search params (easier than new URL())
  const key = nextUrl.searchParams.get('key');
  const page = nextUrl.searchParams.get('page') || '1';
  
  // Base URL
  console.log('Origin:', nextUrl.origin);           // 'http://localhost:3000'
  console.log('Host:', nextUrl.host);               // 'localhost:3000'
  
  // Clone and modify
  const redirectUrl = nextUrl.clone();
  redirectUrl.pathname = '/new-path';
  redirectUrl.searchParams.set('from', 'api');
  
  return Response.json({
    pathname: nextUrl.pathname,
    params: Object.fromEntries(nextUrl.searchParams),
  });
}

// ✅ nextUrl.pathname - current path
// ✅ nextUrl.searchParams - easy param access
// ✅ nextUrl.clone() - create modified copy

Response Object

Creating Responses

app/api/responses/route.ts
export async function GET(request: Request) {
  // 1. JSON response (most common)
  return Response.json({ message: 'Hello' });
  
  // 2. JSON with status and headers
  return Response.json(
    { error: 'Not found' },
    { 
      status: 404,
      headers: {
        'X-Custom-Header': 'Value',
      },
    }
  );
  
  // 3. Plain text
  return new Response('Hello, World!', {
    status: 200,
    headers: {
      'Content-Type': 'text/plain',
    },
  });
  
  // 4. HTML
  return new Response('<h1>Hello</h1>', {
    headers: {
      'Content-Type': 'text/html',
    },
  });
  
  // 5. Redirect (use NextResponse)
  // return NextResponse.redirect(new URL('/path', request.url));
  
  // 6. No content
  return new Response(null, { status: 204 });
}

// ✅ Response.json() for JSON
// ✅ new Response() for other types
// ✅ Set status and headers in second arg

Setting Response Headers

app/api/files/download/route.ts
export async function GET(request: Request) {
  const fileContent = await getFileContent();
  
  return new Response(fileContent, {
    status: 200,
    headers: {
      // Content type
      'Content-Type': 'application/pdf',
      
      // Download filename
      'Content-Disposition': 'attachment; filename="document.pdf"',
      
      // Cache control
      'Cache-Control': 'public, max-age=3600',
      
      // CORS
      'Access-Control-Allow-Origin': '*',
      
      // Custom headers
      'X-File-Size': fileContent.length.toString(),
      'X-Generated-At': new Date().toISOString(),
    },
  });
}

// Common headers:
// - Content-Type: MIME type
// - Content-Disposition: Inline or attachment
// - Cache-Control: Caching directives
// - ETag: Cache validation
// - Location: Redirect target (with 3xx status)
// - Set-Cookie: Set cookies
// - Access-Control-*: CORS headers

// ✅ Headers object in second arg
// ✅ Case-insensitive names
// ✅ Values must be strings

Content Types

app/api/content/route.ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const format = searchParams.get('format');
  
  const data = {
    message: 'Hello',
    timestamp: new Date().toISOString(),
  };
  
  switch (format) {
    case 'json':
      return Response.json(data);
    
    case 'xml':
      const xml = `<?xml version="1.0"?>
<response>
  <message>${data.message}</message>
  <timestamp>${data.timestamp}</timestamp>
</response>`;
      return new Response(xml, {
        headers: { 'Content-Type': 'application/xml' },
      });
    
    case 'csv':
      const csv = `message,timestamp
${data.message},${data.timestamp}`;
      return new Response(csv, {
        headers: {
          'Content-Type': 'text/csv',
          'Content-Disposition': 'attachment; filename="data.csv"',
        },
      });
    
    case 'text':
      return new Response(`Message: ${data.message}`, {
        headers: { 'Content-Type': 'text/plain' },
      });
    
    default:
      return Response.json(data);
  }
}

// GET /api/content?format=json
// GET /api/content?format=xml
// GET /api/content?format=csv

// ✅ Support multiple formats
// ✅ Set correct Content-Type
// ✅ Use format parameter or Accept header

NextResponse - Extended Response

NextResponse Features

app/api/next-response/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
  // 1. JSON response (same as Response.json)
  return NextResponse.json({ message: 'Hello' });
  
  // 2. Redirect
  return NextResponse.redirect(new URL('/new-path', request.url));
  
  // 3. Rewrite (proxy to different URL)
  return NextResponse.rewrite(new URL('/api/other', request.url));
  
  // 4. Response with cookies
  const response = NextResponse.json({ success: true });
  response.cookies.set('name', 'value');
  return response;
  
  // 5. Next (pass to next middleware/handler)
  return NextResponse.next();
}

// ✅ NextResponse = Response + Next.js features
// ✅ Use for redirects, rewrites, cookies
// ✅ Otherwise, Response works fine

Setting Cookies

app/api/auth/login/route.ts
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const body = await request.json();
  
  // Authenticate user
  const user = await authenticate(body.email, body.password);
  
  if (!user) {
    return NextResponse.json(
      { error: 'Invalid credentials' },
      { status: 401 }
    );
  }
  
  // Create session token
  const sessionToken = await createSession(user.id);
  
  // Create response
  const response = NextResponse.json({
    success: true,
    user: {
      id: user.id,
      email: user.email,
    },
  });
  
  // Set cookie
  response.cookies.set('session', sessionToken, {
    httpOnly: true,                              // Not accessible via JS
    secure: process.env.NODE_ENV === 'production', // HTTPS only in prod
    sameSite: 'lax',                            // CSRF protection
    maxAge: 60 * 60 * 24 * 7,                   // 7 days
    path: '/',                                   // Available site-wide
  });
  
  return response;
}

// Cookie options:
// - httpOnly: Prevent JavaScript access (security)
// - secure: HTTPS only (production)
// - sameSite: 'strict' | 'lax' | 'none' (CSRF protection)
// - maxAge: Seconds until expiration
// - expires: Specific expiration date
// - path: Where cookie is available
// - domain: Cookie domain

// ✅ Create response first
// ✅ Then set cookies
// ✅ httpOnly for security
// ✅ secure in production

Deleting Cookies

app/api/auth/logout/route.ts
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const response = NextResponse.json({
    success: true,
    message: 'Logged out successfully',
  });
  
  // Method 1: Delete cookie
  response.cookies.delete('session');
  
  // Method 2: Set to expire immediately
  response.cookies.set('session', '', {
    maxAge: 0,
    path: '/',
  });
  
  return response;
}

// ✅ response.cookies.delete(name)
// ✅ Or set maxAge: 0
// ✅ Match original path

Redirects

app/api/redirect/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const target = searchParams.get('target');
  
  if (target === 'home') {
    // Redirect to homepage
    return NextResponse.redirect(new URL('/', request.url));
  }
  
  if (target === 'login') {
    // Redirect to login with return URL
    const loginUrl = new URL('/login', request.url);
    loginUrl.searchParams.set('returnTo', request.url);
    return NextResponse.redirect(loginUrl);
  }
  
  // External redirect
  if (target === 'docs') {
    return NextResponse.redirect('https://nextjs.org/docs');
  }
  
  // 301 Permanent redirect
  return NextResponse.redirect(new URL('/default', request.url), 301);
}

// Redirect status codes:
// - 302 (default): Temporary redirect
// - 301: Permanent redirect
// - 307: Temporary redirect (preserve method)
// - 308: Permanent redirect (preserve method)

// ✅ Use new URL() for internal redirects
// ✅ String URL for external redirects
// ✅ Include status code if needed

Streaming Responses

app/api/stream/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
  // Create readable stream
  const stream = new ReadableStream({
    async start(controller) {
      // Send data in chunks
      for (let i = 0; i < 10; i++) {
        const chunk = `Chunk ${i}
`;
        controller.enqueue(new TextEncoder().encode(chunk));
        
        // Simulate delay
        await new Promise(resolve => setTimeout(resolve, 500));
      }
      
      controller.close();
    },
  });
  
  return new Response(stream, {
    headers: {
      'Content-Type': 'text/plain',
      'Transfer-Encoding': 'chunked',
    },
  });
}

// Use cases:
// - Large file downloads
// - Real-time data feeds
// - Server-sent events (SSE)
// - Progressive data loading

// ✅ Memory efficient
// ✅ Start sending before complete
// ✅ Better user experience

Request/Response Structure

API routes using Request and Response features

appImportant

Select a file or folder to see details

Advanced Request/Response Examples

Example 1: File Upload with Progress

app/api/upload/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  try {
    const formData = await request.formData();
    const file = formData.get('file') as File;
    
    if (!file) {
      return NextResponse.json(
        { error: 'No file provided' },
        { status: 400 }
      );
    }
    
    // Validate file type
    const allowedTypes = ['image/jpeg', 'image/png', 'image/webp'];
    if (!allowedTypes.includes(file.type)) {
      return NextResponse.json(
        { error: `Invalid file type. Allowed: ${allowedTypes.join(', ')}` },
        { status: 400 }
      );
    }
    
    // Validate file size (5MB)
    const maxSize = 5 * 1024 * 1024;
    if (file.size > maxSize) {
      return NextResponse.json(
        { error: 'File too large. Maximum 5MB' },
        { status: 400 }
      );
    }
    
    // Convert to buffer
    const bytes = await file.arrayBuffer();
    const buffer = Buffer.from(bytes);
    
    // Save file
    const filename = `${Date.now()}-${file.name}`;
    await saveFile(filename, buffer);
    
    // Save to database
    const upload = await db.uploads.create({
      data: {
        filename,
        originalName: file.name,
        mimeType: file.type,
        size: file.size,
        url: `/uploads/${filename}`,
      },
    });
    
    return NextResponse.json(upload, { status: 201 });
  } catch (error) {
    console.error('Upload error:', error);
    return NextResponse.json(
      { error: 'Upload failed' },
      { status: 500 }
    );
  }
}

// ✅ FormData for files
// ✅ Validate type and size
// ✅ Save metadata to database

Example 2: API with Authentication

app/api/protected/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
  // Check session cookie
  const sessionCookie = request.cookies.get('session');
  
  if (!sessionCookie) {
    return NextResponse.json(
      { error: 'Unauthorized - No session' },
      { status: 401 }
    );
  }
  
  // Verify session
  try {
    const session = await verifySession(sessionCookie.value);
    
    if (!session || session.expired) {
      return NextResponse.json(
        { error: 'Unauthorized - Invalid session' },
        { status: 401 }
      );
    }
    
    // Get user data
    const user = await db.users.findUnique({
      where: { id: session.userId },
    });
    
    if (!user) {
      return NextResponse.json(
        { error: 'User not found' },
        { status: 404 }
      );
    }
    
    // Return protected data
    return NextResponse.json({
      user: {
        id: user.id,
        email: user.email,
        name: user.name,
      },
      session: {
        createdAt: session.createdAt,
        expiresAt: session.expiresAt,
      },
    });
  } catch (error) {
    console.error('Auth error:', error);
    return NextResponse.json(
      { error: 'Authentication failed' },
      { status: 401 }
    );
  }
}

// ✅ Read session cookie
// ✅ Verify session validity
// ✅ Return user data if authenticated
// ✅ Proper error responses

Example 3: Content Negotiation

app/api/data/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
  const data = await getData();
  
  // Check Accept header
  const accept = request.headers.get('accept') || '';
  
  // JSON (default)
  if (accept.includes('application/json') || !accept) {
    return NextResponse.json(data);
  }
  
  // XML
  if (accept.includes('application/xml')) {
    const xml = convertToXML(data);
    return new Response(xml, {
      headers: { 'Content-Type': 'application/xml' },
    });
  }
  
  // CSV
  if (accept.includes('text/csv')) {
    const csv = convertToCSV(data);
    return new Response(csv, {
      headers: {
        'Content-Type': 'text/csv',
        'Content-Disposition': 'attachment; filename="data.csv"',
      },
    });
  }
  
  // Unsupported format
  return NextResponse.json(
    { error: 'Unsupported format. Use JSON, XML, or CSV' },
    { status: 406 }
  );
}

// ✅ Check Accept header
// ✅ Return requested format
// ✅ 406 for unsupported formats

Request/Response Best Practices

1. Always Validate Headers

TYPESCRIPT
// ✅ GOOD: Check for null
const auth = request.headers.get('authorization');
if (!auth) {
  return Response.json({ error: 'Missing auth' }, { status: 401 });
}

// Validate format
if (!auth.startsWith('Bearer ')) {
  return Response.json({ error: 'Invalid auth format' }, { status: 401 });
}

// ❌ BAD: Assume header exists
const auth = request.headers.get('authorization');
const token = auth.replace('Bearer ', ''); // Crashes if null!

2. Use Proper Cookie Settings

TYPESCRIPT
// ✅ GOOD: Secure cookie settings
response.cookies.set('session', token, {
  httpOnly: true,       // Prevent XSS
  secure: true,         // HTTPS only
  sameSite: 'lax',      // CSRF protection
  maxAge: 86400,        // 1 day
  path: '/',
});

// ❌ BAD: Insecure settings
response.cookies.set('session', token); // No security options!

3. Set Correct Content-Type

TYPESCRIPT
// ✅ GOOD: Explicit Content-Type
return new Response(xmlData, {
  headers: { 'Content-Type': 'application/xml' },
});

// ✅ Response.json() sets Content-Type automatically
return Response.json(data); // Content-Type: application/json

// ❌ BAD: Wrong or missing Content-Type
return new Response(jsonString); // No Content-Type header!

4. Use Absolute URLs for Redirects

TYPESCRIPT
// ✅ GOOD: Absolute URL
return NextResponse.redirect(new URL('/path', request.url));

// ✅ GOOD: Full URL for external
return NextResponse.redirect('https://example.com');

// ❌ BAD: Relative path
return NextResponse.redirect('/path'); // Error!

5. Handle CORS Properly

TYPESCRIPT
// ✅ GOOD: CORS headers
export async function GET(request: Request) {
  const data = await getData();
  
  return NextResponse.json(data, {
    headers: {
      'Access-Control-Allow-Origin': 'https://trusted-site.com',
      'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    },
  });
}

// Handle preflight
export async function OPTIONS(request: Request) {
  return new Response(null, {
    status: 204,
    headers: {
      'Access-Control-Allow-Origin': 'https://trusted-site.com',
      'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    },
  });
}

Key Takeaways

  • Request vs NextRequest - NextRequest adds cookies, geo, IP
  • Response vs NextResponse - NextResponse adds cookies, redirects
  • request.headers.get() - returns null if missing
  • request.json() - parse JSON body (async)
  • response.cookies.set() - set cookies with options
  • NextResponse.redirect() - redirect with absolute URL
  • Content-Type header - set for non-JSON responses
  • httpOnly cookies - security best practice

What's Next?

You've mastered Request and Response objects! Next, we'll explore API Error Handling and Status Codes—building robust error responses, using appropriate HTTP status codes, creating consistent error formats, implementing try-catch patterns, and handling edge cases gracefully. You'll build production-ready APIs!

We'll cover error response patterns, status code selection, validation errors, database errors, and comprehensive error handling strategies.

🔒 Security Reminder

Always use httpOnly cookies for sessions, enable secure flag in production, validate all headers before use, set proper CORS headers, and never expose sensitive data in error messages. Security is non-negotiable!

Test Your Understanding

Question 1 of 4

What's the difference between Request and NextRequest?

Master Request and Response objects in Next.js! Learn headers, cookies, and HTTP handling.

Previous
Dynamic API Routes
Next
API Error Handling and Status Codes

Master Next.js APIs

Join 2,000+ developers building robust APIs with Next.js. Get the final API lesson on error handling - 100% FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

NextJS Tutorials

0 of 70 completed

Your Progress0%

Topics

Getting Started

  • What is Next.js?
  • Next.js vs React - Key Differences
  • Creating Your First Next.js 15 Project
  • Next.js Project Structure Explained
  • App Router vs Pages Router

Routing Fundamentals

  • File-Based Routing Basics
  • Creating Pages with page.tsx
  • Dynamic Routes and Route Parameters
  • Catch-All and Optional Catch-All Routes
  • Route Groups for Organization
  • Parallel Routes
  • Intercepting Routes

Layouts and Pages

  • Understanding Layouts
  • Root Layout and Global Configuration
  • Nested Layouts
  • Templates vs Layouts
  • Loading States with loading.tsx
  • Error Handling with error.tsx

Server and Client Components

  • Understanding Server Components
  • Client Components with 'use client'
  • When to Use Server vs Client Components
  • Component Composition Patterns
  • Passing Props Between Server and Client
  • Server Component Patterns and Best Practices

Data Fetching

  • Fetching Data in Server Components
  • Parallel and Sequential Data Fetching
  • Data Fetching Patterns and Strategies
  • Caching and Revalidation
  • Revalidate and Cache Tags
  • Handling Loading and Error States in Data Fetching

Navigation and Links

  • Link Component Basics
  • useRouter Hook for Programmatic Navigation
  • usePathname and useSearchParams Hooks
  • Active Links and Navigation States
  • Redirects and Navigation Guards

Styling in Next.js

  • CSS Modules in Next.js
  • Tailwind CSS Setup and Configuration
  • Global Styles and CSS Variables
  • Next.js Font Optimization

Images and Media

  • Next.js Image Component Basics
  • Image Optimization and Best Practices
  • Working with Static Assets

Forms and Data Mutations

  • Understanding Server Actions
  • Form Handling with Server Actions
  • Form Validation and Error Handling
  • useFormStatus and useFormState Hooks
  • Revalidating Data After Mutations
  • Optimistic Updates

Metadata and SEO

  • Static Metadata Configuration
  • Dynamic Metadata Generation
  • Open Graph and Social Media Cards
  • Sitemap and Robots.txt

API Routes and Route Handlers

  • Route Handlers Introduction
  • GET and POST Request Handlers
  • Dynamic API Routes
  • Request and Response Objects
  • API Error Handling and Status Codes

Middleware and Advanced Features

  • Introduction to Middleware
  • Authentication with Middleware
  • Environment Variables and Configuration
  • Streaming and Suspense
  • Not Found and Global Error Pages

Deployment and Optimization

  • Understanding Static and Dynamic Rendering
  • generateStaticParams for Static Generation
  • Build and Production Optimization
  • Deploying to Vercel
  • Alternative Deployment Options
  • Performance Monitoring and Analytics

Real-World Projects

  • Project 1: E-commerce Product Catalog
  • Project 2: Dashboard with Authentication
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo