Foundations: Python, Git and toolsLoading progress…

HTTP and JSON

Build a small HTTP service with clear boundaries, tests, logs and a repeatable runtime.

A request and a response are just text

HTTP is a conversation of two messages. The client sends a request: a method (what to do), a path (to which resource), headers (facts about the message) and sometimes a body. The server sends back a response: a status code (how it went), headers and a body. Edit the request below and press Send. The panel on the right shows the exact text of both messages.

You edit the request

Headers (one per line)

Body

On the wire: request

POST /items HTTP/1.1
Host: localhost:8000
Content-Type: application/json
Content-Length: 30

{"name": "ruler", "price": 90}

On the wire: response

(press Send)

The server is a small simulation written for this course, with its own rules (for example it answers 422 for a well-formed JSON body that fails validation). Real servers choose their own.

Try the presets, then change one thing at a time: remove the Content-Type header, turn the price into a string, break the JSON.

Status codes are the headline

  • 2xx worked. 200 OK, 201 Created (a new resource now exists), 204 No Content (done, nothing to send back).
  • 4xx the request has a problem the caller can fix. 400 Bad Request, 404 Not Found, 405 Method Not Allowed, 415 Unsupported Media Type.
  • 5xx the server failed.

Which 4xx code to use for a validation failure is a design choice. The simulated server in this lesson answers 400 when the body is not JSON at all and 422 when it is JSON but the values are not acceptable.

JSON has types, and strings are not numbers

JSON text has a few kinds of value: string, number, boolean, null, array and object. The text "12" is a string and 12 is a number. A parser faithfully hands you whichever one was sent, and it is validation that decides what your program accepts. JSON that parses is not necessarily JSON your application can use.

keyJSON typevalue
namestring"ruler"
pricestring"90"
countnumber3
paidbooleanfalse
notenullnull
tagsarray["a","b"]

A value in quotes is a string, even if it looks like a number. Parsing succeeds either way. Deciding whether "90" is acceptable where a number is expected is the job of validation.

Edit the text. Values in quotes are strings, even when they look numeric.

Predict first. Is the JSON string "12" automatically the same as the number 12?

Chapter context

Engineering makes a program understandable when it fails or changes. Separate pure calculations from external I/O so behavior can be checked cheaply and errors can be connected to specific inputs.

Chapter reference: math, worked example & code

This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.

Math and notation

For money examples, use integer minor units rather than binary floating point. The subtotal is sum(quantity × unit_price), and the domain must specify rounding and tax rules before those operations are implemented.

Worked example

Two items cost 125 minor units each and three cost 40 each. The subtotal is 2×125 + 3×40 = 370. A test can exercise this calculation without starting an HTTP server. Request parsing and response formatting need separate checks.

Reference code

The following example uses the Python standard library and does not call a remote service.

def subtotal(items):
    return sum(quantity * price for quantity, price in items)
assert subtotal([(2, 125), (3, 40)]) == 370
assert subtotal([]) == 0

Python examples are provided for study and local execution; this page does not execute Python.

Common mistakes

Test coverage counts executed lines, not verified requirements. A container does not turn an unsafe operation into a safe one. JSON validity alone does not establish application validity.