A useful REST API experiment answers a precise question: what happens when this client sends this request to this resource? GET and PUT are good starting points because they represent different intentions. GET retrieves a representation. PUT asks the server to create or replace the state at a known target. Understanding that distinction helps you explore an interface without confusing a successful response with a correct integration.

This walkthrough uses an imaginary project settings resource. The request fragments are illustrative and belong in a local fixture or an authorized development environment. You can follow the same reasoning with your own documented API, whether you prefer a terminal, an IDE HTTP file, or a graphical request client.

Begin with the meaning of the method

The HTTP standard classifies GET as safe and idempotent, and PUT as idempotent. Safe describes the intended request semantics: the client is asking to read, not to change application state. Idempotent means repeating an identical request has the same intended effect as sending it once. It does not promise identical responses, forbid access logs, or freeze a resource against other clients. PUT requests replacement or creation at the target URI. These definitions come from RFC 9110, the HTTP Semantics standard.

Before sending anything, write the resource name and the operation in plain language. For example, “read project 42 settings” and “replace project 42 settings with this document.” If you cannot describe the intended effect clearly, an attractive API explorer interface will not resolve the ambiguity. Our REST API exploration guide provides a broader starting point for mapping resources and methods.

Make one deliberate GET request

Start with a single resource that has a small, predictable response. Check the documentation for the path, authentication requirements, accepted response format, and possible errors. Prefer a disposable example over a customer record. Capture the status, relevant response headers, and body together; a body without its surrounding response can hide useful evidence.

This illustrative request reads the settings document:

GET /projects/42/settings HTTP/1.1
Accept: application/json

A successful body might contain a project display name, visibility, and notification preference. Record which properties are writable, which are generated by the server, and which are available only to particular roles. Do not assume that every field you can read may be sent back during an update. The API contract should explain that boundary.

Then change one documented read parameter, such as a supported field selection. Compare the result with your baseline. Keep other variables constant so that the difference has a plausible explanation. The GET request topic page offers additional questions for response inspection and retrieval behavior.

Treat PUT as a complete intention

For the imaginary settings interface, suppose the documented writable representation contains three required properties. Prepare that complete representation before making an update. A request that supplies only the property you want to change may be rejected or may remove omitted values, depending on the contract. Never infer partial update behavior from a successful experiment with one field.

PUT /projects/42/settings HTTP/1.1
Content-Type: application/json

{
  "display_name": "Research workspace",
  "visibility": "private",
  "notifications": true
}

Read the result and retrieve the resource again. Compare meaningful properties instead of relying on object key order or whitespace. If the server adds a timestamp, normalizes a name, or returns a calculated property, record that behavior separately. Your test should describe the contract the application needs, including normalization, without accidentally requiring the entire response to remain byte-for-byte identical.

Use the PUT request guide when deciding what belongs in the replacement document and which observations should become assertions.

Repeat the request and inspect the effect

Send the same prepared PUT again in the development environment, then read the resource. The important question is whether the requested resource state remains correct. A first request may create the resource while a later request updates it, so a different success status does not automatically mean the operation lacks idempotent semantics.

Look for unintended business effects as well. Imagine that saving settings also triggers a welcome message. Repeating a network request should not surprise a person with duplicate messages if the application promises one notification. That application-level expectation deserves an explicit test and may require a separate operation design.

Do not turn this experiment into an unrestricted retry loop. Give the client an attempt limit and a total time budget. When a request times out, preserve the request identifier and inspect known state before deciding whether another attempt is appropriate. A timeout tells you the client did not obtain a timely result; it does not establish what the server did.

Explore concurrent changes with a controlled scenario

A replacement workflow can overwrite another person's edit if both clients start from the same old document. Build a small two-client exercise: read the settings twice, save a change from the first client, and then attempt an update based on the second client's earlier copy. Decide what the product should do when the copies conflict.

Where the API supports entity tags and conditional updates, retain the returned ETag and submit the documented If-Match condition with the replacement. A failed precondition, commonly reported with status 412, gives the client a chance to retrieve the latest representation and ask the user to resolve competing edits. This mechanism is covered by the conditional request sections of the HTTP standard cited above.

The product decision matters as much as the header. Automatically taking the newest value may be reasonable for a harmless preference, while silently replacing an editorial change may be unacceptable. Write that decision into the integration notes so another developer does not “fix” a conflict by removing its protection.

Build an exploration notebook that becomes a test plan

For each experiment, save a short record with the purpose, environment, prerequisite state, request template, expected outcome, and actual observation. Replace credentials and personal data before sharing it. A useful note should allow a teammate to repeat the experiment without access to your terminal history.

Separate examples from guarantees. “This test record returned three properties” is an observation. “The contract requires these three properties” is a stronger statement that needs documentation or agreement from the API owner. Keeping these statements distinct prevents a convenient fixture from becoming an accidental production dependency.

Turn the most important expectations into focused checks: an authorized read returns the intended resource; a valid replacement persists the expected settings; a malformed document fails clearly; and a stale update follows the agreed conflict behavior. The Django API QA testing article extends this approach into a more systematic test suite.

Include the cleanup plan in that record. A repeatable experiment should start from a known fixture and leave the development environment ready for the next person. If the test changes settings, save the original values or recreate the disposable resource between runs. Avoid using cleanup as an excuse to perform broad deletion: restore only the objects the exercise owns. This also makes failures easier to diagnose, because yesterday's unfinished experiment cannot quietly become today's starting condition.

Investigate failures one variable at a time

When a request fails, avoid changing its URL, body, headers, and identity simultaneously. Begin with the documented working baseline. Check whether the failure concerns routing, authentication, permission, representation format, validation, or a conflict with current state. A small controlled difference is easier to explain than a pile of unrelated edits.

Also test how the client presents the failure. Preserve useful field errors, avoid displaying sensitive diagnostic details, and provide a next action when possible. An integration is incomplete when it handles the happy path beautifully but turns every other response into an unexplained spinner.

Conclusion: make requests explainable

GET and PUT become easier to work with when each experiment has a written intention and an observable outcome. Read a known resource, prepare a documented replacement, inspect the result, repeat deliberately, and exercise a competing update. The result is more than a successful request: it is a compact explanation of how your client should behave when data, permissions, and network conditions change.