How to Create a Fake REST API in 5 Minutes
Need a REST API but don't have a backend? Whether you're learning, prototyping, or waiting for your backend team, this tutorial shows you three ways to create a fake REST API in under 5 minutes.
Why Use a Fake REST API?
- 🎓 Learning: Practice frontend development without setting up a backend
- 🚀 Prototyping: Build demos and MVPs quickly
- 🧪 Testing: Test your frontend with consistent data
- ⏰ Development: Don't wait for backend teams
Method 1: Symulate (Recommended - AI-Powered)
Best for: Production-quality fake APIs with realistic data
Setup time: 2 minutes
Step 1: Install the SDK
npm install @symulate/sdk
Step 2: Define Your Endpoints
Create api/posts.ts:
import { defineEndpoint, m, type Infer } from '@symulate/sdk'
// Define schema
const PostSchema = m.object({
id: m.uuid(),
title: m.lorem.sentence(),
body: m.lorem.paragraphs({ min: 2, max: 4 }),
author: m.person.fullName(),
publishedAt: m.date({ max: 'now' }),
likes: m.number({ min: 0, max: 1000 }),
comments: m.number({ min: 0, max: 50 })
})
// Infer TypeScript type
type Post = Infer<typeof PostSchema>
// Get all posts
export const getPosts = defineEndpoint<Post[]>({
path: '/api/posts',
method: 'GET',
schema: PostSchema,
mock: {
count: 15 // Generate 15 posts
}
})
// Get single post
export const getPost = defineEndpoint<Post>({
path: '/api/posts/:id',
method: 'GET',
params: [
{
name: 'id',
location: 'path',
required: true,
schema: m.uuid()
}
],
schema: PostSchema
})
// Create post
export const createPost = defineEndpoint<Post>({
path: '/api/posts',
method: 'POST',
params: [
{
name: 'title',
location: 'body',
required: true,
schema: m.string()
},
{
name: 'body',
location: 'body',
required: true,
schema: m.string()
}
],
schema: PostSchema
})
Step 3: Use in Your App
import { getPosts, createPost } from './api/posts'
// Fetch posts
async function loadPosts() {
const posts = await getPosts()
console.log(posts) // Array of realistic post objects
}
// Create a post
async function addPost() {
const newPost = await createPost({
title: 'My First Post',
body: 'This is the content...'
})
console.log(newPost) // Newly created post
}
That's it! You now have a working REST API with:
- ✅ Realistic AI-generated data
- ✅ Full TypeScript support
- ✅ No server to run
- ✅ Smart cloud caching for faster responses
Generation Modes
By default, Symulate uses AI to generate realistic, contextual data. However, you can also use:
Faker Mode - For CI/CD and unlimited free generation:
import { configureSymulate } from '@symulate/sdk'
configureSymulate({
generateMode: 'faker' // Unlimited free mode using Faker.js
})
Auto Mode - Automatically falls back to Faker when AI tokens run out:
configureSymulate({
generateMode: 'auto' // Uses AI first, falls back to Faker (default)
})
Per-Endpoint Override - Force mock mode for specific endpoints:
export const getPosts = defineEndpoint({
path: '/api/posts',
method: 'GET',
schema: PostSchema,
mock: {
count: 10 // Generate 10 posts
},
mode: 'mock' // Force mock mode even in production
})
Note: The mode parameter forces either 'mock' or 'production' mode for a specific endpoint, overriding the global environment setting. The mock generation type (AI or Faker) is still controlled by the global generateMode in configureSymulate.
Method 2: JSON Server (Quickest Setup)
Best for: Simple prototypes and learning
Setup time: 1 minute
Step 1: Install JSON Server
npm install -g json-server
Step 2: Create Data File
Create db.json:
{
"posts": [
{
"id": 1,
"title": "Hello World",
"body": "This is my first post",
"author": "John Doe",
"publishedAt": "2025-01-15"
},
{
"id": 2,
"title": "Learning REST APIs",
"body": "REST APIs are awesome!",
"author": "Jane Smith",
"publishedAt": "2025-01-16"
}
],
"comments": [
{
"id": 1,
"postId": 1,
"text": "Great post!",
"author": "Alice"
}
]
}
Step 3: Start the Server
json-server --watch db.json --port 3000
Step 4: Use the API
You automatically get these endpoints:
# Get all posts
GET http://localhost:3000/posts
# Get single post
GET http://localhost:3000/posts/1
# Create post
POST http://localhost:3000/posts
# Update post
PUT http://localhost:3000/posts/1
PATCH http://localhost:3000/posts/1
# Delete post
DELETE http://localhost:3000/posts/1
# Search/filter
GET http://localhost:3000/posts?author=John%20Doe
GET http://localhost:3000/posts?_sort=publishedAt&_order=desc
Bonus features:
- Pagination:
?_page=1&_limit=10 - Full-text search:
?q=hello - Relationships:
/posts/1/comments - Custom routes via
routes.json
Method 3: Mocky (No Installation)
Best for: Quick demos and sharing
Setup time: 30 seconds
Step 1: Go to Mocky.io
Visit https://designer.mocky.io
Step 2: Create Your Mock
- Set HTTP Method (GET, POST, etc.)
- Set Status Code (200, 404, etc.)
- Add Response Body:
{
"posts": [
{
"id": "uuid-1",
"title": "Hello World",
"author": "John Doe"
},
{
"id": "uuid-2",
"title": "Mock APIs",
"author": "Jane Smith"
}
]
}
- Click Generate
Step 3: Use the URL
You get a URL like:
https://run.mocky.io/v3/abc123...
Use it in your code:
fetch('https://run.mocky.io/v3/abc123...')
.then(res => res.json())
.then(data => console.log(data))
Limitations:
- Fixed responses (no dynamic data)
- Manual setup for each endpoint
- Requires internet connection
Full Example: Blog Application
Let's build a complete fake API for a blog:
Using Symulate (Full Example)
// api/blog.ts
import { defineEndpoint, m, type Infer } from '@symulate/sdk'
// Schemas
const AuthorSchema = m.object({
id: m.uuid(),
name: m.person.fullName(),
avatar: m.internet.avatar(),
bio: m.lorem.sentence()
})
const CommentSchema = m.object({
id: m.uuid(),
author: AuthorSchema,
text: m.lorem.paragraph(),
createdAt: m.date({ max: 'now' }),
likes: m.number({ min: 0, max: 50 })
})
const PostSchema = m.object({
id: m.uuid(),
title: m.lorem.sentence(),
slug: m.lorem.slug(),
body: m.lorem.paragraphs({ min: 3, max: 6 }),
excerpt: m.lorem.paragraph(),
author: AuthorSchema,
publishedAt: m.date({ max: 'now' }),
updatedAt: m.date({ max: 'now' }),
tags: m.array(m.string('blog post tag'), { min: 2, max: 5 }),
likes: m.number({ min: 0, max: 500 }),
views: m.number({ min: 100, max: 10000 }),
commentsCount: m.number({ min: 0, max: 50 })
})
// Infer TypeScript types
type Author = Infer<typeof AuthorSchema>
type Comment = Infer<typeof CommentSchema>
type Post = Infer<typeof PostSchema>
// Response type for getPosts
const GetPostsResponseSchema = m.object({
posts: m.array(PostSchema),
total: m.number(),
page: m.number(),
limit: m.number()
})
type GetPostsResponse = Infer<typeof GetPostsResponseSchema>
// Endpoints
export const getPosts = defineEndpoint<GetPostsResponse>({
path: '/api/posts',
method: 'GET',
params: [
{
name: 'page',
location: 'query',
required: false,
schema: m.number()
},
{
name: 'limit',
location: 'query',
required: false,
schema: m.number()
},
{
name: 'tag',
location: 'query',
required: false,
schema: m.string()
}
],
schema: GetPostsResponseSchema,
mock: {
count: 1 // Returns single object containing posts array
}
})
export const getPost = defineEndpoint<Post>({
path: '/api/posts/:slug',
method: 'GET',
params: [
{
name: 'slug',
location: 'path',
required: true,
schema: m.string()
}
],
schema: PostSchema
})
export const getComments = defineEndpoint<Comment[]>({
path: '/api/posts/:postId/comments',
method: 'GET',
params: [
{
name: 'postId',
location: 'path',
required: true,
schema: m.uuid()
}
],
schema: CommentSchema,
mock: {
count: 10 // Generate 10 comments
}
})
export const createComment = defineEndpoint<Comment>({
path: '/api/posts/:postId/comments',
method: 'POST',
params: [
{
name: 'postId',
location: 'path',
required: true,
schema: m.uuid()
},
{
name: 'text',
location: 'body',
required: true,
schema: m.string()
},
{
name: 'authorId',
location: 'body',
required: true,
schema: m.uuid()
}
],
schema: CommentSchema
})
const LikeResponseSchema = m.object({
likes: m.number()
})
type LikeResponse = Infer<typeof LikeResponseSchema>
export const likePost = defineEndpoint<LikeResponse>({
path: '/api/posts/:postId/like',
method: 'POST',
params: [
{
name: 'postId',
location: 'path',
required: true,
schema: m.uuid()
}
],
schema: LikeResponseSchema
})
Using in React
import { useEffect, useState } from 'react'
import { getPosts, getPost, getComments, type Post } from './api/blog'
function BlogList() {
const [posts, setPosts] = useState([])
const [loading, setLoading] = useState(true)
useEffect(() => {
getPosts({ page: 1, limit: 10 })
.then(data => setPosts(data.posts))
.finally(() => setLoading(false))
}, [])
if (loading) return <div>Loading...</div>
return (
<div>
{posts.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
<div>
<span>{post.author.name}</span>
<span>{post.likes} likes</span>
<span>{post.commentsCount} comments</span>
</div>
</article>
))}
</div>
)
}
function BlogPost({ slug }) {
const [post, setPost] = useState(null)
const [comments, setComments] = useState([])
useEffect(() => {
Promise.all([
getPost({ slug }),
getComments({ postId: slug })
]).then(([postData, commentsData]) => {
setPost(postData)
setComments(commentsData)
})
}, [slug])
if (!post) return <div>Loading...</div>
return (
<article>
<h1>{post.title}</h1>
<div>
<img src={post.author.avatar} alt={post.author.name} />
<span>{post.author.name}</span>
<time>{new Date(post.publishedAt).toLocaleDateString()}</time>
</div>
<div dangerouslySetInnerHTML={{ __html: post.body }} />
<section>
<h3>{comments.length} Comments</h3>
{comments.map(comment => (
<div key={comment.id}>
<strong>{comment.author.name}</strong>
<p>{comment.text}</p>
</div>
))}
</section>
</article>
)
}
Advanced Features
1. Error Simulation
Test how your app handles errors using the errors array:
export const getPosts = defineEndpoint({
path: '/api/posts',
method: 'GET',
schema: PostSchema,
mock: {
count: 10
},
errors: [
{
code: 500,
description: 'Internal server error',
schema: m.object({
error: m.object({
message: m.string(),
code: m.string()
})
}),
failNow: true // Simulates this error in mock mode
}
]
})
When failNow: true is set, the endpoint will throw this error in development/mock mode, allowing you to test error handling.
2. Loading Delays
Test loading states using the delay parameter in mock config:
export const getPosts = defineEndpoint({
path: '/api/posts',
method: 'GET',
schema: PostSchema,
mock: {
count: 10,
delay: 2000 // 2 second delay for cached responses
}
})
The delay parameter simulates network latency for cached data, helping you test loading states and spinners.
3. Authentication
Mock auth flows:
export const login = defineEndpoint({
path: '/auth/login',
method: 'POST',
params: [
{
name: 'email',
location: 'body',
required: true,
schema: m.email()
},
{
name: 'password',
location: 'body',
required: true,
schema: m.string()
}
],
schema: m.object({
token: m.string(),
user: m.object({
id: m.uuid(),
email: m.email(),
name: m.person.fullName()
})
})
})
4. Pagination
Implement proper pagination:
export const getPosts = defineEndpoint({
path: '/api/posts',
method: 'GET',
params: [
{
name: 'page',
location: 'query',
required: false,
schema: m.number(),
example: 1
},
{
name: 'limit',
location: 'query',
required: false,
schema: m.number(),
example: 10
}
],
schema: m.object({
posts: m.array(PostSchema),
pagination: m.object({
page: m.number(),
limit: m.number(),
total: m.number(),
pages: m.number()
})
}),
mock: {
count: 1 // Single response object containing posts array
}
})
Comparison Table
| Feature | Symulate | JSON Server | Mocky |
|---|---|---|---|
| Setup Time | 2 min | 1 min | 30 sec |
| Realistic Data | ✅ AI-powered | ❌ Manual | ❌ Manual |
| TypeScript | ✅ Full | ❌ No | ❌ No |
| Local/Cloud | Both | Local only | Cloud only |
| Free Tier | 20K AI tokens + unlimited Faker | Unlimited | Limited |
| Learning Curve | Low | Very low | None |
| Production Ready | ✅ Yes | ⚠️ Prototypes | ❌ No |
Common Issues and Solutions
Issue 1: CORS Errors
Problem: Browser blocks requests
Solution:
- JSON Server:
json-server --watch db.json --port 3000 --host 0.0.0.0 - Symulate: Runs locally, no CORS issues
- Mocky: Add CORS headers in response settings
Issue 2: Data Persistence
Symulate's Smart Caching:
One of Symulate's main features is intelligent cloud-based caching. When data is generated for an endpoint:
- Cloud Storage: Generated data is stored in the cloud
- Automatic Reuse: Same endpoint with same schema reuses cached data
- Local Cache Option: Can also be stored in localStorage for faster responses
- Schema Change Detection: If endpoint schema or config changes, new data is automatically generated
- Configuration Control: Use
regenerateOnConfigChangeto control when cache invalidates
import { configureSymulate } from '@symulate/sdk'
configureSymulate({
cacheEnabled: true,
persistentCache: true, // Enable localStorage persistence in browser
regenerateOnConfigChange: true // Regenerate when config changes (default)
})
Other Tools:
- JSON Server: Data persists in
db.jsonfile - Mocky: No persistence (fixed responses)
Issue 3: Slow Requests
Problem: Requests take too long
Solution:
- Add delays intentionally to test loading states
- Remove delays for development
- Use caching for repeated requests
When to Switch to Real API
Switch when:
- ✅ Backend API is ready
- ✅ Integration tests pass
- ✅ Performance meets requirements
- ✅ Error handling is tested
With Symulate, switching is one configuration change:
import { configureSymulate } from '@symulate/sdk'
// Development (uses mocks)
configureSymulate({
environment: 'development',
symulateApiKey: 'your-api-key',
projectId: 'your-project-id'
})
// Production (uses real backend)
configureSymulate({
environment: 'production',
backendBaseUrl: 'https://api.yourapp.com'
})
Done! All your defineEndpoint calls automatically switch to the real backend. No code refactoring needed.
Next Steps
- Choose your method:
- Quick prototype → JSON Server
- Production app → Symulate
- Simple demo → Mocky
- Build something:
- Start with GET endpoints
- Add POST/PUT/DELETE as needed
- Test error states
- Learn more:
Conclusion
Creating a fake REST API doesn't have to be complicated. Whether you use Symulate (AI-powered), JSON Server (quick setup), or Mocky (no installation), you can have a working API in under 5 minutes.
Our recommendation: Start with Symulate if you're building a real application, or JSON Server if you're just learning.
Ready to start? Get Symulate with 20K free AI tokens (plus unlimited Faker mode), or install JSON Server and start building!
Resources:
Ready to try Symulate?
Start building frontends without waiting for backend APIs. Get 100K free AI tokens.
Sign Up Free