Build the mental model
A Postman collection is not a nice-to-have wrapper around a few requests, it is the shared, runnable documentation your whole team, and any future integration partner, will actually read instead of a wiki page that goes stale.
Collection structure means grouping every request for one API into a single named collection, so a new teammate can import one file and immediately have every request ready to fire.
The environments and variables lesson's baseUrl is defined once in an environment, so switching between local, staging, and production is a one-field edit instead of editing every request.
Happy-path tests alone are not enough
The test-case-categories thinking from the Advanced chapter means adding failure-path tests like a 404 for a missing ID or a 400 for a missing field -- exactly the paths a careless refactor breaks first, often silently.
- A collection with only happy-path tests gives false confidence.
- A collection with both happy and failure tests per request catches regressions before your users do.
NOTES API POSTMAN COLLECTION
----------------------------
Environment: local
baseUrl = http://localhost:3000
|
| injected into every request as {{baseUrl}}
v
Collection: Notes API
|-- GET {{baseUrl}}/notes (List Notes)
| test: status is 200
| test: body is an array
|
|-- GET {{baseUrl}}/notes/:id (Get Note)
| test 1 (happy): status is 200
| test 2 (failure): missing id -> status is 404
|
|-- POST {{baseUrl}}/notes (Create Note)
| test 1 (happy): status is 201
| test 2 (failure): missing title -> status is 400
|
|-- PUT {{baseUrl}}/notes/:id (Update Note)
| test: title was updated
|
|-- DELETE {{baseUrl}}/notes/:id (Delete Note)
test: status is 204Connect it to a real scenario
Create the environment
Create a local environment with one variable, baseUrl, so every request can reference {{baseUrl}} instead of a hardcoded host.
Add List Notes
Add GET {{baseUrl}}/notes with two tests: status is 200, and the body is an array.
Add Get Note (happy + failure)
Add a happy-path request and a missing-id request, asserting 200 and 404 separately.
Add Create Note (happy + failure)
Add a request with title present and one without, asserting 201 and 400 separately.
Add Update Note and Delete Note
Add each with one happy-path test, then run the whole collection with Postman's Collection Runner.
Postman is a GUI tool
Since the collection can't be pasted into a lesson, the code rebuilds the same test logic as plain functions against a mock API.
Try the working example
// A tiny in-memory "Notes API" that stands in for a real server,
// so the collection's test cases have something real to run against.
const notes = {
1: { id: 1, title: 'Buy milk' },
2: { id: 2, title: 'Pay rent' },
};
let nextId = 3;
function mockApi(method, path, body) {
const getMatch = path.match(/^\/notes\/(\d+)$/);
if (method === 'GET' && path === '/notes') {
return { status: 200, json: Object.values(notes) };
}
if (method === 'GET' && getMatch) {
const note = notes[getMatch[1]];
return note ? { status: 200, json: note } : { status: 404, json: { error: 'not_found' } };
}
if (method === 'POST' && path === '/notes') {
if (!body || !body.title) {
return { status: 400, json: { error: 'title_required' } };
}
const note = { id: nextId++, title: body.title };
notes[note.id] = note;
return { status: 201, json: note };
}
if (method === 'PUT' && getMatch) {
const note = notes[getMatch[1]];
if (!note) return { status: 404, json: { error: 'not_found' } };
note.title = body.title;
return { status: 200, json: note };
}
if (method === 'DELETE' && getMatch) {
const existed = Boolean(notes[getMatch[1]]);
delete notes[getMatch[1]];
return existed ? { status: 204, json: null } : { status: 404, json: { error: 'not_found' } };
}
return { status: 404, json: { error: 'no_route' } };
}
// The "collection": each request plus its test cases, mirroring how a
// Postman request stores a Tests tab with several assertions.
const baseUrl = '{{baseUrl}}'; // resolved by the Postman environment
const collection = [
{
name: 'List Notes',
run: () => mockApi('GET', '/notes'),
tests: [
{ name: 'status is 200', check: (res) => res.status === 200 },
{ name: 'body is an array', check: (res) => Array.isArray(res.json) },
],
},
{
name: 'Get Note (happy path)',
run: () => mockApi('GET', '/notes/1'),
tests: [
{ name: 'status is 200', check: (res) => res.status === 200 },
{ name: 'title is present', check: (res) => typeof res.json.title === 'string' },
],
},
{
name: 'Get Note (missing id)',
run: () => mockApi('GET', '/notes/999'),
tests: [{ name: 'status is 404', check: (res) => res.status === 404 }],
},
{
name: 'Create Note (happy path)',
run: () => mockApi('POST', '/notes', { title: 'Read a book' }),
tests: [
{ name: 'status is 201', check: (res) => res.status === 201 },
{ name: 'returned id is a number', check: (res) => typeof res.json.id === 'number' },
],
},
{
name: 'Create Note (missing title)',
run: () => mockApi('POST', '/notes', {}),
tests: [{ name: 'status is 400', check: (res) => res.status === 400 }],
},
{
name: 'Update Note (happy path)',
run: () => mockApi('PUT', '/notes/2', { title: 'Pay rent early' }),
tests: [{ name: 'title was updated', check: (res) => res.json.title === 'Pay rent early' }],
},
{
name: 'Delete Note (happy path)',
run: () => mockApi('DELETE', '/notes/1'),
tests: [{ name: 'status is 204', check: (res) => res.status === 204 }],
},
];
function runCollection(requests) {
const report = [];
for (const req of requests) {
const res = req.run();
const results = req.tests.map((t) => ({ name: t.name, passed: t.check(res) }));
report.push({
request: req.name,
status: res.status,
passed: results.filter((r) => r.passed).length,
total: results.length,
results,
});
}
return report;
}
console.log('baseUrl =', baseUrl, '(resolved from the "local" Postman environment)\n');
const report = runCollection(collection);
for (const r of report) {
console.log(`${r.request} -> HTTP ${r.status} [${r.passed}/${r.total} tests passed]`);
for (const t of r.results) {
console.log(` ${t.passed ? 'PASS' : 'FAIL'} - ${t.name}`);
}
}
const totalPassed = report.reduce((sum, r) => sum + r.passed, 0);
const totalTests = report.reduce((sum, r) => sum + r.total, 0);
console.log(`\nCollection run complete: ${totalPassed}/${totalTests} assertions passed.`);The runner reports all 7 requests / 10 assertions passing: List Notes 2/2, Get Note (happy) 2/2, Get Note (missing id) 1/1 (404 confirmed), Create Note (happy) 2/2, Create Note (missing title) 1/1 (400 confirmed), Update Note 1/1, Delete Note 1/1 -- ending with 'Collection run complete: 10/10 assertions passed.'5-minute try-it
Add a sixth request, 'Update Note (missing id)', that PUTs to a nonexistent note ID and asserts a 404 -- then add its test case to the mock collection runner and confirm it reports correctly.
One important caution
Hardcoding the base URL into every request instead of an environment variable -- moving from local to staging then means editing every request by hand, and one gets missed.
Only writing happy-path tests -- a collection with no failure-path assertions doesn't actually verify error handling, and will not catch a broken error response.
Postman Learning Center: Collections Overview — API Integration & Webhooks