Local · Claude

Mock APIs with natural language

Describe the API your project needs. Grim creates real, stateful endpoints locally — seeded with data that fits your schema. Just focus on building your frontend!

grim
i'm building a community feed — users, posts with upvote counts and topic tags, and comment threads. seed it heavy, i need enough records to stress test the feed. Asking Claude... 3 resources · 650 records · users 50 records · posts 200 records · comments 400 records ↳ posts.userId → users.id ↳ comments.postId → posts.id
$ curl -fsSL https://raw.githubusercontent.com/thomscoder/grim/main/scripts/install.sh | sh

Needs an Anthropic API key  ·  GitHub →


It's a real API.
Curl it.

Whether you're building an MVP, a personal project or a new feature, Grim has you covered with disposable REST endpoints that you can tweak however you like.

Every resource you describe becomes a live endpoint. Full CRUD — filter, sort, create, update, delete. No config files, no schema definitions.

~
$ curl 'localhost:7777/posts?sort=likes:desc&limit=3' [ { "id": 42, "title": "How I built my side project", "likes": 2841, "published": true }, { "id": 7, "title": "10 lessons from shipping fast", "likes": 1204, "published": true }, { "id": 23, "title": "Why I chose Bun over Node", "likes": 891, "published": true } ] $ curl -X POST localhost:7777/posts \ -H 'Content-Type: application/json' \ -d '{"userId": 3, "title": "My first post", "likes": 0}' { "id": 201, "userId": 3, "title": "My first post", "likes": 0, "published": false }

GraphQL, auto-generated.

Every resource gets a GraphQL endpoint automatically — queries, mutations, nested resolvers. Same data, no schema to write.

~
$ curl -X POST localhost:7777/__cast/graphql \ -H 'Content-Type: application/json' \ -d '{"query": "{ posts(limit: 3) { id title likes author { name } } }"}' { "data": { "posts": [ { "id": 42, "title": "How I built my side project", "likes": 2841, "author": { "name": "James Park" } }, { "id": 7, "title": "10 lessons from shipping fast", "likes": 1204, "author": { "name": "Elena Rodriguez" } }, { "id": 23, "title": "Why I chose Bun over Node", "likes": 891, "author": { "name": "Alice Chen" } } ] } }

Data that reacts.
Not just sits there.

Endpoints can react to each other. Describe the logic — create an order and stock decrements, post a comment and the count increments, delete a user and their content is removed. Grim wires it so your mock behaves like the real thing.

grim
i'm building a storefront. when i POST an order, subtract the quantity from the product's stock. when it hits zero, flip the status to "out_of_stock" — my UI reads that field to disable the buy button. Also: 2 triggers wired
~
$ curl localhost:7777/products/12 { "id": 12, "name": "Wireless Headphones", "stock": 7, "status": "in_stock" } $ curl -X POST localhost:7777/orders \ -H 'Content-Type: application/json' \ -d '{"productId": 12, "quantity": 7}' { "id": 88, "productId": 12, "quantity": 7, "status": "confirmed" } $ curl localhost:7777/products/12 { "id": 12, "name": "Wireless Headphones", "stock": 0, "status": "out_of_stock" } stock went from 7 → 0, status flipped automatically

Change the schema
while it's running.

Describe what changed. Grim updates the schema and backfills existing records — no restart, no data loss. Useful when the real API spec changes and you need your mock to keep up.

~
$ curl -X POST localhost:7777/__cast/evolve \ -H 'Content-Type: application/json' \ -d '{"name": "posts", "changes": "add a views counter, rename likes to reactions, drop published. i'\''m adding an api key layer — require X-API-Key on write requests"}' { "updated": 200, "added": ["views"], "renamed": { "likes": "reactions" }, "removed": ["published"], "guards": 1 }

Want pagination?

Describe what you need — cursor, offset, page-based. Grim configures it. Your frontend gets real paginated responses to build against.

grim
i need the posts feed paginated — 20 per page, newest first. the response should wrap the array in "items" and give me a "nextToken" field to fetch the next page. · posts ← pagination configured
~
$ curl 'localhost:7777/posts?limit=2' { "items": [ { "id": 42, "title": "How I built my side project", "likes": 2841 }, { "id": 7, "title": "10 lessons from shipping fast", "likes": 1204 } ], "nextToken": "eyJpZCI6N30", "has_more": true } $ curl 'localhost:7777/posts?nextToken=eyJpZCI6N30&limit=2' { "items": [ { "id": 23, "title": "Why I chose Bun over Node", "likes": 891 }, { "id": 31, "title": "Building my first side project", "likes": 445 } ], "nextToken": "eyJpZCI6MzF9", "has_more": true }

Need a header guard
on a route?

Describe the rule — bearer token, API key, custom header. Grim enforces it. Your frontend gets real 401s to handle instead of skipping auth entirely during development.

grim
i'm adding auth to my api — i need write operations protected. require a bearer token on POST, PATCH and DELETE. return 401 if it's missing or invalid. Also: 1 header guard
~
$ curl -X POST localhost:7777/posts \ -d '{"userId": 3, "title": "test"}' { "error": "Missing or invalid Authorization header" } ← 401 $ curl -X POST localhost:7777/posts \ -H 'Authorization: Bearer my-token' \ -d '{"userId": 3, "title": "test"}' { "id": 202, "userId": 3, "title": "test", "likes": 0 } ← 201

Full OAuth 2.0 provider,
from a description.

Describe the flow. Grim runs a real OAuth 2.0 / OIDC provider locally — auth code, PKCE, client credentials, scopes, refresh tokens, introspection, discovery. Build and test your auth integration against it before the real one exists.

grim
i'm testing oauth in my SPA. users log in and get a token. three permission levels: read for guests, write for editors, admin for everything. use pkce — i don't want to deal with a client secret in the browser. OAuth 2.0 configured · authorization_code + pkce · scopes read write admin · authorize /__cast/oauth/authorize · token /__cast/oauth/token · discovery /__cast/oauth/.well-known/openid-configuration

Make it fail
on purpose.

Inject failures, latency, and rate limits into any endpoint. Test your error states and retry logic against the mock before the real backend exists.

grim
fail 20% of POST /comments with a 503 so i can test my retry logic. add 100–400ms latency to GET /posts so i can see my loading skeleton. Also: 2 chaos rules

Browse it live.

/web opens a web UI for your running API — browse records, filter, create, delete, inspect active chaos rules and guards.

grim
/web Opened http://localhost:7777/__cast
Grim · localhost:7777/__cast
us
po
co
🔒 Bearer required on POST, PATCH, DELETE  ·  ⚡ comments/POST → 20% 503  ·  ⏱ posts/GET 100–400ms
users 50 records · GET /users
idnameemailtag
1Alice Chenalice@example.comfrontend
2Marcus Williamsmarcus@example.combackend
3Sophie Turnersophie@example.comdesign
4James Parkjames@example.comdevops
5Elena Rodriguezelena@example.comfrontend
posts 200 records · ?sort=likes:desc
iduserIdtitlelikespublished
424How I built my side project2841true
7910 lessons from shipping fast1204true
83Async/await finally explained1089true
232Why I chose Bun over Node891true
317Building my first side project445true
181CSS tips I wish I knew earlier312false
comments 400 records · GET /comments
idpostIduserIdbody
1423Really helpful, thanks!
2711Been waiting for this post.
3235Saved this one.
487Agree completely.
5422This changed how I think.

Fork the state.
Wreck it safely.

Clone the entire running state into an isolated workspace. Route requests with X-Workspace and only that fork mutates — useful for parallel test runs, per-branch environments, or sharing a sandbox with a teammate.

~
$ curl -X POST localhost:7777/__cast/fork \ -d '{"name": "qa-branch"}' { "id": "a7f3b2c1", "name": "qa-branch", "resources": 3, "records": 650 } # QA hits the fork — only the fork mutates $ curl -X DELETE localhost:7777/posts/42 \ -H 'X-Workspace: a7f3b2c1' { "deleted": true } # main state is untouched $ curl localhost:7777/posts/42 { "id": 42, "title": "How I built my side project", "likes": 2841 } ← still there

Import a spec.
Export your state.

Point Grim at an existing OpenAPI or Swagger spec and it imports the resources directly. Export your current state — resources, data, rules — as JSON to share with a teammate or restore later.

~
$ curl -X POST localhost:7777/__cast/openapi \ -H 'Content-Type: application/json' \ -d '{"url": "https://petstore3.swagger.io/api/v3/openapi.json"}' { "imported": ["pets", "store", "users"], "records": 90 } $ curl localhost:7777/__cast/export > session.json # send it to a teammate, commit it, restore it later $ curl -X POST localhost:7777/__cast/import \ -H 'Content-Type: application/json' \ -d @session.json { "imported": 3, "message": "State restored." }

What are you building?

Type what your project actually needs. These are examples.

i'm building a saas dashboard. companies with teams inside them, members with different permission levels. a big activity feed i can scroll through. lock everything behind an api key — and start returning 429s if they hammer the feed too hard.
storefront with products and stock levels. when someone orders something, subtract from stock — flip it to out_of_stock when it hits zero. make checkout fail about a third of the time so i can actually test my error state.
hr tool for a client demo — employees, departments, time-off requests. i need real oauth2 running locally so i can test my auth flow end to end. authorization code with pkce, a few permission scopes, auto-approve the consent.
blog with authors, posts, and comments. bump the post's comment count whenever someone comments. writes need a bearer token. and make maybe 1 in 5 comment posts fail — i've never actually tested if my retry logic works.