Introduction

What mockly is

A free fake REST API for frontends and prototypes. Create a project, drop JSON into a collection, and get full CRUD endpoints with filtering, sorting, pagination and relations. By default there are no keys and no headers — mocks are served over a public link; enable authorization when you need private resources.

Base URL
https://api.m0ckly.site/m/:publicId/:collection

publicId identifies the project and is shown on its page. collection is the collection name.

Quick start

Your first request

  1. Create a project and a collection — products, for example.
  2. Paste an array of JSON objects. The id field is filled in for you.
  3. Call the endpoint from your code.
example
const res = await fetch('https://api.m0ckly.site/m/acme/products?limit=2')
const products = await res.json()
response
[
  { "id": 1, "title": "Keyboard", "price": 90 },
  { "id": 2, "title": "Mouse", "price": 40 }
]
Projects and collections

How it is all arranged

An account holds projects, a project holds collections, a collection holds records. Registering creates a project named default for you, so there is something to work with straight away.

publicId
https://api.m0ckly.site/m/4f8c1e0a9b3d7c25/products

Every project gets its own publicId — 16 hex characters generated on creation and shown on the project page. It is the only thing that identifies the project in a mock URL, and renaming the project does not change it.

Project and collection names are 1 to 64 characters. A name is unique inside its scope: two projects on one account cannot share a name, and neither can two collections inside one project.

Deleting a project deletes its collections along with every record in them, and deleting a collection deletes its records. There is no undo. To take a project offline without losing data, turn it off instead.

Collection list

Finding out what is in a project

The project root lists its collections and whether each one is on. Handy for a client that discovers the schema instead of hardcoding it.

example
GET /m/acme

{ "collections": [
  { "name": "products", "enabled": true },
  { "name": "orders", "enabled": false }
] }

Disabled collections are listed too, marked with enabled: false — requests to them answer 403. A disabled project responds 403 here as well.

CRUD

Working with records

The full set of methods on a collection. Request and response bodies are JSON.

methodpathwhat it does
GET/:collectionList records
GET/:collection/:idA single record
POST/:collectionCreate a record
PUT/:collection/:idReplace a record entirely
PATCH/:collection/:idUpdate individual fields
DELETE/:collection/:idDelete a record

The id is generated by the server; sending one in a POST body is ignored. PUT replaces the data outright, PATCH merges the given fields into what is already there.

Query parameters

Filtering, search and sorting

These work on the list endpoint and combine in any order.

parameterwhat it does
?title=MouseA numeric-looking value compares exactly; any other value is a case-insensitive substring match
?title=Mou*Explicit pattern, case-insensitive: * stands for any characters and the pattern is anchored at both ends (use *mouse* for a substring)
?price_gte=20&price_lte=90Numeric range, ≥ and ≤
?q=mouseSubstring search across every field of a record, case-insensitive
?sortBy=price&order=descSort by a field; order is asc or desc
?page=2&limit=10Paginated output
example
GET /m/acme/products
  ?sortBy=price&order=asc
  &price_gte=20&page=1&limit=10

The names page, limit, sortBy, order, q and _relations are reserved — they will not filter fields of the same name. The _gte and _lte ranges only apply to numeric values; anything else is skipped.

A plain ?title=mouse now matches any title containing "mouse", ignoring case. Use * for prefixes or suffixes (?title=mouse*), and numbers still compare exactly (?price=100).

Pagination

Paginated output

By default the list endpoint returns a plain array. Pass page or limit and the response is wrapped in an envelope with metadata. If limit is not passed, the page size is 10 — passing page alone also falls back to 10 rather than the page size configured on the collection.

response
{
  "items": [ … ],
  "meta": {
    "total_items": 50,
    "total_pages": 5,
    "current_page": 1,
    "per_page": 10
  }
}

To always get the envelope, turn on Pagination in the collection settings. The same place sets the default page size and drops the total_pages field if you do not need it.

Relations

Embedding related records

The _relations parameter embeds a related object straight into the record. List several relations separated by commas.

example
GET /m/acme/orders?_relations=user

{ "id": 1, "userId": 7, "user": { "id": 7, "name": "Ann" } }

Relations follow a naming convention: _relations=user looks for a userId field on the record and pulls the matching row from the users collection. If the collection is missing or the reference is dangling, the field comes back as null.

The same parameter works the other way round. Name a collection outright — _relations=orders on a record from users — and you get every order pointing back through userId, as an array. A parent with no children gets an empty array. When both readings are possible, the singular one wins.

example
GET /m/acme/users/7?_relations=orders

{ "id": 7, "name": "Ann", "orders": [{ "id": 1, "userId": 7 }] }
Collection settings

Forced responses and disabling

A forced response makes the collection answer every request with a fixed status and an arbitrary body — handy for exercising error handling in the frontend. Any status from 100 to 599 will do. With no body set, you get an object holding the status and its text.

A forced response replaces the normal handler: it applies to every enabled method, and filters, pagination and relations are not evaluated at all. Access checks still run first — a disabled project or collection answers 403, a private resource without a token 401, and a disabled method 405. The records stay untouched — clear the status and the collection answers normally again.

Accepted methods are toggled per collection: read (GET), create (POST), update (PATCH, PUT) and delete (DELETE) independently. A disabled method answers 405 Method Not Allowed; the dashboard keeps full access.

A disabled project or collection responds with 403. Nothing is lost — switch it back on and the data is there.

Limits

What the quotas are

The numbers are generous enough for prototyping and are not configurable.

limitvalue
Collections per project25
Records per collection500
Objects in one import500
Records per bulk operation1000
per_page in collection settings1–100
Project or collection name1–64
Password length≥ 6

Going over the collection limit answers 409, as does a duplicate project or collection name. A collection holds up to 500 records — POST and imports beyond that answer 409 too.

Response codes

What comes back

codewhen
200Successful GET, PUT or PATCH
201Record created via POST
204Record deleted via DELETE, response body is empty
400The request body is not a valid JSON object
401Private resource without a valid token · wrong credentials or refresh token
403The project is disabled in settings · The collection is disabled in settings
404Project, collection or record not found
405The method is disabled in the collection settings
409Limit reached, or a project, collection or account with that name already exists

Errors carry a JSON body of the shape: { "error": "..." }

Security

The mock API is public

By default the mock endpoints have no authentication. There is no token, no header, no origin check — CORS is open to every site. Anyone who has the link can read the records, create new ones, edit them and delete them.

So treat a collection as public data. Do not put real personal data, keys, tokens or anything copied out of production in there. The publicId is not a secret: it travels in the URL and lands in browser history, logs and anything you paste it into.

If a link has leaked, turn the project off — the endpoints go 403 straight away while the data stays put. Private resources help you mock a login flow, but they are still mock-grade protection: the data behind them deserves no more trust than the rest.

mockly