ЁЯПл The SchoolтА║ЁЯПв APIsтА║ЁЯЧДя╕П рдзрдбрд╛ 03 тАФ REST resources: рдлрд╛рдЗрд▓рд┐рдВрдЧ рдХрдкрд╛рдЯрд╛рдВрддрд▓реА рдирд╛рдореЗ
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯЧДя╕П рдзрдбрд╛ 03 тАФ REST resources: рдлрд╛рдЗрд▓рд┐рдВрдЧ рдХрдкрд╛рдЯрд╛рдВрддрд▓реА рдирд╛рдореЗ

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 03 ┬╖ рдорд╛рдЧреЗ: lesson-02-http-anatomy ┬╖ рдкреБрдвреЗ: lesson-04-json-and-schemas


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ02, рдЖрдгрд┐ рддреНрдпрд╛рд╕реЛрдмрдд рдХреЛрдгрддреЗрд╣реА API рдЕрдВрджрд╛рдЬ рдХрд░рддрд╛ рдпреЗрдгреНрдпрд╛рдЬреЛрдЧреЗ рдмрдирд╡рдгрд╛рд░реА рдорд╛рдВрдбрдгреАрдЪреА рдкрджреНрдзрдд: resources (рдирд╛рдореЗ), collections, ids, рдЖрдгрд┐ рдХреЛрдгрддреА рдХреНрд░рд┐рдпрд╛рдкрджреЗ рдкреБрдиреНрд╣рд╛ рдХрд░рд╛рдпрд▓рд╛ рд╕реБрд░рдХреНрд╖рд┐рдд рдЖрд╣реЗрдд.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

Archive рдордзреНрдпреЗ рдХрдкрд╛рдЯреЗ ЁЯЧДя╕П рдЖрд╣реЗрдд, рдкреНрд░рддреНрдпреЗрдХ рдХрдкрд╛рдЯрд╛рдд drawers ЁЯУБ рдЖрд╣реЗрдд, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ drawer рд▓рд╛ рдПрдХ рд▓реЗрдмрд▓ рдЖрд╣реЗ. Counter рдЪреНрдпрд╛ slips рддреНрдпрд╛рдВрдирд╛ рддрд╢реАрдЪ рдирд╛рд╡реЗ рджреЗрддрд╛рдд:

рд╣реЗ рдЕрдВрджрд╛рдЬ рдХрд░рдгреНрдпрд╛рдЬреЛрдЧреЗ рдмрдирд╡рдгрд╛рд░рд╛ рдирд┐рдпрдо: URLs рдореНрд╣рдгрдЬреЗ рдирд╛рдореЗ, methods рдореНрд╣рдгрдЬреЗ рдХреНрд░рд┐рдпрд╛рдкрджреЗ. рдХрдзреАрдЪ /getStudent?id=2 рдХрд┐рдВрд╡рд╛ /deleteStudent/2 рдирд╛рд╣реА тАФ рдХреНрд░рд┐рдпрд╛рдкрдж рдЖрдзреАрдЪ method рдордзреНрдпреЗ рдЖрд╣реЗ. рд▓реЛрдХ REST рдореНрд╣рдгрддрд╛рдд рддреЗрд╡реНрд╣рд╛ рддреНрдпрд╛рдВрдирд╛ рд╣реЗрдЪ рдореНрд╣рдгрд╛рдпрдЪреЗ рдЕрд╕рддреЗ.

рдЖрдгрд┐ clerk рд▓рд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреА рд╡рд╛рдЯрдгрд╛рд░реА рдЖрдгрдЦреА рдПрдХ рдЧреЛрд╖реНрдЯ: рд╣реА slip рджреЛрдирджрд╛ рджреЗрдгреЗ рд╕реБрд░рдХреНрд╖рд┐рдд рдЖрд╣реЗ рдХрд╛?

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart TB
    cab["ЁЯЧДя╕П /v1/students тАФ the cabinet (collection)<br/>GET lists ┬╖ POST adds a drawer"]
    dr["ЁЯУБ /v1/students/2 тАФ one drawer (resource)<br/>GET reads ┬╖ PUT replaces ┬╖ DELETE removes"]
    nest["ЁЯзн /v1/classes/3A/students<br/>nouns nest; no verbs in URLs"]
    cab -->|"1 pick an id"| dr
    cab -->|"2 filter by parent"| nest
    safe["ЁЯФБ safe to repeat? GET yes ┬╖ PUT/DELETE twice = once ┬╖ POST no (тЖТ lesson 07)"]
    dr -.->|"3"| safe

тЭУ рдХрд╛рдп

ЁЯФз PUT рд╡рд┐рд░реБрджреНрдз PATCH рд╡рд┐рд░реБрджреНрдз POST, рдЖрдгрд┐ рдмрд╛рдХреАрдЪреЗ рдЪрд╛рд░: counter рдЖрддрд╛ рд╕рд╛рддрд╣реА methods рдирд╛ рдЙрддреНрддрд░ рджреЗрддреЛ тАФ PATCH /v1/students/2 {"grade":"A"} рдПрдХ field рдмрджрд▓рддреЗ, HEAD рдлрдХреНрдд headers рджреЗрддреЗ, OPTIONS рдХрд╛рдп рдЪрд╛рд▓рддреЗ рддреНрдпрд╛рдЪреА рдпрд╛рджреА рджреЗрддреЗ. рдкреНрд░рддреНрдпреЗрдХ method, рддреАрди рд╢рдмреНрдж (safe ┬╖ idempotent ┬╖ cacheable) рдЖрдгрд┐ рддреНрдпрд╛рдЪреЗ status codes рдпрд╛рдВрд╕рд╣, рдзрдбрд╛ 13 тАФ рдкреНрд░рддреНрдпреЗрдХ REST method рдордзреНрдпреЗ рдХрд╛рдврд▓реЗрд▓реА рдЖрд╣реЗ; bash api/methods_demo.sh рдЪрд╛рд▓реВ counter рд╡рд░ рдкреНрд░рддреНрдпреЗрдХ рдирд┐рдпрдо рд╕рд┐рджреНрдз рдХрд░рддреЗ.

ЁЯдФ рдХрд╛

рдЕрдВрджрд╛рдЬ рдХрд░рддрд╛ рдпреЗрдгреЗ рд╣реЗрдЪ product рдЖрд╣реЗ. рддреБрдордЪреЗ API рдХрдзреАрдЪ рди рдкрд╛рд╣рд┐рд▓реЗрд▓рд╛ developer рдЕрдВрджрд╛рдЬ рдХрд░реВ рд╢рдХрддреЛ рдХреА GET /v1/students/2 рдПрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдереА рд╡рд╛рдЪрддреЗ рдЖрдгрд┐ DELETE /v1/students/2 рддреНрдпрд╛рд▓рд╛ рдХрд╛рдврддреЗ тАФ рдЖрдгрд┐ proxy, cache рдЖрдгрд┐ gateway рд╕реБрджреНрдзрд╛ рддрд╕рд╛рдЪ рдЕрдВрджрд╛рдЬ рдХрд░реВ рд╢рдХрддрд╛рдд, рдХрд╛рд░рдг рд╣реА рдкрджреНрдзрдд рд╕рдЧрд│реНрдпрд╛рдВрдЪреА рд╕рд╛рдорд╛рдпрд┐рдХ рдЖрд╣реЗ. URLs рдордзрд▓реА рдХреНрд░рд┐рдпрд╛рдкрджреЗ рд╣реЗ рд╕рдЧрд│реЗ рдлреЗрдХреВрди рджреЗрддрд╛рдд рдЖрдгрд┐ рд╕рдЧрд│реНрдпрд╛рдВрдирд╛ PDF рд╡рд╛рдЪрд╛рдпрд▓рд╛ рднрд╛рдЧ рдкрд╛рдбрддрд╛рдд.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

school_api.py рдордзрд▓реЗ route() path рд▓рд╛ рдирд╛рдореЗ рдЖрдгрд┐ ids рдордзреНрдпреЗ рддреЛрдбрддреЗ (['students', '2']); do_GET, do_POST, do_PUT, do_DELETE рд╣реА рдХреНрд░рд┐рдпрд╛рдкрджреЗ рдЖрд╣реЗрдд. рд▓рдХреНрд╖рд╛рдд рдШреНрдпрд╛, do_DELETE рд╡рд┐рджреНрдпрд╛рд░реНрдереА рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рд╣реЛрддрд╛ рдХрд╛ рддреЗ рдХрдзреАрдЪ рддрдкрд╛рд╕рдд рдирд╛рд╣реА: STUDENTS.pop(sid, None) рдордЧ 204 тАФ рд╣реА рдПрдХрд╛ рдУрд│реАрддрд▓реА idempotency рдЖрд╣реЗ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

K='X-API-Key: hall-pass-123'; B=http://127.0.0.1:8080/v1
curl -s "$B/students?limit=10"                       # the cabinet
curl -s $B/students/2                                # one drawer
curl -s $B/classes/3B/students                       # nested nouns
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE $B/students/5 -H "$K"   # 204
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE $B/students/5 -H "$K"   # 204 again тАФ idempotent
curl -s -X PUT $B/students/4 -H "$K" -H 'Content-Type: application/json' -d '{"name":"Meera","class":"3B","grade":"A+"}'
curl -s -X PUT $B/students/4 -H "$K" -H 'Content-Type: application/json' -d '{"name":"Meera","class":"3B","grade":"A+"}'   # same answer

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

рджреЛрди DELETE рджреЛрдирджрд╛ 204 рдЫрд╛рдкрддрд╛рдд; рджреЛрди рдПрдХрд╕рд╛рд░рдЦреЗ PUT рдПрдХрд╕рд╛рд░рдЦреЗрдЪ JSON рдкрд░рдд рджреЗрддрд╛рдд (рдЖрдгрд┐ -i рдЬреЛрдбрд▓реНрдпрд╛рд╕ рддреЛрдЪ ETag). GET /v1/classes/3B/students рдлрдХреНрдд 3B рдЪреА рдпрд╛рджреА рджреЗрддреЗ. рд╡рд┐рджреНрдпрд╛рд░реНрдереА 5 рдкрд░рдд рдорд┐рд│рд╡рдгреНрдпрд╛рд╕рд╛рдареА server рдкреБрдиреНрд╣рд╛ рд╕реБрд░реВ рдХрд░рд╛ (Ctrl+C, рдкреБрдиреНрд╣рд╛ рдЪрд╛рд▓рд╡рд╛) тАФ archive memory рдордзреНрдпреЗ рдЖрд╣реЗ.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рдлрдХреНрдд рдирд╛рдо рдЖрдгрд┐ рдХреНрд░рд┐рдпрд╛рдкрджрд╛рд╡рд░реВрди рддреБрдореНрд╣реА endpoint рдЪрд╛ рдЕрд░реНрде рдУрд│рдЦреВ рд╢рдХрддрд╛, рдЖрдгрд┐ рддреБрдореНрд╣реА idempotency рдЕрдиреБрднрд╡рд▓реА: safe slip рдкреБрдиреНрд╣рд╛ рджрд┐рд▓реНрдпрд╛рдиреЗ рдХрд╛рд╣реАрдЪ рдмрджрд▓рд▓реЗ рдирд╛рд╣реА.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: idempotent рдХреНрд░рд┐рдпрд╛рдкрджрд╛рдВрдореБрд│реЗрдЪ retries, load-balancer failover рдЖрдгрд┐ "at-least-once" queues рд╕реБрд░рдХреНрд╖рд┐рдд рд╣реЛрддрд╛рдд. рддреБрдореНрд╣реА рд╡рд╛рдЪрд▓реЗрд▓реА рдкреНрд░рддреНрдпреЗрдХ рджреБрд╣реЗрд░реА-order рдШрдЯрдирд╛ рдореНрд╣рдгрдЬреЗ рдЪрд╛рдВрдЧрд▓реНрдпрд╛ рд╣реЗрддреВрдЪреНрдпрд╛ client рдиреЗ retry рдХреЗрд▓реЗрд▓реЗ non-idempotent write рдЕрд╕рддреЗ.

тПня╕П рдкреБрдвреЗ

Slip рд╡рд░ рдХрд╛рдп рдЕрд╕рддреЗ? рдкреНрд░рдорд╛рдгрд┐рдд form тАФ JSON, validation, рдЖрдгрд┐ рдЫрд╛рдкрд▓реЗрд▓рд╛ рдХреЕрдЯрд▓реЙрдЧ (OpenAPI).

git checkout lesson-04-json-and-schemas

ЁЯЧДя╕П Lesson 03 тАФ REST resources: nouns in filing cabinets

ЁЯУН You are here: Lesson 03 of 12 ┬╖ Previous: lesson-02-http-anatomy ┬╖ Next: lesson-04-json-and-schemas


ЁЯУж What's in this branch

Lessons 01тАУ02, plus the filing convention that makes any API predictable: resources (nouns), collections, ids, and which verbs are safe to repeat.

ЁЯзТ Explain like I'm 5

The archive has cabinets ЁЯЧДя╕П, each cabinet has drawers ЁЯУБ, and every drawer has a label. The counter's slips name them the same way:

The rule that makes it predictable: URLs are nouns, methods are verbs. Never /getStudent?id=2 or /deleteStudent/2 тАФ the verb is already in the method. That is what people mean by REST.

And one more thing the clerk cares about: is this slip safe to hand in twice?

ЁЯЧ║я╕П Diagram

flowchart TB
    cab["ЁЯЧДя╕П /v1/students тАФ the cabinet (collection)<br/>GET lists ┬╖ POST adds a drawer"]
    dr["ЁЯУБ /v1/students/2 тАФ one drawer (resource)<br/>GET reads ┬╖ PUT replaces ┬╖ DELETE removes"]
    nest["ЁЯзн /v1/classes/3A/students<br/>nouns nest; no verbs in URLs"]
    cab -->|"1 pick an id"| dr
    cab -->|"2 filter by parent"| nest
    safe["ЁЯФБ safe to repeat? GET yes ┬╖ PUT/DELETE twice = once ┬╖ POST no (тЖТ lesson 07)"]
    dr -.->|"3"| safe

тЭУ What

ЁЯФз PUT vs PATCH vs POST, and the other four: the counter now answers all seven methods тАФ PATCH /v1/students/2 {"grade":"A"} changes one field, HEAD gives the headers only, OPTIONS lists what is allowed. Each is drawn, with the three words (safe ┬╖ idempotent ┬╖ cacheable) and its status codes, in lesson 13 тАФ every REST method; bash api/methods_demo.sh proves every rule on the running counter.

ЁЯдФ Why

Predictability is the product. A developer who has never seen your API can guess that GET /v1/students/2 reads one student and DELETE /v1/students/2 removes it тАФ and a proxy, a cache and a gateway can guess the same, because the convention is shared. Verbs in URLs throw that away and force everyone to read the PDF.

ЁЯФз How (in this repo)

route() in school_api.py splits the path into nouns and ids (['students', '2']); do_GET, do_POST, do_PUT, do_DELETE are the verbs. Notice do_DELETE never checks whether the student existed: STUDENTS.pop(sid, None) then 204 тАФ that is idempotency in one line.

ЁЯзк Try it

K='X-API-Key: hall-pass-123'; B=http://127.0.0.1:8080/v1
curl -s "$B/students?limit=10"                       # the cabinet
curl -s $B/students/2                                # one drawer
curl -s $B/classes/3B/students                       # nested nouns
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE $B/students/5 -H "$K"   # 204
curl -s -o /dev/null -w '%{http_code}\n' -X DELETE $B/students/5 -H "$K"   # 204 again тАФ idempotent
curl -s -X PUT $B/students/4 -H "$K" -H 'Content-Type: application/json' -d '{"name":"Meera","class":"3B","grade":"A+"}'
curl -s -X PUT $B/students/4 -H "$K" -H 'Content-Type: application/json' -d '{"name":"Meera","class":"3B","grade":"A+"}'   # same answer

тЬЕ Verify тАФ what you should see

Two DELETEs print 204 twice; two identical PUTs return the identical JSON (and the same ETag if you add -i). GET /v1/classes/3B/students lists only 3B. Restart the server (Ctrl+C, run again) to get student 5 back тАФ the archive is in memory.

ЁЯПБ What you just proved

You can predict an endpoint's meaning from its noun and verb alone, and you have felt idempotency: repeating a safe slip changed nothing.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: idempotent verbs are what make retries, load-balancer failover and "at-least-once" queues safe. Every duplicate-order incident you have read about is a non-idempotent write retried by a well-meaning client.

тПня╕П Next

What goes on the slip? The standard form тАФ JSON, validation, and the printed catalogue (OpenAPI).

git checkout lesson-04-json-and-schemas
тЖР Previoushttp anatomyNext тЖТjson and schemas

This page is the lesson's README from the lesson-03-rest-resources branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.