Functional Mocks
Node 22.18+ and 23.6+ support TypeScript by default.
You can write mocks in JavaScript or TypeScript
api/foo.GET.200.js
export default (req, response) => {
// These two lines are not needed but you can change their values
/* response.statusCode = 200 */ // default derived from filename
/* response.setHeader('Content-Type', 'application/json') */ // unconditional default
return JSON.stringify({ foo: 'bar' })
}
Return a string | Buffer | Uint8Array,
but don’t call response.end().
async functions are supported.
Custom HTTP Handlers
For example, you can intercept requests to write to a database. Or act based on
some query string value, etc. In summary, you get Node’s request,
response as arguments, so you can think of Mockaton as a
router, but in the handlers you return, instead of ending the response.
Example A: JSON body parser and in-memory database
Imagine you have an initial list of colors, and you want to concatenate newly added colors.
api/colors.POST.201.js
import { parseJSON } from 'mockaton'
export default async function insertColor(req, response) {
const color = await parseJSON(req)
globalThis.newColorsDatabase ??= []
globalThis.newColorsDatabase.push(color)
return JSON.stringify({ msg: 'CREATED' })
}
api/colors.GET.200.js
import colorsFixture from './colors.json' with { type: 'json' }
export default function listColors() {
return JSON.stringify([
...colorsFixture,
...(globalThis.newColorsDatabase || [])
])
}
Example B: Parse query string params
api/list?limit=[my-limit].GET.200.js
import { parseQueryParams } from 'mockaton'
export default function (req) {
const searchParams = parseQueryParams(req.url)
const limit = Number(searchParams.get('limit'))
return JSON.stringify({ limit })
}
Example C: Parse splats
api/company/[companyId]/user/[userId].GET.200.js
import { parseSplats } from 'mockaton'
export default function (req, response) {
const { companyId, userId } = parseSplats(req.url, import.meta.filename)
return JSON.stringify({ companyId, userId })
}
What if I need to serve a static .js or .ts?
Option A: Put it in your config.staticDir without the .GET.200.js extension.
Mocks in staticDir take precedence over mocksDir/*.
Option B: Read it and return it. For example:
import { readFileSync } from 'node:fs'
export default function (_, response) {
response.setHeader('Content-Type', 'application/javascript')
return readFileSync('./some-dir/foo.js', 'utf8')
}