HTTP Methods

An HTTP method is the first word of every request line: it tells the server what the client wants done with the target resource, the thing the URI identifies, such as an order. GET /orders/42 asks for order 42, while DELETE /orders/42 asks the server to remove it. The URI is the same; the meaning, the expected response and the risk are completely different.

RFC 9110, the HTTP Semantics standard, defines GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS and TRACE, and RFC 5789 adds PATCH. Each method has a defined meaning and two properties testers rely on: whether it is safe and whether it is idempotent. This lesson covers the seven that web applications and APIs use every day.

Why it matters

The method is a promise to every program between the user and the server. Crawlers and link-preview services follow GET links, browsers prefetch pages, and HTTP clients may resend an idempotent request when a connection drops. That is harmless only while the application keeps the promise: a crawler can trigger a delete action placed behind a GET link.

For a tester, methods become a ready-made list of expectations for every endpoint: what must not change state, what may be sent twice and which methods must be refused. Duplicate orders, updates that wipe fields and regular users who can delete records are often found by changing only the method or by sending the same request twice.

The seven methods you will test

The responses below are typical; the API contract states the exact codes. RFC 9110 also defines CONNECT (a tunnel through a proxy) and TRACE (echoes the request for diagnostics), rarely tested inside an application. Method names are case-sensitive; the standard ones are uppercase.

  • GET retrieves a representation of the resource, meaning its current state in a format such as JSON or HTML, usually with 200 OK. Content sent in a GET has no defined meaning in RFC 9110, and some servers reject it.
  • HEAD is GET without the response body. The server should send the same headers as for GET, so a client can check existence, size or type without downloading. Every general-purpose server must support GET and HEAD.
  • POST sends content for the resource to process by its own rules: create an order in /orders, submit a form, start an action such as /orders/42/cancel. A POST that creates something should answer 201 Created with a Location header.
  • PUT creates or replaces the resource with the complete state in the body: 200 or 204 when it replaced, 201 when it created.
  • PATCH (RFC 5789) applies the changes described in a patch document, so only what the document names changes. Content-Type names the format, for example application/merge-patch+json.
  • DELETE removes the resource: typically 204 No Content, 200 with a message, or 202 Accepted when the deletion is queued. As with GET, content sent in a DELETE request has no defined meaning.
  • OPTIONS asks which methods and features the resource supports; the answer is in headers such as Allow. Browsers also send it on their own as a CORS preflight, covered in the CORS lesson.

Try it: HTTP Request Inspector Try it: cURL Generator

Safe and idempotent: two promises in RFC 9110

A method is safe when its meaning is read-only: the client neither requests nor expects a change of state on the server. GET, HEAD, OPTIONS and TRACE are safe. Logging the request or counting a page view is still allowed. RFC 9110 gives the example of a link like page?do=delete: if following it deletes data, the resource is at fault, not the crawler that followed it.

A method is idempotent when sending the same request several times has the same intended effect on the server as sending it once. PUT, DELETE and every safe method are idempotent; POST is not, and PATCH is not in general. Setting an address twice leaves one address; "add one item" sent twice adds two. Idempotency concerns the server state, not the response: a second DELETE may return 404 and still be correct.

RFC 9110 allows an idempotent request to be repeated automatically when the connection fails before the response arrives, and says a client should not automatically retry a non-idempotent one unless it knows the request is in fact idempotent or was never applied. Safe does not mean secure: a GET still needs authorization, and sensitive data does not belong in its URI, which servers, proxies and browsers record.

GET, HEAD and OPTIONS are safe and idempotent, PUT and DELETE change state but are idempotent, and POST and, in general, PATCH are neither, so clients should not retry them automatically.
MethodSaferead-only meaningIdempotentrepeating = same effectRequest bodyTypical success response
GETreadYesYesNo defined meaning200 OKwith the representation
HEADheaders onlyYesYesNo defined meaning200 OKsame headers as GET, no body
OPTIONSwhat is supportedYesYesNo defined use200 or 204with Allow
PUTcreate or replaceNoYesThe complete new state200 or 204201 if it created
DELETEremoveNoYesNo defined meaning204, 200 or 202202 if queued
POSTprocess contentNoNoContent to process201 Createdwith Location, when it creates
PATCHpartial changeNoNot in generala specific patch can beA patch document200 or 204

Properties as defined in RFC 9110, PATCH in RFC 5789. Status codes are the typical ones; the API contract states the exact codes.

Text version
Method   Safe  Idempotent      Request body         Typical success response
-------  ----  --------------  -------------------  -------------------------------
GET      yes   yes             no defined meaning   200 + the representation
HEAD     yes   yes             no defined meaning   200, same headers as GET, no body
OPTIONS  yes   yes             no defined use       200 or 204 + Allow
PUT      no    yes             full new state       200 or 204; 201 if it created
DELETE   no    yes             no defined meaning   204, 200, or 202 if queued
POST     no    no              content to process   201 + Location if it created
PATCH    no    not in general  patch document       200 or 204

What to test for each method

Turn each promise into test conditions. After every request check two things: the response, and the state of the resource, read back with a separate GET or from the database.

  • GET and HEAD: nothing changes, however often you send them. HEAD returns the same status and headers as GET with an empty body. Look for actions hidden in GET links, such as ?action=cancel.
  • POST: send the same request twice, as a double-click or a retry would, and test the duplicate rule agreed with the team: reject, merge or accept. Some APIs accept a client-generated key, often in an Idempotency-Key header, to recognise a repeat.
  • PUT: send it twice and expect one stored state. Leave out an optional field: expect it to be cleared, or the request rejected, as the contract says; quietly keeping the old value means PUT is applied as a partial update.
  • PATCH: compare the whole resource before and after; fields you did not send must not change. An unsupported patch format should get 415 Unsupported Media Type, with an Accept-Patch header as RFC 5789 recommends.
  • DELETE: a following GET returns 404, a repeated DELETE changes nothing else, and related data is handled as the requirement says.
  • Unsupported methods: expect 405 Method Not Allowed with an Allow header, which RFC 9110 makes mandatory, or 501 Not Implemented for a method the server does not recognise. A 200 or 500 is a defect, and OPTIONS should list the methods that really work.
  • Authorization per method: a user who may GET a record is not necessarily allowed to PUT or DELETE it. Repeat the write methods with a less privileged account; the OWASP API Security Top 10 (2023) calls this risk Broken Function Level Authorization. Test only systems you own or have written permission to test.

Try it: API Request Builder Try it: HTTP Status Code Lookup

Worked example: one endpoint, every method

An address-book API documents GET, HEAD, OPTIONS, PUT, PATCH and DELETE on /v1/addresses/{id}, and address 7 belongs to user A. Instead of one vague "update address" test, the tester writes one row per promise and checks the stored state as well as the status code in every row:

  • Row 4 separates PUT from PATCH: keeping the old city would mean PUT is applied as a partial update.
  • Row 8 runs while address 7 still exists; a 204 there means user B can delete another user's data, a critical authorization defect.
#   Request (as user A unless stated)       Expected result
1   GET /v1/addresses/7, sent twice         200 both times, same body, nothing changed
2   HEAD /v1/addresses/7                    200, same headers as GET, empty body
3   PUT /v1/addresses/7 (full body), twice  200 or 204 both times, one stored address
4   PUT /v1/addresses/7 without "city"      4xx (city is required), address unchanged
5   PATCH /v1/addresses/7 {"zip": "12271"}  200, only zip changed; street and city kept
6   POST /v1/addresses/7                    405 + Allow: GET, HEAD, OPTIONS, PUT, PATCH,
                                            DELETE
7   OPTIONS /v1/addresses/7                 200 or 204, Allow lists the same six methods
8   DELETE /v1/addresses/7 as user B        403 or 404, address 7 still exists
9   DELETE /v1/addresses/7                  204, then GET returns 404
10  DELETE /v1/addresses/7 again            404 as documented, no other address affected

Try it: REST API Tester

Common mistakes

  • Reading "safe" as "secure". Safe only means the client asks for no change; a GET still needs authentication and authorization.
  • Sending each POST only once. Double submissions and retries are a common source of duplicate orders and payments.
  • Expecting identical responses from an idempotent method. A repeated DELETE may return 404; idempotency is about the state on the server.
  • Treating PUT and PATCH as interchangeable, and never checking the fields that were not sent.
  • Testing only the methods the user interface calls. Any client can send any method, so check that unlisted ones get 405 with Allow.

The QA perspective

Methods are a review checklist before any code runs. For each endpoint in a story or API contract, list its methods and ask: what changes on the server, may the request be repeated, and what does a duplicate do? Ask the web and mobile developers whether their clients retry after a timeout; on mobile networks a resent POST is a real scenario.

Name the method in every test case and bug report: "update the address" could be PUT or PATCH, and a request without its method cannot be replayed. For endpoints with roles, keep a small method × role table with the expected status in each cell, and run it again whenever permissions change.

Practice exercise

Review the methods of a shop cart API

Your task

You are testing a shop API on staging. Using the contract excerpt and the six observations below, state whether each documented method is safe and idempotent, then decide for each observation whether it is a defect, what should happen instead, and why.

Material
Contract excerpt
GET    /v1/cart                  read the cart
POST   /v1/cart/items            add an item, body {"sku": "A1", "qty": 1}
PUT    /v1/cart/items/{sku}      set the quantity of an item, body {"qty": 2}
DELETE /v1/cart/items/{sku}      remove an item
PATCH  /v1/profile               change some profile fields
GET    /v1/coupons/apply?code=X  apply a coupon to the cart

Observations
a  PUT /v1/cart/items/A1 {"qty": 2}, sent twice  -> quantity is 4
b  Opening /v1/coupons/apply?code=SAVE10 twice    -> discount applied twice
c  HEAD /v1/cart                                  -> 200 with the full JSON body
d  DELETE /v1/cart (not in the contract)          -> 500 Internal Server Error
e  PATCH /v1/profile {"phone": "0550000000"}      -> 200, "email" is now null
f  POST /v1/cart/items, retried after a timeout   -> the same item appears twice
Steps
  1. Mark every contract line as safe or not, and idempotent or not.
  2. Compare each observation with what its method promises, and write the expected behaviour or a question for the team.
  3. Order the defects by risk.
Show the model answer
Model answer

Safe and idempotent by their method: both GET lines, although the coupon line describes a change of state (see b). Idempotent but not safe: PUT and DELETE. Neither: POST, and PATCH in general.

a) Defect. PUT sets the state, so two identical requests must leave quantity 2; this server adds instead.

b) Design defect. Applying a coupon changes state, so it must not sit behind a GET, where crawlers, link previews and prefetching can trigger it. Expected: an unsafe method such as POST /v1/cart/coupons. Even then, the same code applied twice should not double the discount unless the coupon rules allow it.

c) Defect. A HEAD response must not contain a body, and its headers should match those of GET.

d) Defect. Expected 405 Method Not Allowed with an Allow header listing the supported methods, not a server error.

e) Defect. PATCH must change only the fields sent; clearing the e-mail is data loss and may lock the user out.

f) Not automatically a defect, because POST is not idempotent. Ask whether the client should retry a POST at all and whether adding an existing SKU should merge quantities, then test the agreed rule.

Risk order: e (data loss), b (discounts triggered by automated tools), a (wrong quantities and totals), then d and c; f stays open until the team answers.

Frequently asked questions

What is the difference between PUT and PATCH?

PUT sends the complete new state of the resource and replaces what is there, or creates it. PATCH sends only a description of changes, such as a new value for one field. Sending the same PUT twice always leaves the same state; PATCH is not idempotent in general, because a change like "add 1 to the quantity" accumulates.

Can a GET request have a body?

HTTP message framing allows it, but RFC 9110 says content in a GET has no generally defined meaning, cannot change what the request means, and may make some servers reject the request. Put the inputs of a GET in the URI, as the next lesson on path and query parameters shows, or use POST when a search needs a large structured body.

Is POST only for creating resources?

No. POST asks the resource to process the content by its own rules: creating an item, submitting a form, starting a job or running a complex search. 201 Created with Location is expected only when it creates a resource; otherwise 200, 202 or 204, as the contract documents.

Why do I see OPTIONS requests in DevTools that nobody wrote?

Browsers send them as CORS preflights: before certain cross-origin requests, for example a PUT, a DELETE or a request with custom headers, the browser asks the server whether the real request is allowed. If the preflight fails, the real request is never sent. The CORS lesson explains this in detail.

References

  • RFC 9110: HTTP SemanticsIETF · 2022The meaning of HTTP methods, header fields, status codes and content negotiation, independent of the wire version.
  • RFC 5789: PATCH Method for HTTPIETF · 2010The PATCH method for partial updates, as opposed to PUT replacing a whole resource.
  • HTTP request methods — MDNMDN Web Docs (Mozilla)The HTTP request methods (GET, POST, PUT, PATCH, DELETE and others) and which of them are safe, idempotent and cacheable.
  • OWASP API Security Top 10 (2023)OWASP Foundation · 2023The ten most common API weaknesses: broken object-level authorization, broken authentication, unrestricted resource consumption and more.

Practise with Mutqan tools

Compose and send HTTP requests (method, URL, headers, auth, body) and inspect the response — a lightweight Postman in your browser.

API Testing

Test REST endpoints with full control over method, headers and JSON body, then assert on status, headers and JSON paths.

API Testing

Build cURL commands from method, URL, headers, body and auth options.

Web

See exactly what your client sends: method, headers, query, body, IP and TLS info.

API Testing

Go deeper

Your progress on this topic

Part of the QA Roadmap