Membuat versi REST API

1. Masalahnya

Mengembangkan REST API adalah masalah yang sulit - di mana banyak pilihan tersedia. Artikel ini membahas beberapa opsi ini.

2. Apa yang Ada di Kontrak?

Sebelumnya, kita perlu menjawab satu pertanyaan sederhana: Apa Kontrak antara API dan Klien?

2.1. URI bagian dari Kontrak?

Pertama-tama mari kita pertimbangkan struktur URI dari REST API - apakah itu bagian dari kontrak? Haruskah klien mem-bookmark, hardcode, dan umumnya mengandalkan URI API?

Jika demikian, maka interaksi Klien dengan Layanan REST tidak lagi didorong oleh Layanan itu sendiri, tetapi oleh apa yang disebut oleh Roy Fielding sebagai informasi out-of-band :

REST API harus dimasukkan tanpa pengetahuan sebelumnya di luar URI awal (bookmark) dan kumpulan jenis media standar yang sesuai untuk audiens yang dituju… Kegagalan di sini menyiratkan bahwa informasi out-of-band mendorong interaksi alih-alih hypertext.

Jadi jelas URI bukan bagian dari kontrak ! Klien seharusnya hanya mengetahui satu URI - titik masuk ke API. Semua URI lainnya harus ditemukan saat menggunakan API.

2.2. Jenis Media bagian dari Kontrak?

Bagaimana dengan informasi Jenis Media yang digunakan untuk representasi Sumber Daya - apakah ini bagian dari kontrak antara Klien dan Layanan?

Agar berhasil menggunakan API, Klien harus memiliki pengetahuan sebelumnya tentang Jenis Media ini . Padahal, definisi jenis media ini mewakili keseluruhan kontrak.

Oleh karena itu, di sinilah Layanan REST harus paling fokus:

REST API harus menghabiskan hampir semua upaya deskriptifnya dalam menentukan jenis media yang digunakan untuk mewakili sumber daya dan mendorong status aplikasi, atau dalam menentukan nama relasi yang diperluas dan / atau mark-up yang mendukung hypertext untuk jenis media standar yang ada.

Jadi definisi Jenis Media adalah bagian dari kontrak dan harus menjadi pengetahuan sebelumnya untuk klien yang menggunakan API. Di sinilah peran standardisasi.

Kami sekarang memiliki ide bagus tentang apa kontraknya, mari beralih ke cara menangani masalah pembuatan versi.

3. Opsi Tingkat Tinggi

Sekarang mari kita bahas pendekatan tingkat tinggi untuk membuat versi REST API:

  • Versi URI - buat versi ruang URI menggunakan indikator versi
  • Versi Jenis Media - versi Representasi Sumber Daya

Saat kami memperkenalkan versi di ruang URI, Representasi Sumber Daya dianggap tidak dapat diubah. Jadi, saat perubahan perlu diperkenalkan di API, ruang URI baru perlu dibuat.

Misalnya, API menerbitkan sumber daya berikut - pengguna dan hak istimewa:

//host/v1/users //host/v1/privileges

Sekarang, mari kita pertimbangkan bahwa perubahan yang dapat menyebabkan gangguan dalam API pengguna memerlukan pengenalan versi kedua:

//host/v2/users //host/v2/privileges

Saat kami membuat versi Jenis Media dan memperluas bahasanya, kami melalui Negosiasi Konten berdasarkan tajuk ini. REST API akan menggunakan jenis media MIME vendor khusus, bukan jenis media umum seperti application / json . Kita akan membuat versi jenis media ini, bukan URI.

Sebagai contoh:

===> GET /users/3 HTTP/1.1 Accept: application/vnd.myname.v1+json <=== HTTP/1.1 200 OK Content-Type: application/vnd.myname.v1+json { "user": { "name": "John Smith" } }

Kami dapat melihat artikel 'Jenis Media Khusus untuk Rest API' ini untuk informasi lebih lanjut dan contoh tentang subjek ini.

Yang penting untuk dipahami di sini adalah bahwa klien tidak membuat asumsi tentang struktur respons di luar apa yang didefinisikan dalam jenis media.

Inilah mengapa jenis media generik tidak ideal. Ini tidak memberikan informasi semantik yang cukup dan memaksa klien untuk menggunakan, memerlukan petunjuk tambahan untuk memproses representasi aktual sumber daya.

Pengecualian untuk ini adalah menggunakan beberapa cara lain untuk mengidentifikasi semantik konten secara unik - seperti skema XML.

4. Keuntungan dan Kerugian

Sekarang setelah kita memiliki konsep yang jelas tentang apa yang merupakan bagian dari Kontrak antara Klien dan Layanan, serta gambaran umum tingkat tinggi dari opsi untuk versi API, mari kita bahas keuntungan dan kerugian dari setiap pendekatan.

Pertama, memperkenalkan pengenal versi di URI akan menghasilkan jejak URI yang sangat besar. Hal ini disebabkan oleh fakta bahwa setiap perubahan yang dapat merusak di salah satu API yang dipublikasikan akan memperkenalkan pohon representasi yang sama sekali baru untuk keseluruhan API. Seiring waktu, ini menjadi beban yang harus dipelihara sekaligus menjadi masalah bagi klien - yang kini memiliki lebih banyak pilihan untuk dipilih.

Pengenal versi di URI ARE juga sangat tidak fleksibel . Tidak ada cara untuk hanya mengembangkan API dari satu Sumber Daya, atau sebagian kecil dari keseluruhan API.

Seperti yang kami sebutkan sebelumnya, ini adalah pendekatan semua atau tidak sama sekali. Jika bagian dari API pindah ke versi baru, maka seluruh API harus ikut bergerak bersamanya. Hal ini juga membuat peningkatan versi klien dari v1 ke v2 menjadi pekerjaan besar - yang mengarah pada peningkatan yang lebih lambat dan periode penghentian yang lebih lama untuk versi lama.

Cache HTTP juga menjadi perhatian utama dalam hal pembuatan versi.

Dari perspektif cache proxy di tengah, setiap pendekatan memiliki kelebihan dan kekurangan. Jika URI dibuat versi, cache perlu menyimpan banyak salinan dari setiap Sumber Daya - satu untuk setiap versi API. Hal ini membebani cache dan menurunkan tingkat ketepatan cache karena klien yang berbeda akan menggunakan versi yang berbeda.

Also, some cache invalidation mechanisms will no longer work. If the media type is the one that is versioned, then both the Client and the Service need to support the Vary HTTP header to indicate that there are multiple versions being cached.

From the perspective of client caching however, the solution that versions the media type involves slightly more work than the one where URIs contain the version identifier. This is because it's simply easier to cache something when its key is an URL than a media type.

Let's end this section with defining some goals (straight out of API Evolution):

  • keep compatible changes out of names
  • avoid new major versions
  • makes changes backwards-compatible
  • think about forwards-compatibility

5. Possible Changes to the API

Next, let's consider the types of changes to the REST API – these are introduced here:

  • representation format changes
  • resource changes

5.1. Adding to the Representation of a Resource

The format documentation of the media type should be designed with forward compatibility in mind. Specifically, a client should ignore information that it doesn't understand (which JSON does better than XML).

Now, adding information in the Representation of a resource will not break existing clients if these are correctly implemented.

To continue our earlier example, adding the amount in the representation of the user will not be a breaking change:

{ "user": { "name": "John Smith", "amount": "300" } }

5.2. Removing or Changing an Existing Representation

Removing, renaming or generally restructuring information in the design of existing representations is a breaking change for clients. This is because they already understand and rely on the old format.

This is where Content Negotiation comes in. For such changes, we can add a new vendor MIME media type.

Let's continue with the previous example. Say we want to break the name of the user into firstname and lastname:

===> GET /users/3 HTTP/1.1 Accept: application/vnd.myname.v2+json <=== HTTP/1.1 200 OK Content-Type: application/vnd.myname.v2+json { "user": { "firstname": "John", "lastname": "Smith", "amount": "300" } }

As such, this does represent an incompatible change for the Client – which will have to request the new Representation and understand the new semantics. However, the URI space will remain stable and will not be affected.

5.3. Major Semantic Changes

These are changes in the meaning of the Resources, the relations between them or what the map to in the backend. This kind of changes may require a new media type, or they may require publishing a new, sibling Resource next to the old one and making use of linking to point to it.

While this sounds like using version identifiers in the URI all over again, the important distinction is that the new Resource is published independently of any other Resources in the API and will not fork the entire API at the root.

The REST API should adhere to the HATEOAS constraint. According to this, most of the URIs should be DISCOVERED by Clients, not hardcoded. Changing such an URI should not be considered an incompatible change. The new URI can replace the old one and Clients will be able to re-discover the URI and still function.

It's worth noting however that, while using version identifiers in the URI is problematic for all of these reasons, it is not un-RESTful in any way.

6. Conclusion

This article tried to provide an overview of the very diverse and difficult problem of evolving a REST Service. We discussed the two common solutions, advantages and disadvantages of each one, and ways to reason about these approaches in the context of REST.

Artikel ini menyimpulkan dengan membuat kasus untuk solusi kedua - membuat versi jenis media sambil memeriksa kemungkinan perubahan pada RESTful API.

Implementasi lengkap dari tutorial ini dapat ditemukan di proyek GitHub.

7. Bacaan Lebih Lanjut

Biasanya, sumber bacaan ini ditautkan ke seluruh artikel, tetapi dalam kasus ini, ada terlalu banyak yang bagus:

    • REST API harus digerakkan oleh hypertext
    • Evolusi API
    • Menautkan ke API HTTP
    • Strategi Kompatibilitas