Skip to content
CodeKruPro

API testing

Designing API tests

Positive and negative cases, validation, schemas and test data.

Learn: Designing API tests: positive, negative, boundaries, schemas and more8 minute read

Test design is deciding which requests to send and what to check, so that a few tests find most of the bugs. "How would you test this endpoint?" is the main question in most API interviews, and a long random list is a weak answer. Interviewers want a structure that shows you think about the contract (what the API promises to do), the data, the users and the ways things fail. This article gives that structure with one running example: POST /orders with the body {"productId": 12, "quantity": 2, "couponCode": "SAVE10"}, where quantity must be 1 to 100.

1. Start from the contract

Read the documentation or the OpenAPI file (a description of the API written in a format that programs can read): required and optional fields, types, limits, status codes, the error format, who may call it, and side effects, meaning other things the call changes besides its answer, such as stock, emails or payments. Write down questions where it is silent. Many bugs are found here, before any request is sent.

2. Positive cases

A valid request returns the documented status (201), the expected headers (Content-Type, Location) and a body with the right fields and types (text, number, true/false). Then prove the effect: read the order back with GET, or check the database, and compare it with what you sent. Some services echo the request back even when nothing was saved, so the read-back matters. Also check side effects the response does not show, such as reduced stock or a queued confirmation email.

3. Negative cases and boundaries

Change one invalid thing at a time, so one failure does not hide another:

  • Boundaries for quantity 1 to 100: 0, 1, 100, 101, and a negative number.
  • Types and presence: quantity as "2", 2.5, null, or missing; productId as text.
  • Business rules: an unknown product, a product out of stock, an expired or used-up coupon.
  • The whole body: empty, broken JSON (400), wrong Content-Type (415), unknown extra fields, an oversized payload (a very large body).

For every negative case, check three things: a 4xx and never a 5xx; an error body that names the field and the problem; and that nothing was saved. A good error body has a stable error code, a readable message, the field name and a correlation id (an ID that lets the team find this call in the logs), without stack traces (the technical list of code lines where a crash happened, which should stay hidden from users). RFC 9457 "problem details" is a standard shape for it.

4. Schema and contract checks

Validate responses against a JSON schema or the OpenAPI definition. A JSON schema is a file that lists which fields a response must have and their types. It catches missing fields, wrong types and unexpected values across the whole response cheaply. It cannot tell whether the values are right for this request, so combine it with value assertions on the fields the test is about.

5. Authentication and authorization

No token, an expired token and a tampered token give 401. Another customer's order id gives 403 or 404 with no data. A normal user calling admin-only operations gets 403, and the data stays unchanged.

6. Collections: paging, filtering and sorting

For GET /orders?page=2&size=20&sort=createdAt: walking every page returns each item exactly once; the total count matches; a page past the end returns an empty list or a documented error; a size above the maximum is capped or rejected; and filters, sorting and paging work together. Duplicates and gaps between pages usually come from an unstable sort order: when two items have the same value in the sort field, the server may order them differently on each call, so an item can appear on two pages or on none.

7. Repeats, races and slow dependencies

  • Repeat the same PUT or DELETE: the stored state does not change further. Repeat a POST with the same idempotency key (a unique value sent in a header, so the server can recognise a repeat; see the methods topic): one order, the same response.
  • Two clients edit the same order at the same time (a race): if the server uses ETags (a version tag for the order) and the If-Match header ("change it only if it still has this version"), the second client gets 412 Precondition Failed; without such protection, the second write silently overwrites the first.
  • Many parallel orders for the last items in stock must never oversell.
  • Hit the rate limit and expect 429; replace a slow payment provider with a stub (a fake service that you control) that delays or fails, and check for a clean timeout and a consistent order.

8. Security basics and automation

Responses must not leak password hashes, internal ids or other users' data, and injection characters (such as a quote mark or <script> that could be run as code) must give a clean 4xx or be stored as plain text. Add a simple response-time limit to catch big slowdowns; testing with many users at once (load testing) needs other tools. Then automate the stable checks, with each test creating its own data and cleaning up, so tests are independent and can run in parallel.

How to answer in an interview

Walk through the headings in order, with one or two concrete examples each, using the endpoint they gave you. Say what you would automate first: the positive path with a read-back, the main validation rules and the authorization checks. That shows both breadth and good judgement.

Common mistakes

  • Listing random inputs with no structure, or only happy paths.
  • Testing several invalid fields in one request, so one error hides another.
  • Stopping at the status code and never reading the data back.
  • Forgetting authorization, the area with the most serious bugs.

Recap

Start from the contract, prove the happy path saves the right data, then attack one field at a time with boundaries, wrong types and broken bodies. Add schema checks, access rules, paging, repeats and races, and basic security checks. For every negative test, check the code, the error body and that nothing changed.

18 questions0/18 solved

Not startedNot startedIn progressIn progressSolvedSolvedPro+Pro+

The first 2 questions of each topic are free. Pro+ opens every question.

Back to the plan