ЁЯЧДя╕П рдзрдбрд╛ 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 рддреНрдпрд╛рдВрдирд╛ рддрд╢реАрдЪ рдирд╛рд╡реЗ рджреЗрддрд╛рдд:
/v1/studentsтАФ рд╕рдВрдкреВрд░реНрдг рдХрдкрд╛рдЯ (рдПрдХ collection).GETрддреНрдпрд╛рдЪреА рдпрд╛рджреА рджреЗрддреЗ;POSTрдирд╡реАрди drawer рдЬреЛрдбрддреЗ./v1/students/2тАФ рдПрдХ drawer (рдПрдХ resource).GETрддреЛ рд╡рд╛рдЪрддреЗ,PUTрддреНрдпрд╛рддрд▓рд╛ рдордЬрдХреВрд░ рдкреВрд░реНрдг рдмрджрд▓рддреЗ,DELETEрддреЛ рдХрд╛рдвреВрди рдЯрд╛рдХрддреЗ./v1/classes/3A/studentsтАФ рдХрдкрд╛рдЯреЗ рдПрдХрдореЗрдХрд╛рдВрдд рдЕрд╕реВ рд╢рдХрддрд╛рдд: рдПрдХрд╛ рд╡рд░реНрдЧрд╛рдЪреЗ рд╡рд┐рджреНрдпрд╛рд░реНрдереА.
рд╣реЗ рдЕрдВрджрд╛рдЬ рдХрд░рдгреНрдпрд╛рдЬреЛрдЧреЗ рдмрдирд╡рдгрд╛рд░рд╛ рдирд┐рдпрдо: URLs рдореНрд╣рдгрдЬреЗ рдирд╛рдореЗ, methods рдореНрд╣рдгрдЬреЗ рдХреНрд░рд┐рдпрд╛рдкрджреЗ.
рдХрдзреАрдЪ /getStudent?id=2 рдХрд┐рдВрд╡рд╛ /deleteStudent/2 рдирд╛рд╣реА тАФ рдХреНрд░рд┐рдпрд╛рдкрдж рдЖрдзреАрдЪ
method рдордзреНрдпреЗ рдЖрд╣реЗ. рд▓реЛрдХ REST рдореНрд╣рдгрддрд╛рдд рддреЗрд╡реНрд╣рд╛ рддреНрдпрд╛рдВрдирд╛ рд╣реЗрдЪ рдореНрд╣рдгрд╛рдпрдЪреЗ рдЕрд╕рддреЗ.
рдЖрдгрд┐ clerk рд▓рд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреА рд╡рд╛рдЯрдгрд╛рд░реА рдЖрдгрдЦреА рдПрдХ рдЧреЛрд╖реНрдЯ: рд╣реА slip рджреЛрдирджрд╛ рджреЗрдгреЗ рд╕реБрд░рдХреНрд╖рд┐рдд рдЖрд╣реЗ рдХрд╛?
GETтАФ safe: рд╡рд╛рдЪрд▓реНрдпрд╛рдиреЗ рдХрд╛рд╣реАрдЪ рдмрджрд▓рдд рдирд╛рд╣реА.PUTрдЖрдгрд┐DELETEтАФ idempotent: рджреЛрдирджрд╛ рдХреЗрд▓реЗ рддрд░реА рдирд┐рдХрд╛рд▓ рдПрдХрджрд╛ рдХреЗрд▓реНрдпрд╛рд╕рд╛рд░рдЦрд╛рдЪ (рджреЛрдирджрд╛ рдмрджрд▓рд▓реЗ = рдмрджрд▓рд▓реЗ; рджреЛрдирджрд╛ рдХрд╛рдврд▓реЗ = рддрд░реАрд╣реА рдЧреЗрд▓реЗрд▓реЗ, рджреЛрдиреНрд╣реА рд╡реЗрд│рд╛204).POSTтАФ рд╕реНрд╡рддрдГрд╣реВрди idempotent рдирд╛рд╣реА: "Zoya рд▓рд╛ рдЬреЛрдбрд╛" рдЕрд╢рд╛ рджреЛрди slips рдореБрд│реЗ рджреЛрди Zoya рдиреЛрдВрджрд▓реНрдпрд╛ рдЬрд╛рдК рд╢рдХрддрд╛рдд. рдзрдбрд╛ 07 рдкрд╛рд╡рддреА рдХреНрд░рдорд╛рдВрдХрд╛рдиреЗ рд╣реЗ рджреБрд░реБрд╕реНрдд рдХрд░рддреЛ.
ЁЯЧ║я╕П рдЖрдХреГрддреА
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
тЭУ рдХрд╛рдп
- Resource: рдУрд│рдЦ рдЖрдгрд┐ URL рдЕрд╕рд▓реЗрд▓реА рдПрдХ рдЧреЛрд╖реНрдЯ. Collection: рдкрд╛рд▓рдХ URL рд╡рд░рдЪрд╛ рддреНрдпрд╛рдВрдЪрд╛ рд╕рдВрдЪ. Ids clients рд╕рд╛рдареА рдЕрдкрд╛рд░рджрд░реНрд╢рдХ рдЕрд╕рддрд╛рдд тАФ рддреЗ рдХреНрд░рдорд╛рдиреЗ рдЖрд╣реЗрдд рдЕрд╕реЗ рдХрдзреАрдЪ рдЧреГрд╣реАрдд рдзрд░реВ рдирдХрд╛ (рдЖрдордЪреЗ рдЖрд╣реЗрдд, рдкрдг рдлрдХреНрдд рд╡рд╛рдЪрд╛рдпрд▓рд╛ рд╕реЛрдкреЗ рдЬрд╛рд╡реЗ рдореНрд╣рдгреВрди).
- рдХреНрд░рд┐рдпрд╛рдкрджрд╛рдВрдЪрд╛ рдЕрд░реНрде (counter рдХрд╛рдп рд╡рдЪрди рджреЗрддреЛ):
GETрд╡рд╛рдЪрддреЗ;POSTрддрдпрд╛рд░ рдХрд░рддреЗ (рдЙрддреНрддрд░201+Location);PUTрдкреВрд░реНрдг drawer рдмрджрд▓рддреЗ;PATCHрддреНрдпрд╛рдЪрд╛ рдХрд╛рд╣реА рднрд╛рдЧ рдмрджрд▓рддреЗ (рдЖрдореНрд╣реА PATCH рд╡рдЧрд│рддреЛ тАФ рдХрд▓реНрдкрдирд╛ рддреАрдЪ);DELETEрдХрд╛рдврддреЗ (рдЙрддреНрддрд░204, рдЖрдгрд┐ рдЖрдзреАрдЪ рдЧреЗрд▓реЗрд▓реЗ рдЕрд╕реЗрд▓ рддрд░реА рдкреБрдиреНрд╣рд╛204). - Idempotent = N рдПрдХрд╕рд╛рд░рдЦреНрдпрд╛ calls рдирдВрддрд░рдЪрд╛ рдирд┐рдХрд╛рд▓ рдПрдХрд╛ call рдирдВрддрд░рдЪреНрдпрд╛ рдирд┐рдХрд╛рд▓рд╛рдЗрддрдХрд╛рдЪ. рдпрд╛рдореБрд│реЗрдЪ client рддреБрдЯрд▓реЗрд▓реНрдпрд╛ connection рдирдВрддрд░ рди рдШрд╛рдмрд░рддрд╛ retry рдХрд░реВ рд╢рдХрддреЛ.
- Nesting "рдХрд╢рд╛рдЪреЗ?" рдпрд╛рдЪреЗ рдЙрддреНрддрд░ рджреЗрддреЗ тАФ
/classes/3A/studentsтАФ рдкрдг рджреЛрди рдкрд╛рддрд│реНрдпрд╛ рд╕рд╣рд╕рд╛ рдкреБрд░реЗрд╢рд╛ рдЕрд╕рддрд╛рдд; рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЦреЛрд▓ рдЭрд╛рдбрд╛рдВрдРрд╡рдЬреА filters рд╡рд╛рдкрд░рддрд╛рдд (/students?class=3A, рдзрдбрд╛ 08).
ЁЯФз 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 рдкреБрдиреНрд╣рд╛ рджрд┐рд▓реНрдпрд╛рдиреЗ рдХрд╛рд╣реАрдЪ рдмрджрд▓рд▓реЗ рдирд╛рд╣реА.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- URLs рдордзреНрдпреЗ рдХреНрд░рд┐рдпрд╛рдкрджреЗ (
/createStudent) тАФ method рд╣реЗрдЪ рдХреНрд░рд┐рдпрд╛рдкрдж рдЖрд╣реЗ - рд╕реНрдерд┐рддреА рдмрджрд▓рдгрд╛рд░рд╛
GET(/students/2/delete) тАФ crawlers рдЖрдгрд┐ prefetchers рддреНрдпрд╛рд╡рд░ "click" рдХрд░рддреАрд▓ - рджреБрд╕рд▒реНрдпрд╛
DELETEрд╡рд░404рдкрд░рдд рдХрд░рдгреЗ тАФ рдпрд╛рдореБрд│реЗ retries рд╡рд┐рдирд╛рдХрд╛рд░рдг рдЕрдпрд╢рд╕реНрд╡реА рд╣реЛрддрд╛рдд; рджреЛрдирджрд╛204рд╣реЗрдЪ рдмрд░реЛрдмрд░ - рдЦреЛрд▓ nesting (
/schools/1/classes/3A/students/2/grades/3) тАФ рджреЛрди рдкрд╛рддрд│реНрдпрд╛рдВрдирдВрддрд░ filters рд╡рд╛рдкрд░рд╛
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: 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