Curl for API Work with Requests Headers and JSON
A browser can open an API URL, but curl lets you see the request and response more closely. In this lesson you will start a small local server, fetch a JSON response, inspect its headers and send a JSON body. You need Python 3 and curl installed. The server is deliberately small and runs only on your own computer.
Create a file called server.py with the following code:
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
body = json.dumps({"name": "tea", "id": 1}).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(body)
def do_POST(self):
body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
try:
data = json.loads(body)
except ValueError:
self.send_error(400)
return
result = json.dumps({"received": data}).encode()
self.send_response(201)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(result)
HTTPServer(("127.0.0.1", 18766), Handler).serve_forever()
Run python3 server.py in a terminal and leave it running. Open another terminal for the curl commands below. The address 127.0.0.1 points to your own machine. This toy service returns the same item for any GET path and echoes JSON sent to any POST path; it does not save anything.
Fetch the response
Start with a GET request:
curl -sS http://127.0.0.1:18766/items
The response body is:
{"name": "tea", "id": 1}
The -sS combination keeps the progress meter quiet while still showing errors. Curl writes the body to standard output, which makes it easy to pipe or save. A connection error means the server is not running at that address, the port is occupied, or a local firewall is interfering. Check the first terminal before changing your request.
A successful connection does not always mean a successful API operation. An API can return a 404 or 500 with a perfectly readable body. You need the HTTP status as well.
See the headers
Add -i to include response headers:
curl -sS -i http://127.0.0.1:18766/items
The relevant output from the local server is shown below. The server version and date will vary.
HTTP/1.0 200 OK
Content-Type: application/json
{"name": "tea", "id": 1}
The first line gives the status. The content type tells a client how to interpret the body. A real API may also return cache instructions, a request identifier or rate-limit information. Those headers can be useful when a request works on your laptop and fails in an application.
The server in this exercise uses Python’s basic HTTP server and reports HTTP/1.0. That is a property of this example, not a requirement for API servers. To inspect the exchange in more detail, curl’s -v option prints diagnostic information to standard error. Be careful with that output: request headers can contain credentials.
Send JSON
A POST request can carry data to the server. Here the handler simply sends back the parsed data:
curl -sS -X POST -H 'Content-Type: application/json' -d '{"name":"coffee"}' http://127.0.0.1:18766/items
The response is:
{"received": {"name": "coffee"}}
The header declares that the request body is JSON. The -d option supplies the body, and curl uses POST for data requests; the explicit -X POST here makes the method visible while you learn. The server responds with status 201, although the body alone does not show it. Add -i when you want to see that status.
The single quotes in the shell command protect the JSON from interpretation by a typical Unix shell. Quoting differs in some Windows shells, so use the syntax appropriate to yours. If you send invalid JSON, this particular server returns a 400 response. Production APIs may validate fields too, and their error bodies can explain which field failed.
Take the exercise further
Change the item name in the POST body and check that it appears in the response. Then add -i and compare the status and headers with the GET response. Finally, stop the server with Ctrl+C in its terminal. You have now seen the pieces that most API clients assemble for you: a method, a URL, headers and a body.
This local service is for learning only. It has no authentication, persistent storage or production security controls. When you move to a real service, read its documentation for its authentication scheme and usage limits, and keep tokens out of command histories and shared logs. The existing lesson on API error handling explains what to do when the response signals a failure.