Tutorial · Step-by-step

Build a Mock API for User-Centric Apps

Follow six steps to design realistic datasets, publish five REST endpoints, and map them to a SaaS dashboard wireframe.

  • SaaS prototypes
  • AI-generated apps
  • Internal tools
  • Frontend development

Highlights

Projects
GET /v1/apis/projects
Tasks
GET /v1/apis/tasks
Notifications
GET /v1/apis/notifications

Step 1

See the end result

Before writing CSV files, picture the SaaS dashboard you are building. Each screen area maps to one API Butler endpoint.

Highlights

Projects
GET /v1/apis/projects
Tasks
GET /v1/apis/tasks
Notifications
GET /v1/apis/notifications
  • GET /v1/apis/usersUser identity & role
  • GET /v1/apis/profilesAvatar, bio, company
  • GET /v1/apis/projectsProject list & status
  • GET /v1/apis/tasksTask board & assignees
  • GET /v1/apis/notificationsActivity feed

Step 2

Design your datasets

Model five CSV files with shared IDs. Users sit at the center — profiles, projects, tasks, and notifications join through foreign keys.

users.csv

Central identity table — other datasets join through shared IDs.

profiles.csv joins via user_id
projects.csv joins via owner_id
tasks.csv joins via project_id · assignee_id
notifications.csv joins via user_id

users.csv

Core identity records for authentication and role-based UI.

idnameemailrolecreated_at
csv
      id,name,email,role,created_at
1,Alex Chen,[email protected],admin,2024-01-15
2,Jordan Lee,[email protected],member,2024-02-03
3,Sam Rivera,[email protected],member,2024-03-21
4,Taylor Kim,[email protected],viewer,2024-04-08
    

profiles.csv

Extended user metadata for avatars, bios, and company context.

user_idavatarbiocompany
csv
      user_id,avatar,bio,company
1,https://cdn.example.com/a1.jpg,Product lead at Acme,Acme Inc
2,https://cdn.example.com/a2.jpg,Full-stack engineer,Acme Inc
3,https://cdn.example.com/a3.jpg,Design systems,Acme Inc
4,https://cdn.example.com/a4.jpg,Operations analyst,Acme Inc
    

projects.csv

Workspace containers owned by users with status tracking.

idnameowner_idstatus
csv
      id,name,owner_id,status
1,Platform Redesign,1,active
2,API Migration,2,in_progress
3,Customer Portal,1,active
4,Inventory Sync,3,paused
    

tasks.csv

Actionable work items linked to projects and assignees.

idproject_idassignee_idtitlestatus
csv
      id,project_id,assignee_id,title,status
1,1,2,Design navigation system,done
2,1,3,Build component library,in_progress
3,2,2,Migrate auth endpoints,todo
4,3,4,Wire notification panel,in_progress
5,1,1,Review launch checklist,todo
    

notifications.csv

User alerts for activity feeds and unread badges.

iduser_idmessagecreated_at
csv
      id,user_id,message,created_at
1,1,Jordan completed "Design navigation system",2024-06-01T09:14:00Z
2,2,You were assigned "Migrate auth endpoints",2024-06-01T10:02:00Z
3,1,Sam updated the component library,2024-06-01T11:30:00Z
4,3,Project "Inventory Sync" was paused,2024-06-01T14:45:00Z
    

Step 3

Publish your APIs

Upload each CSV to API Butler. One file becomes one hosted GET endpoint with filtering, pagination, and JSON responses.

  1. Prepare

    Export CSV files

    Save each dataset with headers in row one.

  2. 2
    Upload Current

    Upload to API Butler

    One upload per resource — users, profiles, projects, tasks, notifications.

  3. 3
    Generate

    API generated

    Each CSV becomes a hosted GET endpoint in seconds.

  4. 4
    Connect

    Endpoints available

    Copy URLs and optional API keys from your dashboard.

products.csv847 rows · 4 cols
namecategorypricestock
Wireless Headphoneselectronics79.99142
USB-C Hubelectronics34.9989
Laptop Standoffice49.00201
+ 844 more rows
GET/v1/apis/products
200 OK
{
"data": [{ "name": "Wireless Headphones" … }],
"total": 847,
"page": 1,
"limit": 25
}
GET/v1/apis/users

List users with role filtering and pagination

GET/v1/apis/profiles

Profile metadata keyed by user_id

GET/v1/apis/projects

Projects with owner and status fields

GET/v1/apis/tasks

Tasks filterable by project, assignee, or status

GET/v1/apis/notifications

Activity feed per user_id

bash
      # Example requests curl "https://api.getapibutler.com/v1/apis/users?limit=25" curl "https://api.getapibutler.com/v1/apis/projects?filter[status]=active"
    

Sample response — GET /users

json
      {
  "data": [
    {
      "id": 1,
      "name": "Alex Chen",
      "email": "[email protected]",
      "role": "admin",
      "created_at": "2024-01-15"
    }
  ],
  "meta": {
    "limit": 25,
    "offset": 0,
    "count": 1,
    "total": 4
  }
}
    

Step 4

Map APIs to UI

When you wire a frontend or AI-generated dashboard, assign each view to the endpoint that owns its data. This keeps schemas honest and avoids hardcoded fixtures.

Highlights

Projects
GET /v1/apis/projects
Tasks
GET /v1/apis/tasks
Notifications
GET /v1/apis/notifications
  • GET /v1/apis/usersUser identity & role
  • GET /v1/apis/profilesAvatar, bio, company
  • GET /v1/apis/projectsProject list & status
  • GET /v1/apis/tasksTask board & assignees
  • GET /v1/apis/notificationsActivity feed

Step 5

Wire up frontend & AI

Point hooks or composables at live endpoints, then paste the same URLs into Cursor or Claude Code to generate the dashboard shell.

API Butler endpoints pasted into Cursor or Claude Code
Endpoints pastedAI

Which views should the dashboard include first?

Users table , projects board, and notifications panel

Generate typed hooksAI

How should the app fetch and filter API data?

Typed fetch hooks with loading, empty, and error states

Working UIAI

What should the first screen look like?

Responsive dashboard shell wired to live GET endpoints

React fetch hook

typescript
      // hooks/useUsers.ts
import { useEffect, useState } from "react";

type User = { id: number; name: string; email: string; role: string };
type ApiResponse = { data: User[]; meta: { total: number } };

export function useUsers(role?: string) {
  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const params = role ? `?filter[role]=${role}&limit=25` : "?limit=25";
    fetch(`${globalThis._importMeta_.env.VITE_USERS_API}${params}`, {
      headers: { "X-API-Key": globalThis._importMeta_.env.VITE_API_BUTLER_KEY },
    })
      .then((res) => {
        if (!res.ok) throw new Error("Failed to load users");
        return res.json() as Promise<ApiResponse>;
      })
      .then((json) => setUsers(json.data))
      .catch((err) => setError(err.message))
      .finally(() => setLoading(false));
  }, [role]);

  return { users, loading, error };
}
    

Vue composable

typescript
      // composables/useProjects.ts
import { ref, onMounted } from "vue";

type Project = { id: number; name: string; owner_id: number; status: string };

export function useProjects(status?: string) {
  const projects = ref<Project[]>([]);
  const loading = ref(true);
  const error = ref<string | null>(null);

  onMounted(async () => {
    try {
      const params = status ? `?filter[status]=${status}&limit=25` : "?limit=25";
      const res = await fetch(`${globalThis._importMeta_.env.VITE_PROJECTS_API}${params}`, {
        headers: { "X-API-Key": globalThis._importMeta_.env.VITE_API_BUTLER_KEY },
      });
      if (!res.ok) throw new Error("Failed to load projects");
      const json = await res.json();
      projects.value = json.data;
    } catch (e) {
      error.value = e instanceof Error ? e.message : "Unknown error";
    } finally {
      loading.value = false;
    }
  });

  return { projects, loading, error };
}
    

Prompt for Cursor

prompt
      Build a modern SaaS admin dashboard that consumes these API Butler REST endpoints.

Endpoints (paste your URLs):
- Users: [PASTE_USERS_ENDPOINT]
- Profiles: [PASTE_PROFILES_ENDPOINT]
- Projects: [PASTE_PROJECTS_ENDPOINT]
- Tasks: [PASTE_TASKS_ENDPOINT]
- Notifications: [PASTE_NOTIFICATIONS_ENDPOINT]

Each endpoint returns { data: [], meta: { limit, offset, count, total } }.

Requirements:
1. Dashboard overview — active users, open projects, task counts, unread notifications
2. Users table — role badges, search, pagination via API query params
3. Projects table — owner name (join via profiles), status filters
4. Task management — assignee, status columns, group by project
5. Notifications panel — unread state, relative timestamps, mark-as-read UI shell
6. Typed fetch hooks with loading, empty, and error states
7. Responsive layout — sidebar collapses on mobile
8. Reuse existing project conventions; do not add new state libraries unless already present
9. Never hardcode mock rows once endpoints are provided
    

Prompt for Claude Code

prompt
      Generate a full-stack UI from these API Butler GET endpoints.

Endpoints (paste your URLs):
- Users: [PASTE_USERS_ENDPOINT]
- Profiles: [PASTE_PROFILES_ENDPOINT]
- Projects: [PASTE_PROJECTS_ENDPOINT]
- Tasks: [PASTE_TASKS_ENDPOINT]
- Notifications: [PASTE_NOTIFICATIONS_ENDPOINT]

Phase 1 — Do not write code yet.
Ask me exactly 2–3 focused questions:
- Framework and routing conventions (React, Vue, file structure)
- Styling approach (Tailwind, CSS modules, existing design tokens)
- Which views to prioritize (dashboard, users, projects, tasks, notifications)

Stop and wait for my answers.

Phase 2 — After I answer:
- Generate TypeScript types from API response shapes
- Create a typed API client with reusable fetch utilities
- Build hooks/composables with loading, error, and empty states
- Implement filterable tables for users and projects
- Task list with status filtering and project grouping
- Notifications feed with relative timestamps
- Responsive dashboard shell with navigation
- Keep API keys in env only—never commit secrets
- Do not use placeholder JSON once real endpoints are provided
    

Step 6

Compare & ship

API Butler gives you domain-specific mock APIs with realistic relationships — not generic placeholder JSON.

JSONPlaceholder

  • Generic posts and users
  • Unrealistic structures
  • No project-specific relationships
  • Same data for every developer

API Butler

  • Your schema and field names
  • Realistic cross-resource IDs
  • Production-like pagination metadata
  • Project-specific mock APIs

FAQ

Mock API tutorial questions

Why not use JSONPlaceholder for mock APIs?

JSONPlaceholder returns generic, unrelated data. API Butler lets you define project-specific schemas—users, projects, tasks, and notifications that match your actual app domain.

How many CSV files do I need?

Upload one CSV per resource. For a user-centric SaaS app, start with users, profiles, projects, tasks, and notifications—five focused datasets that mirror real product relationships.

Can I use this tutorial with Cursor or Claude Code?

Yes. The tutorial includes copy-paste prompts for both tools. Upload your CSVs to API Butler, paste the endpoints into the prompt, and generate a dashboard with typed fetch hooks and realistic data.

Do I need a backend or database?

No. API Butler hosts the REST endpoints. You upload CSV files and get live GET endpoints in minutes—no server, database, or infrastructure setup.

What frameworks work with the generated APIs?

Any framework that can call REST endpoints—React, Vue, Next.js, Nuxt, or AI-generated apps from Cursor and Claude Code. The tutorial includes React and Vue fetch examples.

Ready to build

Upload CSV. Get API. Build your app.

Start with your five datasets and have live endpoints in minutes.