Gesaan dan masa ia terpakai
Satu API REST Pesanan awam telah pun digunakan oleh 600 integrasi pihak ketiga dan beberapa aplikasi mudah alih yang tidak boleh dipaksa untuk menaik taraf. GET /v1/orders sedia ada mengembalikan setiap pesanan dalam satu respons. Setiap pesanan mengandungi satu rentetan customer_name, dan status pada masa ini hanya mengembalikan pending atau paid. Keluaran seterusnya harus mendedahkan data pelanggan sebagai objek berstruktur, menomborkan halaman senarai tersebut, dan memperkenalkan status refunded.
600 integrasi, medan semasa, dan nilai status adalah andaian temu duga. Kekangan yang mengikat ialah penyedia tidak dapat mengawal bila setiap pengguna menaik taraf. Kejayaan merangkumi v2 yang berfungsi, tingkah laku v1 yang berterusan di bawah kontrak asal, migrasi yang boleh diperhatikan, tarikh penamatan yang boleh ditemui, dan pemulihan daripada keluaran yang gagal tanpa mengubah makna versi yang dijanjikan.
Ini adalah soalan backend kerana ia menguji kontrak API, perwakilan sisi pelayan, kejuruteraan keluaran, dan tadbir urus keserasian. Ia tidak memerlukan reka bentuk untuk keseluruhan sistem pesanan atau pelan sharding pangkalan data (database sharding). Tulis kontrak sedia ada sebelum mengklasifikasikan setiap perubahan. Hanya berkata "letakkan v2 dalam URL" tidak membuktikan bahawa klien lama kekal selamat.
{
"orders": [
{
"id": "ord_1",
"customer_name": "Ada Lovelace",
"status": "paid"
}
]
}Perkara yang dinilai oleh penemu duga
Isyarat pertama ialah sama ada calon membezakan tiga jenis keserasian. Keserasian sumber (source compatibility) mempersoalkan sama ada kod klien lama masih boleh dikompilasi selepas menjana semula atau menaik taraf SDK-nya. Keserasian wayar (wire compatibility) mempersoalkan sama ada penyiri (serializer) lama boleh menghuraikan mesej baharu. Keserasian semantik (semantic compatibility) mempersoalkan sama ada panggilan yang sama masih berkelakuan seperti yang dijangkakan oleh pengguna yang munasabah. Jenis medan yang tidak berubah tidak mengekalkan semantik dengan sendirinya. Mengubah secara senyap "kembalikan setiap pesanan" kepada "kembalikan 100 pesanan pertama" masih menghasilkan JSON yang sah, tetapi klien lama kehilangan data.
Isyarat kedua ialah pertimbangan berasaskan kontrak. Jadual universal yang dihafal tidak dapat mewakili tingkah laku penghuraian setiap klien sebenar. Medan permintaan pilihan baharu yang mana peninggalannya mengekalkan tingkah laku lama biasanya boleh kekal dalam v1. Mengalih keluar, menamakan semula, atau menukar jenis medan akan merosakkan v1. Medan respons tambahan adalah penambahan yang selamat hanya jika kontrak membenarkan medan yang tidak diketahui dan SDK sebenar mengabaikannya. Menambah nilai enum respons wajar diteliti lebih mendalam: kontrak open-enum boleh membenarkan peluasan, manakala closed enum, SDK ditaip kuat yang dijana, atau switch menyeluruh tanpa cawangan lalai boleh gagal.
Isyarat ketiga ialah laluan boleh laksana yang menghubungkan versi, pelaksanaan, dan kitaran hayat. Jawapan yang kukuh mengekalkan lapisan persembahan v1, menggunakan logik domain kongsi untuk menghasilkan respons v1 dan v2 yang berasingan, menjalankan ujian perbezaan kontrak dan SDK lama sebelum keluaran, mengukur penerimaan, ralat, dan kependaman mengikut pengguna selepas itu, dan akhirnya menamatkan versi lama dengan isyarat penamatan standard, panduan migrasi, dan get penutupan eksplisit. Pengenal pasti versi ialah pilihan penghalaan; ia tidak melakukan mana-mana tugasan tersebut secara automatik.
Soalan untuk dijelaskan sebelum menjawab
- Adakah pengguna boleh dikawal? Tiga perkhidmatan di dalam satu syarikat yang boleh menyelaraskan pelancaran atomik boleh menggunakan
kembangkan–hijrah–kecutkan (expand–migrate–contract) tanpa v2 yang berjangka hayat panjang. Pihak ketiga dan klien mudah alih lama memerlukan sempadan versi yang stabil dan kitaran hayat awam.
- Adakah kontrak semasa memerlukan klien untuk mengabaikan medan dan nilai enum yang tidak diketahui? Ini menentukan sama ada
medan respons atau nilai enum yang ditambah boleh kekal dalam v1. JSON yang sah sahaja tidak mencukupi; periksa kontrak OpenAPI, jenis SDK, dan tingkah laku pengguna sebenar.
- Berapa besarkah senarai tersebut, dan apakah risiko kebolehpercayaan yang diciptanya? Jika mengembalikan semua pesanan masih memenuhi SLO,
penomboran halaman hanya boleh wujud dalam v2. Jika respons tanpa had telah mengancam ketersediaan, had kadar dan laluan komunikasi kecemasan mungkin diperlukan, tetapi pemotongan senyap masih bukan perubahan yang serasi.
- Adakah API telah menerbitkan mekanisme pemilihan versi? Teruskan menggunakan
/v1dan/v2apabila versi
laluan telah wujud, atau kekalkan pengepala tarikh sedia ada apabila versi berasaskan pengepala. Menukar mekanisme semasa migrasi mencipta satu lagi perubahan klien.
- Bolehkah penyedia mengenal pasti setiap pengguna dan menghubungi pemiliknya? ID aplikasi yang stabil, versi SDK, dan hubungan
pemilik membolehkan penjejakan migrasi yang tepat. Trafik tanpa nama memerlukan get penamatan yang lebih konservatif.
- Apakah tempoh sokongan undang-undang, kontrak, atau perniagaan yang telah dijanjikan? Tarikh penutupan datang daripada dasar yang
diterbitkan, kewajipan pelanggan, risiko, dan penerimaan sebenar. Tempoh sokongan platform lain bukanlah peraturan sejagat.
Kerangka respons 30 saat
"Saya akan terlebih dahulu membekukan kontrak bertulis v1 dan tingkah laku yang boleh diperhatikan, kemudian mengklasifikasikan setiap cadangan merentasi keserasian sumber, wayar, dan semantik. Medan pilihan baharu dengan tingkah laku lalai yang tidak berubah mungkin muat dalam v1. Menggantikan rentetan dengan objek, menamakan semula medan, dan menukar senarai semua-hasil kepada penomboran halaman memerlukan v2. Nilai enum respons baharu bergantung pada dasar open-enum dan tingkah laku SDK lama. Saya akan berkongsi logik domain Pesanan dan hanya mengekalkan penyesuai persembahan v1 dan v2. Sebelum keluaran, saya akan menjalankan OpenAPI diff, ujian SDK lama, memainkan semula permintaan yang direkodkan, dan ujian kontrak hujung-ke-hujung, kemudian membiarkan pengguna yang diketahui memilih masuk ke v2. Saya akan memantau penerimaan dan ralat mengikut pengguna, menerbitkan tarikh migrasi, penamatan, dan penutupan, serta menghentikan v1 hanya selepas get migrasi dan kewajipannya lulus. Pada mana-mana titik kegagalan, saya boleh mengundurkan laluan atau penyesuai v2 sementara v1 kekal tidak berubah."
Selaman mendalam langkah demi langkah
Mulakan dengan membina garis dasar keserasian. Kekalkan dokumen OpenAPI semasa, SDK yang dikeluarkan, permintaan dan respons representatif, kod ralat, susunan, lalai, dan tingkah laku senarai. Sampelkan juga tingkah laku yang tidak didokumentasikan tetapi kelihatan, kerana pengguna mungkin bergantung pada format medan, pengendalian null, susunan, atau mendapatkan set hasil penuh dalam satu respons. Rekod ID pengguna, versi, volum permintaan, dan pemilik pada masa yang sama. Kemudian, ini memisahkan "tidak digunakan" daripada "digunakan oleh seseorang yang tidak dapat dikenal pasti oleh penyedia."
Kemudian kelaskan setiap perubahan yang dicadangkan:
| Perubahan yang dicadangkan | Penilaian v1 | Rawatan |
|---|---|---|
| Tambah medan permintaan pilihan yang mana peninggalannya mengekalkan tingkah laku lama | Biasanya serasi | Tambah ke v1 dan uji permintaan lama |
| Tambah medan respons pilihan | Serasi secara bersyarat | Sahkan dasar medan tidak diketahui dan SDK lama terlebih dahulu |
Gantikan customer_name dengan objek customer | Tidak serasi | Kekalkan rentetan dalam v1; kembalikan objek dalam v2 |
| Alih keluar atau namakan semula medan sedia ada | Tidak serasi | Tambah nama baharu dalam versi baharu; jangan alih keluar daripada v1 |
| Tukar senarai semua-hasil kepada penomboran halaman secara lalai | Tidak serasi secara semantik | Tentukan semantik kursor dan halaman dalam v2 |
Tambah refunded pada enum respons | Bergantung pada kontrak enum | Periksa peraturan open-enum, kod yang dijana, dan switch menyeluruh |
| Betulkan ejaan tidak didokumentasikan yang tidak boleh menjejaskan kebergantungan munasabah | Masih memerlukan bukti | Buktikan dengan ujian pengguna dan main semula trafik |
Penomboran halaman adalah kes yang mudah dipandang rendah. Panduan keserasian Google menekankan risiko menambah page_size lalai yang terhad kepada API yang sebelum ini mengembalikan setiap item: klien lama boleh salah menganggap bahawa respons pertama adalah lengkap. Tentukan items, next_page_token, susunan, dan peraturan ketidaksahan token dalam v2. Semasa tempoh sokongan, v1 mengekalkan semantik asalnya manakala kuota, pemantauan saiz respons, dan jangkauan migrasi mengawal risiko operasi.
Seterusnya, lukis sempadan versi. Gesaan tersebut telah menggunakan penversian laluan, jadi tambahkan /v2/orders. Jangan teka versi daripada User-Agent pada laluan yang sama, dan jangan halakan v1 secara senyap kepada perwakilan dengan semantik baharu. Versikan hanya perwakilan luaran. Huraikan setiap permintaan ke dalam arahan domain yang sama, kongsi logik pertanyaan pesanan dan pengesahan, kemudian gunakan V1OrderPresenter atau V2OrderPresenter untuk menghasilkan bentuk yang sepadan. Pembaikan keselamatan dan peraturan perniagaan masih boleh mencapai kedua-dua versi tanpa menduplikasi perkhidmatan.
Respons v2 ilustratif ialah:
{
"orders": [
{
"id": "ord_1",
"customer": {
"display_name": "Ada Lovelace"
},
"status": "paid"
}
],
"next_page_token": "eyJvcmRlcl9pZCI6Im9yZF8xIn0"
}Gunakan empat get keluaran. Pertama, bandingkan takrif OpenAPI lama dan baharu serta tolak penyingkiran medan v1, perubahan keperluan (requiredness), perubahan jenis, dan peraturan pengesahan baharu yang tidak disengajakan. Kedua, kompilasi dan jalankan kes kontrak tetap dengan SDK v1 awam terakhir, termasuk medan tidak diketahui, null, respons ralat, dan enum. Ketiga, mainkan semula permintaan disanitasi yang representatif dan bandingkan kod status, medan kritikal, dan susunan antara pelaksanaan v1 lama dan baharu. Keempat, biarkan sekumpulan kecil pengguna yang diketahui memilih masuk ke v2 dalam persekitaran sandbox atau kenari dan perhatikan kefungsian, 4xx, 5xx, kependaman, dan saiz respons. Perbezaan skema boleh menemui perubahan struktur; ia tidak boleh menggantikan penegasan semantik tentang susunan, lalai, atau kelengkapan halaman.
Migrasi bermula sebagai pilihan masuk (opt-in). Terbitkan dokumentasi v2, SDK, jadual migrasi medan demi medan, dan sandbox yang menyokong kedua-dua versi. Tunjukkan kepada setiap pengguna yang diketahui tentang volum panggilan v1 mereka, titik akhir yang gagal, dan tarikh sasaran. Hijrahkan contoh penyedia dan SDK rasmi terlebih dahulu supaya jurang dalam panduan muncul awal. Semak penerimaan mengikut pengguna dan periksa permintaan agregat secara berasingan: integrasi penyesuaian akhir bulan bervolum rendah boleh menjadi lebih penting daripada banyak semakan kesihatan. Jejak pengguna aktif unik bagi setiap versi, volum permintaan, 4xx, 5xx, kependaman p95, penyelesaian penomboran halaman, kegagalan penghuraian SDK lama, dan akaun berisiko tinggi yang telah dihubungi tetapi belum berhijrah.
Pisahkan tiga detik kitaran hayat: menerbitkan dasar migrasi, menamatkan API secara rasmi, dan menghentikannya daripada merespons. RFC 9745 mentakrifkan pengepala respons Deprecation untuk tarikh penamatan dan hubungan pautan deprecation untuk maklumat sokongan. Tambah Sunset hanya apabila penyedia merancang untuk sumber tersebut berhenti merespons. Penamatan itu sendiri tidak seharusnya mengubah tingkah laku sumber. Tarikh-tarikh ini adalah contoh temu duga; tarikh sebenar mesti mengikut dasar yang diterbitkan:
Deprecation: @1803859200
Sunset: Wed, 01 Sep 2027 00:00:00 GMT
Link: <https://api.example.com/migrations/orders-v2>; rel="deprecation"; type="text/html"Sebelum menamatkan v1, wajibkan semua yang berikut: kewajipan sokongan dipenuhi; pengguna kritikal yang diketahui telah berhijrah atau menerima pengecualian yang diluluskan; baki trafik dijelaskan; panduan migrasi dan saluran sokongan berfungsi; get ralat, kependaman, dan hasil perniagaan v2 lulus; dan latihan penutupan boleh diundurkan. Jika pelanggan bernilai tinggi masih disekat, lanjutkan sokongan, sediakan get laluan keserasian yang dikekang, atau ikut kontrak. Jangan abaikan pelanggan tersebut semata-mata untuk memaparkan 100% penerimaan.
Tentukan pengunduran (rollback) sebelum keluaran. Laluan v2 dan penyesuai persembahan boleh dinyahdayakan secara bebas, penulisan domain kekal serasi ke belakang, dan v1 mengekalkan artifak terakhirnya yang disahkan. Jika medan v2 memerlukan storan baharu, kembangkan dan isi kembali (backfill) storan tersebut sebelum v2 membacanya; jangan padamkan data yang diperlukan oleh v1 dalam keluaran v2. Mengundurkan v2 bermakna memulihkan pelaksanaannya. Mengubah maksud "v2" untuk menyembunyikan insiden tersebut akan melanggar kontrak sekali lagi.
Contoh jawapan berkualiti tinggi
"Saya akan memisahkan perubahan kontrak daripada kitaran hayat keluaran. Klien-klien ini tidak boleh dipaksa untuk menaik taraf, jadi saya perlu mengekalkan penghuraian JSON, pelaksanaan SDK lama, dan hasil yang lengkap dengan makna yang sama untuk permintaan yang sama.
Mengubah customer_name daripada rentetan kepada objek mengubah jenisnya, dan menamakannya semula ialah operasi buang-tambah, jadi kedua-duanya tergolong dalam v2. Menomborkan halaman GET /orders secara lalai akan menyebabkan klien lama terlepas hasil, yang merupakan pemutusan semantik dan juga tergolong dalam v2. Saya tidak akan menganggap bahawa menambah refunded adalah selamat. Jika enum respons didokumentasikan sebagai terbuka dan SDK lama mengekalkan nilai yang tidak diketahui, v1 boleh berkembang. Jika kod yang dijana menggunakan closed enum atau pengguna menukar secara menyeluruh padanya, saya akan mengekalkan nilai baharu dalam v2 atau terlebih dahulu mewujudkan dan menguji laluan nilai tidak diketahui yang selamat.
Saya akan mengekalkan respons dan semantik semua-hasil /v1/orders, kemudian mencipta /v2/orders dengan objek pelanggan, kursor, dan peraturan halaman yang berstruktur. Kedua-dua versi berkongsi logik pertanyaan, pengesahan, dan status pesanan; hanya penghuraian permintaan dan persembahan respons yang berbeza. Sebelum penggabungan (merge), saya akan membandingkan takrif OpenAPI, menjalankan ujian kontrak melalui SDK v1 yang terakhir, dan memainkan semula permintaan yang disanitasi untuk menyemak kod status, susunan, lalai, dan kelengkapan. SDK dalaman dan sekumpulan kecil integrasi yang diketahui memilih masuk ke v2 terlebih dahulu. Regresi akan menyahdayakan laluan v2 sementara v1 berterusan tanpa perubahan.
Semasa migrasi, saya akan mengukur pengguna aktif mengikut ID aplikasi, menggunakan jumlah trafik sebagai isyarat sokongan, dan menjejaki penerimaan versi, kegagalan penghuraian, 4xx, 5xx, kependaman, penyelesaian penomboran halaman, dan akaun kritikal. Panduan tersebut merangkumi pemetaan medan, gelung penomboran halaman, sandaran enum, dan persekitaran ujian. Penamatan rasmi boleh ditemui melalui pengepala respons dan pautan migrasi; penutupan mempunyai tarikh yang diisytiharkan secara berasingan. Saya menamatkan v1 hanya selepas kewajipan sokongan, pengguna kritikal, baki trafik, dan SLO v2 semuanya melepasi get mereka, dan selepas latihan yang boleh diundurkan. Ini menjadikan pengenal pasti versi, pelaksanaan yang serasi, bukti migrasi, dan penamatan sebagai satu pelan yang boleh diuji."
Kesilapan lazim
- Hanya menjawab "letakkan
/v2dalam URL" → Ia tidak mengenal pasti siapa yang terjejas mahupun get migrasi dan penutupan →
Garis dasarkan v1, kemudian kelaskan setiap perubahan merentasi keserasian sumber, wayar, dan semantik.
- Menganggap setiap penambahan respons adalah serasi → Nyahsiri (deserializer) yang ketat, closed enum, dan switch menyeluruh masih
boleh gagal → Periksa kontrak awam dan SDK yang dijana, kemudian jalankan ujian versi lama yang sebenar.
- Mengarahkan v1 ke v2 secara automatik → Satu pengenal pasti versi mula mewakili dua semantik, jadi klien tidak boleh
memilih atau mengundur balik → Kekalkan perwakilan v1 yang stabil dan perlukan pemilihan v2 yang eksplisit.
- Menyalin keseluruhan perkhidmatan untuk v1 dan v2 → Pembetulan keselamatan dan peraturan perniagaan terpesong sementara kos dwi-versi meningkat →
Kongsi logik domain dan asingkan hanya penghuraian dan persembahan yang benar-benar berbeza.
- Mematikan v1 apabila tarikh yang diumumkan tiba → Panggilan ekor panjang tanpa nama, penyesuaian frekuensi rendah, dan
pelanggan kritikal mungkin masih bergantung padanya → **Sahkan penerimaan mengikut pengguna, kewajipan, dan baki trafik, kemudian latih pemulihan.**
- Hanya memerhatikan kadar 2xx sisi pelayan → Klien boleh menerima respons tetapi gagal menghuraikannya, meninggalkan halaman, atau
salah mentafsir status baharu → Tambah hasil SDK lama, penyelesaian penomboran halaman, hasil hujung-ke-hujung, dan isyarat sokongan.
Soalan susulan dan respons
Susulan 1: Adakah tiga pengguna dalaman yang dimiliki oleh syarikat yang sama memerlukan v2?
Tidak semestinya. Jika setiap pemanggil boleh dikenal pasti, keluaran boleh diselaraskan, dan pengunduran adalah pantas, gunakan kembangkan–hijrah–kecutkan: tambah medan atau titik akhir yang serasi, keluarkan pengguna yang boleh membaca kedua-dua bentuk, tukar pengeluar, kemudian alih keluar kontrak lama selepas penggunaan yang diukur mencapai sifar. Ujian kontrak dan bukti penggunaan berversi masih penting, tetapi pengguna yang boleh dikawal tidak memerlukan v2 awam yang kekal. Satu tugas luar talian yang tidak diselaraskan, klien lama, atau rakan kongsi luaran akan membatalkan andaian tersebut.
Susulan 2: Patutkah peristiwa webhook mengikut versi API semasa akaun?
Jangan tafsirkan semula peristiwa sejarah dengan versi "semasa" semasa main semula. Sematkan versi API peristiwa apabila titik akhir dicipta, rekodkannya bersama peristiwa, dan kekalkan bentuk asal untuk percubaan semula dan main semula. Naik taraf dengan mencipta atau beralih ke titik akhir versi baharu dan sahkan pengguna tersebut. Dokumentasi awam Stripe juga mengikat bentuk peristiwa webhook dengan versi API semasa penciptaan titik akhir. Menghantar kedua-dua peristiwa lama dan baharu mencipta kesan sampingan pendua dan selamat hanya sebagai migrasi singkat apabila pengguna menyahduplikasi menggunakan ID peristiwa yang stabil.
Susulan 3: Adakah nilai enum respons baharu merupakan perubahan pemutus (breaking change)?
Ia bergantung pada kontrak yang diterbitkan. GitHub menyenaraikan penambahan nilai enum sebagai aditif, manakala panduan keserasian Google juga memberi amaran bahawa kod lama mungkin tidak mengendalikan nilai enum respons baharu dengan baik. Nyatakan ketegangan itu secara eksplisit. Jika kontrak mentakrifkan set terbuka, SDK mendedahkan perwakilan yang tidak diketahui, dan pengguna mesti bertolak ansur dengannya, perubahan tersebut boleh menjadi serasi. Jika jenis tersebut ditutup atau ekosistem mengandungi switch yang menyeluruh, anggap ia sebagai risiko pemutus: perbaiki SDK dan kontrak terlebih dahulu atau letakkan nilai tersebut dalam versi baharu. Skema sisi pelayan sahaja tidak dapat memutuskannya.
Susulan 4: Senarai v1 tanpa had mengalami masa tamat (timeout). Bagaimana jika migrasi tidak dapat diselesaikan tepat pada masanya?
Mula-mula pulihkan perkhidmatan dengan kawalan yang dibenarkan oleh kontrak sedia ada: kuota, caching, pengoptimuman pertanyaan, dan tekanan balik (backpressure), sambil memindahkan pengguna bervolum tinggi terus ke v2. Jika had respons kecemasan tidak dapat dielakkan, nyatakan bahawa ia mungkin memecahkan v1, gunakan proses kelulusan insiden dan perubahan, umumkan skop yang terjejas, sediakan eksport pukal atau saluran keserasian sementara, dan pantau risiko kehilangan data. Mengembalikan 100 rekod pertama secara senyap dengan respons 200 menukar insiden ketersediaan kepada ralat data yang sukar dikesan; ia bukan pembaikan yang serasi.
Susulan 5: Tarikh penutupan tiba, tetapi 0.2% trafik masih menggunakan v1. Apa seterusnya?
Leraikan peratusan tersebut kepada pengguna dan tujuan perniagaan: prob (probe), konfigurasi yang salah, tugas akhir bulan, atau pelanggan berkontrak. Alih keluar trafik yang boleh dikenal pasti tanpa kebergantungan perniagaan. Pengguna kritikal memerlukan peningkatan, pengecualian, atau eskalasi sokongan. Kendalikan trafik tanpa nama di bawah dasar yang diterbitkan dan model risiko. Rekod panggilan yang tinggal, bukti pemberitahuan, kewajipan sokongan, pelan pemulihan, dan pemilik keputusan. Peratusan sahaja tidak membuktikan bahawa penutupan adalah selamat mahupun versi tersebut mesti kekal selama-lamanya.