LearnFrenzy
Sign in Take a free test

Consuming REST APIs · Lesson 14 of 30

Testing REST APIs with curl, Postman and HTTPie

4 min read Updated Nov 8, 2026 Saurabh Samir

Every API developer needs a fast way to send a request and see exactly what comes back. curl is on every machine and in every API's documentation; Postman (or Insomnia, Bruno) adds a GUI, saved requests and team collections; HTTPie is a friendlier command line. This lesson covers the options you'll use daily.

In this lesson

  • The curl options that matter
  • Sending JSON, headers and auth
  • Postman collections, environments and tests
  • HTTPie and copying requests from the browser

curl essentials

OptionDoes
-iinclude response headers
-vverbose: request headers, TLS handshake, everything
-X PUTset the method (POST is implied by -d)
-H 'Name: value'add a header
-d '…' / --json '…'send a body; --json also sets JSON Content-Type and Accept (curl 7.82+)
-u user:passHTTP Basic authentication
-s, -o file, -w '%{http_code}'silent, save body to a file, print the status code
-Lfollow redirects

Trying them on a real API

// server.js
import express from 'express';

const app = express();
app.use(express.json());

app.post('/api/tickets', (req, res) => {
  const auth = req.get('Authorization') ?? '';
  if (!auth.startsWith('Basic ')) return res.status(401).set('WWW-Authenticate', 'Basic realm="support"').json({ error: 'Authentication required' });
  const [user] = Buffer.from(auth.slice(6), 'base64').toString().split(':');
  res.status(201).location('/api/tickets/T-501').json({ id: 'T-501', createdBy: user, ...req.body });
});

app.get('/old-docs', (req, res) => res.redirect(301, '/api/docs'));
app.get('/api/docs', (req, res) => res.json({ docs: 'https://api.learnfrenzy.com/docs' }));

app.listen(process.env.PORT ?? 3000);

Real responses

$ curl --json '{"subject":"Cannot log in"}' http://localhost:3000/api/tickets
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="support"
Content-Type: application/json; charset=utf-8

{
  "error": "Authentication required"
}

$ curl -u asha:s3cret --json '{"subject":"Cannot log in","priority":"high"}' http://localhost:3000/api/tickets
HTTP/1.1 201 Created
Location: /api/tickets/T-501
Content-Type: application/json; charset=utf-8

{
  "id": "T-501",
  "createdBy": "asha",
  "subject": "Cannot log in",
  "priority": "high"
}

$ curl -L http://localhost:3000/old-docs
HTTP/1.1 301 Moved Permanently
Location: /api/docs
Vary: Accept
Content-Type: text/plain; charset=utf-8

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "docs": "https://api.learnfrenzy.com/docs"
}

Note how -u became a Basic header that the server decoded, and -L followed the 301 to the new location. In scripts, curl -s -o /dev/null -w '%{http_code}\n' URL prints just the status code – handy for health checks.

Postman: collections, environments, tests

A well-organised Postman workspace

  • Collection: Tasks API
    • Auth – Log in (saves the token to a variable)
    • Tasks – List, Create, Get, Update, Delete
  • Environments
    • Local – baseUrl = http://localhost:3000
    • Staging – baseUrl = https://staging-api.example.com
  • Write URLs as {{baseUrl}}/api/tasks and switch environments instead of editing requests.
  • Set auth once on the collection; requests inherit it.
  • Add tests in the "Scripts → Post-response" tab and run the whole collection (or with Newman in CI):
pm.test('created a task', () => {
  pm.response.to.have.status(201);
  const task = pm.response.json();
  pm.expect(task.title).to.eql('Write docs');
  pm.collectionVariables.set('taskId', task.id);     // used by the next request: {{baseUrl}}/api/tasks/{{taskId}}
});

Most APIs publish an OpenAPI file (next chapters); Postman and Insomnia can import it to generate a collection with every endpoint.

HTTPie and browser tricks

# HTTPie: JSON by default, coloured output, readable syntax
http POST localhost:3000/api/tasks title="Write docs" priority:=2 Authorization:"Bearer $TOKEN"

# Browser DevTools → Network → right-click a request → Copy → Copy as cURL
# then paste it into a terminal to replay exactly what the browser sent

Keep secrets out of history and screenshots

Tokens typed into commands end up in shell history; Postman workspaces can be shared. Use environment variables (-H "Authorization: Bearer $TOKEN"), Postman's secret variable type, and rotate any key that leaks.

Practice

Try it yourself

  1. Write a curl command that sends a PATCH with JSON {"status":"done"} and a bearer token from $TOKEN to /api/tasks/7, printing response headers.

    Show solution
    curl -i -X PATCH http://localhost:3000/api/tasks/7 \
      -H "Authorization: Bearer $TOKEN" \
      --json '{"status":"done"}'

Quick check

Which curl option shows response headers?

-i (or -v for everything).

What does --json do?

Sends the body and sets JSON Content-Type and Accept headers.

How do you switch Postman requests between local and staging?

Use a {{baseUrl}} variable and switch environments.

Summary

  • curl: -i, -v, -X, -H, --json, -u, -L, -w cover most debugging.
  • Postman: collections, environments, inherited auth and tests; import OpenAPI specs.
  • Copy requests from DevTools as cURL; keep tokens in variables, not commands.

Finished this lesson?

Mark it complete to track your progress, then carry on with the next lesson.

Next lesson

Search LearnFrenzy

Esc

Quick links