Building APIs with Next.js App Router: A Complete Guide
build API with Next.jsNext.js API tutorialcreating APIs with Next.jsTutorial

3 min read

In this tutorial, we'll learn how to build robust APIs using Next.js 14's App Router. We'll create a simple API for managing a book collection to demonstrate key concepts and best practices.

Prerequisites

  • Node.js installed on your system
  • Basic knowledge of JavaScript/TypeScript
  • Familiarity with Next.js fundamentals

Setting Up the Project

First, create a new Next.js project:

npx create-next-app@latest my-api-project
cd my-api-project

Project Structure

Our API will follow the Next.js App Router convention. Create the following structure:

app/
  api/
    books/
      route.ts
    books/[id]/
      route.ts

Creating the API Routes

1. GET and POST Endpoints (app/api/books/route.ts)

import { NextResponse } from 'next/server'

// In-memory storage for demonstration
let books = [
  { id: 1, title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },
  { id: 2, title: '1984', author: 'George Orwell' }
]

export async function GET() {
  return NextResponse.json(books)
}

export async function POST(request: Request) {
  try {
    const book = await request.json()
    
    // Validate input
    if (!book.title || !book.author) {
      return NextResponse.json(
        { error: 'Title and author are required' },
        { status: 400 }
      )
    }

    // Create new book
    const newBook = {
      id: books.length + 1,
      title: book.title,
      author: book.author
    }
    
    books.push(newBook)
    
    return NextResponse.json(newBook, { status: 201 })
  } catch (error) {
    return NextResponse.json(
      { error: 'Invalid request body' },
      { status: 400 }
    )
  }
}

2. Single Book Operations (app/api/books/[id]/route.ts)

import { NextResponse } from 'next/server'

export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  const book = books.find(b => b.id === parseInt(params.id))
  
  if (!book) {
    return NextResponse.json(
      { error: 'Book not found' },
      { status: 404 }
    )
  }
  
  return NextResponse.json(book)
}

export async function PUT(
  request: Request,
  { params }: { params: { id: string } }
) {
  try {
    const bookIndex = books.findIndex(b => b.id === parseInt(params.id))
    
    if (bookIndex === -1) {
      return NextResponse.json(
        { error: 'Book not found' },
        { status: 404 }
      )
    }
    
    const updatedBook = await request.json()
    
    // Validate input
    if (!updatedBook.title || !updatedBook.author) {
      return NextResponse.json(
        { error: 'Title and author are required' },
        { status: 400 }
      )
    }
    
    books[bookIndex] = {
      ...books[bookIndex],
      ...updatedBook
    }
    
    return NextResponse.json(books[bookIndex])
  } catch (error) {
    return NextResponse.json(
      { error: 'Invalid request body' },
      { status: 400 }
    )
  }
}

export async function DELETE(
  request: Request,
  { params }: { params: { id: string } }
) {
  const bookIndex = books.findIndex(b => b.id === parseInt(params.id))
  
  if (bookIndex === -1) {
    return NextResponse.json(
      { error: 'Book not found' },
      { status: 404 }
    )
  }
  
  books = books.filter(b => b.id !== parseInt(params.id))
  
  return NextResponse.json(
    { message: 'Book deleted successfully' },
    { status: 200 }
  )
}

Testing the API

You can test your API using cURL or tools like Postman. Here are some example requests:

Get All Books

curl http://localhost:3000/api/books

Create a Book

curl -X POST http://localhost:3000/api/books \
  -H "Content-Type: application/json" \
  -d '{"title": "Dune", "author": "Frank Herbert"}'

Get a Single Book

curl http://localhost:3000/api/books/1

Update a Book

curl -X PUT http://localhost:3000/api/books/1 \
  -H "Content-Type: application/json" \
  -d '{"title": "Updated Title", "author": "Updated Author"}'

Delete a Book

curl -X DELETE http://localhost:3000/api/books/1

Error Handling and Best Practices

  1. Input Validation: Always validate incoming request data
  2. HTTP Status Codes: Use appropriate status codes for different scenarios
  3. Error Messages: Provide clear error messages for better debugging
  4. Type Safety: Use TypeScript for better type checking and IDE support
  5. Response Format: Maintain consistent response format across endpoints

Conclusion

Next.js's App Router provides a powerful and intuitive way to build APIs. The file-based routing system makes it easy to organize your endpoints, while built-in features like automatic response parsing make handling requests straightforward.

Remember to:

  • Use appropriate HTTP methods for different operations
  • Implement proper error handling
  • Validate input data
  • Follow REST conventions
  • Use TypeScript for better type safety

For production applications, consider:

  • Adding authentication/authorization
  • Implementing rate limiting
  • Setting up a proper database
  • Adding request validation middleware
  • Implementing logging and monitoring

Related Posts

API Management Tools: A Comprehensive Overview
build API with Next.jsNext.js API tutorialcreating APIs with Next.jsTutorial

5 min read

APIs (Application Programming Interfaces) are the backbone of modern digital applications. They allow different software systems to communicate, exchange data, and collaborate seamlessly. As businesse...

API Security: Best Practices for Protecting Your Application
build API with Next.jsNext.js API tutorialcreating APIs with Next.jsTutorial

4 min read

In today’s interconnected digital world, APIs (Application Programming Interfaces) are the backbone of communication between different software applications. From mobile apps to cloud services, APIs e...

API Design Best Practices: Crafting Robust and Scalable APIs
build API with Next.jsNext.js API tutorialcreating APIs with Next.jsTutorial

5 min read

In the modern digital ecosystem, APIs (Application Programming Interfaces) serve as the backbone of connectivity. Whether you're building microservices, enabling integrations, or crafting data pipelin...