QA StepsJoin the waitlist

How to test a REST API manually: a checklist

To test a REST API manually, read its documentation first, then for every endpoint send one request that should work and several that should be refused. In each response, check the status code, the body and the headers, and then check with a second request that the change really happened. A refused request must fail with the right code and a clear message: 400 for invalid data, 401 when the API does not know who you are, 403 when you are known but not allowed, 404 when the thing is not there or not yours, and 409 when the request conflicts with the current state. You need no code: an API client such as Postman, or the documentation's own "Try it out" button, is enough.

7 checks
for every endpoint
15 example requests
to a practice shop's API
No code
an API client is enough

How to test an endpoint, step by step

  1. Step 1

    Read the documentation for the endpoint

    Note the method, the path, the required fields with their types and limits, and every response code the documentation lists. Each listed code is at least one test.

  2. Step 2

    Send the request that should work

    Use the documentation's example body. Check the status code first, then every value in the body against the rule, then the headers.

  3. Step 3

    Confirm the change with a second request

    After a POST, PUT, PATCH or DELETE, read the same resource with GET. The answer to a change says what the API claims; the next read shows what it kept.

  4. Step 4

    Break one input at a time

    A missing required field, a wrong type, a value outside the limits, an id that does not exist. One fault per request, so the refusal points at one rule.

  5. Step 5

    Test access

    Send the request without a token, then with a token for data that belongs to someone else, then on a resource you may read but not change.

  6. Step 6

    Test the state

    Repeat the request, send it in the wrong order or on an empty resource. These are where 409 and the business rules show up.

  7. Step 7

    Write down the evidence

    For a defect, keep the method, address, body, the status and body you got, the status the documentation promises, and the response's trace header if there is one.

    Open

What to check in a REST API

A REST API exposes resources (products, a cart, orders) at addresses, and you act on them with HTTP methods: GET reads, POST creates, PUT replaces, PATCH changes some fields, DELETE removes. Every answer has a status code, headers and usually a body. Manual API testing means sending those requests yourself and comparing each part of the answer with the documentation.

The examples use the API of Shelf, the practice shop the courses use. Its base address and the link to its documentation are on the start page of your own sandbox; below, the base address is written as {{base_url}}, so {{base_url}}/products means the products endpoint. The API writes money as a number of dollars: 49 is USD 49.00.

  • 1. Status code

    The one the documentation lists for this case, not just "something in the 200s".

  • 2. Body values

    Each value against the rule: the right product, the right quantity, the right total.

  • 3. Body shape

    Field names and types as documented: a price is a number, not a string; an id is a whole number.

  • 4. Headers

    Content-Type of the body, Location after a create, trace or request ids, nothing that leaks internals.

  • 5. The change itself

    A second request shows that the create, update or delete was kept.

  • 6. Refusals

    Invalid data, missing access and wrong state each fail with their own code and a clear message.

  • 7. Nothing extra

    No password hashes and no other users' data in any answer.

Reading the OpenAPI documentation

Most REST APIs publish an OpenAPI description, often shown in Swagger UI. Shelf's start page links to it with "REST docs in Swagger UI", and offers the raw description to import into Postman. Endpoints are grouped by tags; in Shelf they are Account, Catalog, Cart, Orders and Service.

Open one endpoint and read four things: the parameters, the request body (its "Example Value" and "Schema" views), the security it needs, and the "Responses" list. "Try it out" and then "Execute" send a real request from the page and show the "Request URL", the "Server response" and a ready curl command. "Authorize" takes your token once for the whole page.

Turn the responses list into a test list. Here is what the documentation of one endpoint gives you before you send anything.

One endpoint, seven tests
POST /api/cart/items  "Add a product (adds to the quantity
                       if it is already in the cart)"
Body: product_id (required, integer), quantity (1 to 10, default 1)

201  Added                        -> a product not yet in the cart
200  Quantity increased           -> the same product again
400  Validation failed            -> product_id missing
401  Not signed in                -> no token
404  Not found                    -> a product id that does not exist
409  Out of stock or not enough   -> a product with stock 0
422  More than 10 of one product  -> 8 in the cart, add 3 more

Status codes and what they should mean

The status code is the API's verdict, and programs that call the API act on it. A refusal sent with 200 breaks those programs even when the body reads well. Check the exact code the documentation names for each case, not just its first digit.

Some codes are worth knowing by their Shelf examples, all from its documentation and messages.

  • 200 OK

    A read or a change that worked. GET {{base_url}}/products?category=toys is 200 with "items": [] and "total": 0: an empty list is a valid answer, not a 404.

  • 201 Created

    Something new exists. POST {{base_url}}/products with your token creates your own product and answers with a Location header that points to it.

  • 204 No Content

    Done, and there is no body to read, as when you empty your cart with DELETE {{base_url}}/cart.

  • 400 Bad Request

    The data breaks a rule. PATCH your product with {"stock": 1000} gives "stock must be from 0 to 999."

  • 402 Payment Required

    Shelf's answer to a declined test card: 4000000000000002 gives "The card was declined. Try another test card."

  • 409 Conflict

    The request is fine, the state is not. A coupon on an empty cart: "Your cart is empty. Add something before you apply a coupon."

  • 422 Unprocessable

    Well formed, but the rule refuses it. An unknown coupon: "There is no coupon SAVE30. Check the code and try again."

Checking the body: values, not just presence

A body that has all the fields can still be wrong. Work out the expected values from the rule before you send, then compare. Calculated fields such as totals, counts and flags are where the mistakes hide, because each one depends on several other values.

Take Shelf's cart rules from its documentation: the coupon SAVE25 takes USD 25.00 off, never more than the subtotal; shipping is USD 4.99 and free from a subtotal of USD 50.00 (before the discount) or when every item ships free; the total is subtotal minus discount plus shipping. One Hearthline Classic Kettle 1.7 l (product 1, USD 49.00, does not ship free) with SAVE25 gives the cart below.

Check the shape too. Every Shelf error has the same body: an error object with a code, a message and, for validation, details. A client program reads the code, so a misspelled or missing code is a defect even when the message is fine.

Expected cart, worked out from the rules
POST {{base_url}}/cart/items   {"product_id": 1, "quantity": 1}  -> 201
POST {{base_url}}/cart/coupon  {"code": "SAVE25"}                 -> 200

Expected in the cart:
  "subtotal": 49      one kettle at USD 49.00
  "discount": 25      SAVE25, less than the subtotal
  "shipping": 4.99    subtotal under USD 50.00, kettle not free
  "total": 28.99      49 - 25 + 4.99

Checking the headers

Headers carry what the body does not. Check that Content-Type matches the body (JSON for a JSON API), that a 201 has a Location header pointing to the new resource, and that the server does not announce more than it needs, such as its framework and version.

Shelf puts an x-trace-id header on every response, refused ones included. Copy it into every API bug report: it lets a developer find the exact request in the logs. Header names are not case sensitive, so x-trace-id and X-Trace-Id are the same header.

Access: 401, 403 and 404

Access checks need at least two accounts, or one account and data that belongs to someone else. 401 means the API does not know who you are: no token, or an invalid or expired one. 403 means it knows who you are and you may not do this. Shelf's start page states the rule in one line: "401 no token or key, or an expired one · 403 signed in, but not allowed".

Some APIs answer 404 for another customer's data instead of 403, so that the answer does not even confirm the order exists. Shelf does this: its 404 means not there, or not yours. Whatever the API chose, the documentation must say it and every endpoint must follow it.

Access checks
GET {{base_url}}/me, no token
  401 "Sign in first: send Authorization: Bearer <token>."
DELETE {{base_url}}/products/3, your token, a shared catalog product
  403 "read_only_product"
GET {{base_url}}/orders/1, your token, another customer's order
  404 "There is no order 1 in your account."

Negative cases and state

For each required field, send the request without it. For each limit, send the values just inside and just outside it. For each typed field, send the wrong type, such as a price as the string "19.99" instead of the number 19.99. One fault per request: two faults in one request leave you guessing which rule refused it.

Then test state. Read the same resource after a change. A PUT replaces all fields, so in Shelf a PUT without a name is refused with "name is required.", while a PATCH changes only the fields you send: PATCH your product with {"stock": 7}, then GET it, and the stock should read 7 and in_stock true. Repeat a request that should happen once, and send steps in the wrong order, such as a coupon before anything is in the cart.

An API bug report template

An API defect is reproduced from text alone, so the report carries the request exactly as sent. Keep the base address as a variable and say where its value comes from, and quote the documentation for the expected result.

Template
Title: <METHOD> <path>: <what is wrong> when <condition>
Environment: <server or sandbox>, <API version or build>
Preconditions: <signed in as / cart state / existing data>
Request: <METHOD> <full address>
  Headers: <only the ones that matter>
  Body: <exact JSON>
Expected: <status and body>, per <documentation section>
Actual: <status and body you got>. Reproduced <N of N>.
Trace id: <x-trace-id from the response>

Where to learn this

Questions and answers

Can I test a REST API without writing code?

Yes. An API client such as Postman sends any request you build by hand, and Swagger UI's "Try it out" and "Execute" send one from the documentation page. Code is needed only to automate checks.

What is the difference between 400 and 422?

Both refuse the data. Many APIs use 400 when the request breaks the format or a field rule, and 422 when it is well formed but the business rule refuses it, such as an unknown coupon. APIs differ; the documentation decides, and every endpoint should follow the same choice.

Should an empty search result be 404?

Usually not. A list endpoint that finds nothing answers 200 with an empty list. 404 is for one resource that does not exist, such as a product id nobody has.

Why answer 404 instead of 403 for someone else's data?

A 403 confirms that the thing exists. A 404 tells a stranger nothing, which is safer for data such as orders. Check that the API does the same on every endpoint that holds private data.

What goes into an API test checklist?

For each endpoint: the success case, every documented error code, each required field missing, each limit just inside and outside, the wrong type, no token, someone else's data, and a second request that confirms the change.

More guides

See the first course

The full outline of every course is available: you can see each lesson before you start.

All courses