POST
Creating something new
GET reads data. But what about creating data? When a user fills out a form, submits an order, or registers an account, the client needs to send data to the server and ask it to create something. That is what POST does.
POST sends data to the server in the request body and asks it to create a new resource. Unlike GET, which only reads, POST changes the server’s state. After a successful POST, something exists that did not exist before.
What a POST request looks like
POST /books HTTP/1.1
Host: api.example.com
Content-Type: application/json
{"title":"Kindred","author_id":"author-3","genre":"science-fiction"} The method is POST. The path is /books, meaning “add to the books collection.” The Content-Type header says the body is JSON. And the body itself contains the data for the new book.
The server creates the book and responds:
HTTP/1.1 201 Created
Content-Type: application/json
Location: /books/book-6
{"id":"book-6","title":"Kindred","author_id":"author-3","genre":"science-fiction"} Two things to notice here. First, the status code is 201 Created, not 200 OK. The server is saying “I created something new for you.” Second, the Location header tells the client where to find the new resource: /books/book-6. This is a convention you will see in production APIs everywhere.
The request body matters here
The previous section explained that the body carries data. POST is where the body matters most, because without it, the server does not know what to create.
The Content-Type header tells the server how to read the body. Different formats look different:
JSON (Content-Type: application/json) is the format we use throughout this course series:
{"title":"Kindred","genre":"science-fiction"} Form data (Content-Type: application/x-www-form-urlencoded) is what HTML forms submit by default:
title=Kindred&genre=science-fiction Multipart (Content-Type: multipart/form-data) is used for file uploads, covered in the File Uploads course.
Section 5 of this course goes deeper into body formats. For now, the important thing is: POST sends data in the body, and Content-Type tells the server how to interpret it.
POST is not safe
POST changes the server. Creating a book, placing an order, sending a message, these all modify state. POST is not a safe method. Browsers do not cache POST responses. If you hit the back button after submitting a form, the browser shows you a “resubmit form?” warning. Why? Because replaying the POST would create a duplicate, and the browser is trying to protect you.
POST is not idempotent
Here is where it gets interesting. What happens if you send the same POST request twice?
You get two books. The first call creates book-6. The second call creates book-7. The result depends on how many times you call it. That is the definition of non-idempotent.
This matters for error handling. If a POST request fails due to a network error, you cannot just blindly retry it. The server might have received the first request, created the resource, and the failure happened on the way back. Retrying would create a duplicate.
[!NOTE] The REST API Design course solves this problem with idempotency keys: the client sends a unique key with the request, and if the server sees the same key twice, it returns the original result instead of creating a duplicate.
We now know how to read data (GET) and create data (POST). But what about changing data that already exists, or removing it entirely? That is what the next lesson covers with PUT, PATCH, and DELETE.
Exercises
Exercise 1: Use curl -X POST with a JSON body to create a resource. Look for the 201 status code and the Location header in the response.
Exercise 2: Send the exact same POST request twice. Verify that two separate resources are created. This is non-idempotent behavior.
Exercise 3: Try sending a POST without a Content-Type header. What happens? The server does not know how to parse the body.
Why is POST not idempotent?