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

ЁЯФв рдзрдбрд╛ 09 тАФ Versioning: рдЬреБрдиреЗ рдлреЙрд░реНрдо рди рдлреЗрдХрддрд╛ рдирд╡реЗ рдлреЙрд░реНрдо

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 09 ┬╖ рдорд╛рдЧреЗ: lesson-08-pagination-filtering ┬╖ рдкреБрдвреЗ: lesson-10-rate-limits-caching


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

рдзрдбреЗ 01тАУ08, рдЖрдгрд┐ рддреНрдпрд╛рд╕реЛрдмрдд рдЖрдзреАрдкрд╛рд╕реВрди forms рднрд░рдгрд╛рд▒реНрдпрд╛ apps рдирд╛ рди рдореЛрдбрддрд╛ counter рдХрд╕рд╛ рд╡рд┐рдХрд╕рд┐рдд рд╣реЛрддреЛ: additive рдмрджрд▓, рдореЛрдбрдгрд╛рд░реЗ рдмрджрд▓ (breaking changes), /v1 тЖТ /v2, рдЖрдгрд┐ рдПрдЦрд╛рджрд╛ form рдирд┐рд╡реГрддреНрдд рдХрд░рдгреНрдпрд╛рдЪреА рд╕рднреНрдп рдкрджреНрдзрдд.

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

рд╡реАрд╕ apps рд░реЛрдЬ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рдЪрд╛ form рднрд░рддрд╛рдд. рдПрдХрд╛ рд╕рдХрд╛рд│реА office рд▓рд╛ рдмрджрд▓ рд╣рд╡рд╛ рдЕрд╕рддреЛ. рдмрджрд▓ рджреЛрди рдкреНрд░рдХрд╛рд░рдЪреЗ рдЕрд╕рддрд╛рдд:

рдореНрд╣рдгреВрди office рдирд╡реАрди form /v2 рдореНрд╣рдгреВрди рдЫрд╛рдкрддреЗ рдЖрдгрд┐ рдХрд╛рд╣реА рдХрд╛рд│ /v1 рд╕реБрджреНрдзрд╛ рджреЗрдд рд░рд╛рд╣рддреЗ. рддреЗ рдирд┐рд╡реГрддреНрддреАрдЪреА рд╕рднреНрдпрдкрдгреЗ рдШреЛрд╖рдгрд╛ рдХрд░рддреЗ: рдкреНрд░рддреНрдпреЗрдХ v1 рдЙрддреНрддрд░рд╛рд╡рд░ Deprecation рд╕реВрдЪрдирд╛, рдПрдХ Sunset рддрд╛рд░реАрдЦ, рдПрдХ migration рдорд╛рд░реНрдЧрджрд░реНрд╢рдХ, рдЖрдгрд┐ рддреЗ counter рд╡рд░ рд▓рдХреНрд╖ рдареЗрд╡рддреЗ тАФ v1 рддреЗрд╡реНрд╣рд╛рдЪ рдХрд╛рдврд▓реЗ рдЬрд╛рддреЗ рдЬреЗрд╡реНрд╣рд╛ рдЖрдгрдЦреА v1 slips рдпреЗрдгреЗ рдмрдВрдж рд╣реЛрддреЗ.

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

flowchart LR
    v1["ЁЯФв /v1/students<br/>{id, name, class, grade}"]
    add["тЮХ additive: + house, + /homework<br/>same version, old apps fine"]
    brk["ЁЯТе breaking: class тЖТ section,<br/>grade тЖТ number"]
    v2["/v2/students<br/>new form, side by side"]
    sunset["ЁЯЧУя╕П Deprecation + Sunset headers on v1<br/>metrics per version тЖТ remove v1 when quiet"]
    v1 -->|"1 safe"| add
    v1 -->|"2 not safe"| brk --> v2
    v2 -.->|"3"| sunset

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

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг API рдореНрд╣рдгрдЬреЗ рдЕрд╢рд╛ code рд▓рд╛ рджрд┐рд▓реЗрд▓реЗ рд╡рдЪрди рдЬреЛ рддреБрдореНрд╣реА рдкрд╛рд╣реВ рдХрд┐рдВрд╡рд╛ update рдХрд░реВ рд╢рдХрдд рдирд╛рд╣реА. Version рд╢рд┐рд╡рд╛рдпрдЪрд╛ рдореЛрдбрдгрд╛рд░рд╛ рдмрджрд▓ рдореНрд╣рдгрдЬреЗ рдкреНрд░рддреНрдпреЗрдХ рд╡рд╛рдкрд░рдХрд░реНрддреНрдпрд╛рд╡рд░ рдПрдХрддреНрд░ рдХреЛрд╕рд│рдгрд╛рд░реЗ outage тАФ рдиреЗрдордХреА рддреАрдЪ рдЧреЛрд╖реНрдЯ рдЯрд╛рд│рдгреНрдпрд╛рд╕рд╛рдареА counter рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдЖрд▓рд╛ (рдзрдбрд╛ 01). Versioning рдореНрд╣рдгрдЬреЗ рдиреЛрдХрд░рд╢рд╛рд╣реА рдирд╛рд╣реА; рдкреБрдвреЗ рдЬрд╛рдд рдЕрд╕рддрд╛рдирд╛рд╣реА office рдЖрдкрд▓рд╛ рд╢рдмреНрдж рдХрд╕рд╛ рдкрд╛рд│рддреЗ рддреЗ рд╣реЗ рдЖрд╣реЗ.

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

рдкреНрд░рддреНрдпреЗрдХ path /v1/ рдиреЗ рд╕реБрд░реВ рд╣реЛрддреЛ (school_api.py рдордзрд▓реЗ VERSION) рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ response рд╡рд░ X-API-Version: v1 рдЕрд╕рддреЗ. STUDENTS рдордзреНрдпреЗ рдЖрдгрд┐ openapi.yaml рдордзрд▓реНрдпрд╛ Student рдордзреНрдпреЗ field рдЬреЛрдбрдгреЗ additive рдЖрд╣реЗ; class рдЪреЗ рдирд╛рд╡ рдмрджрд▓рдгреЗ рд╣реЗ рддреБрдордЪреЗ рдкрд╣рд┐рд▓реЗ /v2 рдард░реЗрд▓.

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

# 1) additive: add "house": "red" to every student in STUDENTS and to the Student schema. Restart.
curl -s http://127.0.0.1:8080/v1/students/2            # old clients still parse this тАФ they ignore "house"
# 2) breaking, done right тАФ on paper (5 minutes):
#    write the /v2 form with "section" instead of "class", the Deprecation + Sunset headers you would add to v1,
#    and the one-paragraph migration note. Then decide the date you would remove v1 тАФ and what metric tells you it is safe.
# 3) look at the version stamp:
curl -si http://127.0.0.1:8080/v1/health | grep -i x-api-version

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

рдкрд╛рдпрд░реА 1 рдирдВрддрд░ smoke test рдЕрдЬреВрдирд╣реА рд╕реБрд░реБрд╡рд╛рддреАрдкрд╛рд╕реВрди рд╢реЗрд╡рдЯрдкрд░реНрдпрдВрдд pass рд╣реЛрддреЛ (рддреЛ рддрдкрд╛рд╕рдд рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдХрд╢рд╛рдЪреЗрд╣реА рдирд╛рд╡ рдмрджрд▓рд▓реЗ рдирд╛рд╣реА) рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рдд house рджрд┐рд╕рддреЗ. рдкрд╛рдпрд░реА 3 рдкреНрд░рддреНрдпреЗрдХ рдЙрддреНрддрд░рд╛рд╡рд░ X-API-Version: v1 рдЫрд╛рдкрддреЗ. рддреБрдордЪреНрдпрд╛ рдкрд╛рдпрд░реА-2 рдЪреНрдпрд╛ рдЯрд┐рдкрдгрд╛рдд рдПрдХ field, рдПрдХ header, рдПрдХ рддрд╛рд░реАрдЦ рдЖрдгрд┐ рдПрдХ metric рдЕрд╕рддреЗ.

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

рддреБрдореНрд╣реА additive рдмрджрд▓ рдЖрдгрд┐ рдореЛрдбрдгрд╛рд░рд╛ рдмрджрд▓ рдпрд╛рдВрддрд▓рд╛ рдлрд░рдХ рдУрд│рдЦреВ рд╢рдХрддрд╛, рдкрд╣рд┐рд▓рд╛ рддреНрдпрд╛рдЪ version рд╡рд░ ship рдХрд░реВ рд╢рдХрддрд╛, рдЖрдгрд┐ рджреБрд╕рд▒реНрдпрд╛рдЪреЗ рдирд┐рдпреЛрдЬрди рдХреЛрдгрд╛рд▓рд╛рд╣реА рди рдореЛрдбрддрд╛ рдХрд░реВ рд╢рдХрддрд╛.

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

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рд▓реЛрдХрд╛рдВрдирд╛ рдЖрд╡рдбрдгрд╛рд░реЗ APIs (Stripe, GitHub) рдкреНрд░рдХрд╛рд╢рд┐рдд sunset рддрд╛рд░рдЦрд╛рдВрд╕рд╣ рд╡рд░реНрд╖рд╛рдиреБрд╡рд░реНрд╖реЗ рдЬреБрдиреЗ versions рдЪрд╛рд▓рд╡рдд рдЖрд▓реЗ рдЖрд╣реЗрдд. рд▓реЛрдХ рдЬреНрдпрд╛рдВрдирд╛ рд╕реЛрдбреВрди рдЬрд╛рддрд╛рдд рддреНрдпрд╛рдВрдиреА рдПрдЦрд╛рджреНрдпрд╛ рдордВрдЧрд│рд╡рд╛рд░реА рдПрдХ field рдореЛрдбрд▓реЗрд▓реЗ рдЕрд╕рддреЗ.

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

рднрд╛рд░рд╛рдЦрд╛рд▓рдЪрд╛ counter: rate limits, caching, timeouts рдЖрдгрд┐ backoff тАФ рд░рд╛рдВрдЧ, рдкреНрд░рдд, рдЖрдгрд┐ рд╕рднреНрдп client.

git checkout lesson-10-rate-limits-caching

ЁЯФв Lesson 09 тАФ Versioning: new forms without throwing the old ones away

ЁЯУН You are here: Lesson 09 of 12 ┬╖ Previous: lesson-08-pagination-filtering ┬╖ Next: lesson-10-rate-limits-caching


ЁЯУж What's in this branch

Lessons 01тАУ08, plus how a counter evolves without breaking the apps that already fill in its forms: additive changes, breaking changes, /v1 тЖТ /v2, and the polite way to retire a form.

ЁЯзТ Explain like I'm 5

Twenty apps fill in the student form every day. One morning the office wants a change. There are two kinds:

So the office prints the new form as /v2 and keeps handing out /v1 for a while. It announces the retirement politely: a Deprecation note on every v1 answer, a Sunset date, a migration guide, and it watches the counter тАФ v1 is removed only when no more v1 slips arrive.

ЁЯЧ║я╕П Diagram

flowchart LR
    v1["ЁЯФв /v1/students<br/>{id, name, class, grade}"]
    add["тЮХ additive: + house, + /homework<br/>same version, old apps fine"]
    brk["ЁЯТе breaking: class тЖТ section,<br/>grade тЖТ number"]
    v2["/v2/students<br/>new form, side by side"]
    sunset["ЁЯЧУя╕П Deprecation + Sunset headers on v1<br/>metrics per version тЖТ remove v1 when quiet"]
    v1 -->|"1 safe"| add
    v1 -->|"2 not safe"| brk --> v2
    v2 -.->|"3"| sunset

тЭУ What

ЁЯдФ Why

Because an API is a promise to code you cannot see or update. A breaking change without a version is a coordinated outage across every consumer тАФ the very thing the counter existed to prevent (lesson 01). Versioning is not bureaucracy; it is how the office keeps its word while still moving.

ЁЯФз How (in this repo)

Every path starts with /v1/ (VERSION in school_api.py) and every response carries X-API-Version: v1. Adding a field to STUDENTS and Student in openapi.yaml is additive; renaming class would be your first /v2.

ЁЯзк Try it

# 1) additive: add "house": "red" to every student in STUDENTS and to the Student schema. Restart.
curl -s http://127.0.0.1:8080/v1/students/2            # old clients still parse this тАФ they ignore "house"
# 2) breaking, done right тАФ on paper (5 minutes):
#    write the /v2 form with "section" instead of "class", the Deprecation + Sunset headers you would add to v1,
#    and the one-paragraph migration note. Then decide the date you would remove v1 тАФ and what metric tells you it is safe.
# 3) look at the version stamp:
curl -si http://127.0.0.1:8080/v1/health | grep -i x-api-version

тЬЕ Verify тАФ what you should see

After step 1 the smoke test still passes end to end (nothing it checks was renamed) and house appears in every student. Step 3 prints X-API-Version: v1 on every answer. Your step-2 note names a field, a header, a date and a metric.

ЁЯПБ What you just proved

You can tell an additive change from a breaking one, ship the first on the same version, and plan the second without breaking anyone.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: the APIs people love (Stripe, GitHub) have run old versions for years with published sunset dates. The ones people leave broke a field on a Tuesday.

тПня╕П Next

The counter under load: rate limits, caching, timeouts and backoff тАФ the queue, the copy, and the polite client.

git checkout lesson-10-rate-limits-caching
тЖР Previouspagination filteringNext тЖТrate limits caching

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