REST APIbackendAPI designinterview prep

REST API Design Interview Guide: Building Production-Ready APIs in 2025

V
Vibe Interviews Team
9 min read
REST API Design Interview Guide: Building Production-Ready APIs in 2025

API design interviews can be deceptively tricky. They start simple: "Design an API for a blog." Seems straightforward, right? But then the follow-up questions start rolling in: How do you handle pagination? What about rate limiting? How do you version your API? Suddenly you're making architectural decisions that affect scalability, security, and maintainability.

Here's what I've learned from designing APIs at various companies and interviewing candidates: most developers can create basic CRUD endpoints, but designing truly good APIs requires understanding principles, trade-offs, and real-world constraints. Let's break down what you need to know.

REST Fundamentals Everyone Should Know

Before we get into complex design questions, let's nail down the foundations. In interviews, I've seen senior developers stumble on basics because they've been using frameworks that abstract away fundamental concepts.

What REST Actually Means

REST (Representational State Transfer) is an architectural style, not a protocol. The key principles:

Resources are identified by URIs. /users/123 represents a specific user resource. The resource is the user, not the API endpoint.

Resources are manipulated through representations. When you GET /users/123, you receive a representation of that user (typically JSON). The server's internal user object might look completely different.

Requests are stateless. Each request contains all information needed to process it. The server doesn't maintain session state between requests. This is crucial for scalability.

Standard HTTP methods define operations:

  • GET retrieves resources
  • POST creates new resources
  • PUT updates/replaces resources
  • PATCH partially updates resources
  • DELETE removes resources

The Difference Between PUT and PATCH

This trips people up constantly. PUT should replace the entire resource. If you PUT a user with only an email, you're saying "this user now has only an email and no other properties."

PATCH modifies specific fields. PATCH with {"email": "new@email.com"} changes only the email, leaving other fields untouched.

In practice, many APIs use PUT for partial updates too, but understanding the semantic difference matters in interviews.

HTTP Status Codes That Matter

You don't need to memorize all 60+ status codes, but know these:

  • 200 OK: Successful GET, PUT, or PATCH
  • 201 Created: Successful POST that created a resource
  • 204 No Content: Successful DELETE or update with no response body
  • 400 Bad Request: Malformed request, validation error
  • 401 Unauthorized: Authentication required or failed
  • 403 Forbidden: Authenticated but lacking permissions
  • 404 Not Found: Resource doesn't exist
  • 409 Conflict: Request conflicts with current state
  • 429 Too Many Requests: Rate limit exceeded
  • 500 Internal Server Error: Something broke on the server
  • 503 Service Unavailable: Server temporarily unavailable

Using the right status code shows you understand HTTP semantics. Returning 200 with {"error": "not found"} in the body is a red flag.

For developers working with Node.js, understanding how these principles map to Express or Fastify routing is essential for implementation discussions.

Designing Resource-Oriented APIs

Here's where interviews get interesting. You're asked to design an API for something like a social media platform, e-commerce site, or project management tool.

Start with Resources, Not Actions

The RESTful approach models your API around resources (nouns), not actions (verbs).

Bad: /getUser, /createPost, /deleteComment Good: /users, /posts, /comments

The HTTP method indicates the action. DELETE /comments/123 is clearer than POST /deleteComment/123.

Designing Resource Hierarchies

Related resources often have hierarchical relationships:

/users/123/posts - all posts by user 123 /posts/456/comments - all comments on post 456

This makes relationships explicit in the URL structure. But be careful with deep nesting:

/users/123/posts/456/comments/789/likes

That's getting unwieldy. Generally, stick to 2-3 levels maximum. For deeper relationships, reference by ID:

/comments/789/likes is clearer than the nested version.

Naming Conventions That Matter

Use plural nouns for collections: /users, not /user

Use lowercase with hyphens for multi-word resources: /blog-posts, not /blogPosts or /BlogPosts

Be consistent. If you use user_id in one endpoint, don't switch to userId in another. This seems obvious, but I've interviewed at companies where APIs were inconsistent nightmares.

Filtering, Sorting, and Pagination

GET /users might return thousands of users. How do you handle this?

Filtering via query parameters: /users?role=admin&status=active

Sorting: /users?sort=created_at&order=desc

Pagination (several approaches):

Offset-based: /users?limit=20&offset=40 Simple but problematic when data changes between requests.

Cursor-based: /users?limit=20&cursor=eyJpZCI6MTIzfQ More robust, cursor encodes position in dataset.

Page-based: /users?page=3&per_page=20 Intuitive but has same issues as offset-based.

In interviews, discuss the trade-offs. Offset pagination is simpler to implement. Cursor pagination handles changing data better but is more complex.

Handling Complex Operations

Not everything fits cleanly into CRUD operations. How do you handle actions that don't map to simple resource manipulation?

Approach 1: Model It as a Resource

Instead of POST /posts/123/publish, create a publication resource: POST /posts/123/publications

This creates a publication record, which triggers the publishing action. The publication itself becomes a trackable resource.

Approach 2: Use Action-Oriented Endpoints (Pragmatically)

Sometimes it's clearer to break REST purity: POST /posts/123/publish POST /users/123/send-verification-email

These are technically RPC-style endpoints, but they're explicit and easy to understand. In production APIs, pragmatism often wins over purity.

Approach 3: Use PATCH with Specific Updates

PATCH /posts/123 with {"status": "published"}

This changes the post's state through a standard update operation.

In interviews, mention multiple approaches and discuss trade-offs. Shows you can think flexibly about design decisions.

Handling Bulk Operations

What if you need to delete multiple posts at once?

Option 1: Batch endpoint POST /posts/batch-delete with {"ids": [1, 2, 3]}

Option 2: Multiple requests Client sends multiple DELETE /posts/1, DELETE /posts/2, etc.

Option 3: Filter-based operations DELETE /posts?status=draft&created_before=2024-01-01

Each has pros and cons regarding atomicity, partial failures, and complexity.

Versioning Strategies

Your API will need to change. How do you handle breaking changes without breaking existing clients?

URI Versioning /v1/users, /v2/users

Pros: Explicit, easy to route different versions to different codebases Cons: Pollutes URI space, versions are resources not endpoints

Header Versioning Accept: application/vnd.myapi.v2+json

Pros: Cleaner URIs, follows HTTP semantics Cons: Less visible, harder to test in browsers

Query Parameter Versioning /users?version=2

Pros: Simple, easy to test Cons: Mixes versioning with filtering parameters

In interviews, I usually recommend URI versioning for external APIs (simplicity and clarity matter) and header versioning for internal APIs (more sophisticated, cleaner URIs).

Semantic Versioning for APIs

Following semantic versioning principles:

  • Major version (v1, v2): Breaking changes
  • Minor version (v1.1, v1.2): Backward-compatible new features
  • Patch version (v1.1.1): Backward-compatible bug fixes

Most APIs only version major versions in the URI, handling minor and patch updates transparently.

If you're designing APIs that need to scale, understanding system design principles is crucial for making the right architectural decisions.

Security and Authentication

A common interview question: "How would you secure this API?"

Authentication vs Authorization

Authentication: Verifying who you are Authorization: Verifying what you can do

Don't confuse them. JWT tokens handle authentication. Your business logic handles authorization.

Common Authentication Approaches

API Keys: Authorization: Bearer sk_live_51abc123... Simple, good for server-to-server, but user-specific authentication needs more.

JWT (JSON Web Tokens): Client includes token in Authorization header. Server verifies signature without database lookup. Great for stateless authentication.

OAuth 2.0: Industry standard for delegated authorization. "Log in with Google" uses OAuth. More complex but necessary for third-party integrations.

Session-based: Traditional approach with server-side sessions. Works but doesn't scale as easily as stateless approaches.

HTTPS Is Not Optional

Always require HTTPS for production APIs. Credentials and sensitive data should never travel over plain HTTP. This should be obvious, but I've seen production APIs without HTTPS.

Rate Limiting

Protect your API from abuse:

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1640000000

Common strategies:

  • Per-user limits (100 requests per minute per user)
  • Per-IP limits (for unauthenticated endpoints)
  • Different limits for different tiers (free vs paid)

CORS (Cross-Origin Resource Sharing)

If your API serves browser clients on different domains, you need CORS headers:

Access-Control-Allow-Origin: https://yourapp.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization

Understanding CORS is crucial for full-stack developers who work with both frontend and backend systems.

Error Handling

How you handle errors reveals API maturity.

Consistent Error Format

Bad:

{"error": "Not found"}

Better:

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "User with ID 123 not found",
    "details": {
      "resource": "user",
      "id": 123
    }
  }
}

Validation Errors Should Be Specific

When a request fails validation, tell the client exactly what's wrong:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "fields": {
      "email": "Must be a valid email address",
      "password": "Must be at least 8 characters"
    }
  }
}

This lets the client show field-specific errors instead of a generic "something went wrong."

Don't Leak Internal Errors

In production, internal errors should return generic messages:

{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "An unexpected error occurred",
    "request_id": "abc123"
  }
}

Log the full stack trace server-side with the request ID for debugging. Never expose database errors, stack traces, or internal paths to clients.

Performance Considerations

Caching Headers

Control how clients and intermediaries cache responses:

Cache-Control: public, max-age=3600
ETag: "abc123"
Last-Modified: Wed, 15 Nov 2024 12:00:00 GMT

Conditional requests save bandwidth:

If-None-Match: "abc123"

If data hasn't changed, return 304 Not Modified with no body.

Compression

Always support gzip/brotli compression:

Accept-Encoding: gzip, deflate, br

Can reduce payload sizes by 70%+ for JSON responses.

Field Selection

Allow clients to request only needed fields: /users/123?fields=id,name,email

This reduces payload size and processing time. GraphQL solves this more comprehensively, but you can implement basic field selection in REST.

Async Operations

For long-running operations, return 202 Accepted immediately:

HTTP/1.1 202 Accepted
Location: /jobs/789

Client can poll /jobs/789 for status. Or use webhooks to notify when complete.

Documentation and Developer Experience

Technical correctness isn't enough. APIs need to be usable.

OpenAPI/Swagger

Document your API with OpenAPI specification. This generates interactive documentation and enables code generation.

Good API documentation includes:

  • Clear descriptions of each endpoint
  • Request/response examples
  • Error codes and their meanings
  • Authentication requirements
  • Rate limits

SDK/Client Libraries

For public APIs, provide official client libraries in popular languages. This dramatically improves adoption.

Changelog

Maintain a public changelog documenting what changed in each version. Developers need to know when something breaks or when new features are available.

Common Interview Questions

"Design an API for a Twitter-like service"

Start with core resources: users, tweets, follows, likes.

POST /users (register)
GET /users/:id
POST /tweets
GET /tweets/:id
DELETE /tweets/:id
POST /tweets/:id/likes
DELETE /tweets/:id/likes
GET /users/:id/tweets
GET /users/:id/followers
POST /users/:id/follow

Discuss pagination for feeds, rate limiting for posting, authentication strategy, and how you'd handle the home timeline (complex query joining follows + tweets).

"How would you handle API versioning for a breaking change?"

Explain you'd create a new version (v2) while maintaining v1 for some deprecation period. Discuss how long to support old versions, how to communicate deprecation to clients, and strategies for migrating users.

"Design a rate limiting strategy"

Discuss token bucket or sliding window algorithms. Explain how you'd track limits (Redis, for example), what limits make sense (per-user, per-IP, different tiers), and how to communicate limits via headers.

For backend engineering roles, you'll likely dive deeper into implementation details like database design and server architecture.

Final Thoughts

Good API design balances theoretical principles with practical constraints. In interviews, show you understand REST principles but also know when to break them pragmatically.

Talk about trade-offs. There's rarely one "right" answer. Explaining why you chose one approach over another demonstrates depth of understanding.

And remember: the best way to prepare for API design interviews is to build APIs. Design a small API for a project you care about. Document it. Version it. Make it production-ready. That hands-on experience is invaluable in interviews.

The interviewer isn't looking for perfection. They want to see how you think through design problems, how you handle constraints, and whether you understand the principles that make APIs maintainable and scalable. Show you can design something developers will enjoy using, and you'll do well.

V

Vibe Interviews Team

Part of the Vibe Interviews team, dedicated to helping job seekers ace their interviews and land their dream roles.

Ready to Practice Your Interview Skills?

Apply what you've learned with AI-powered mock interviews. Get instant feedback and improve with every session.

Start Practicing Now

Continue Reading