GoSuda

Go dan Ekosistem OpenAPI

By iwanhae
views ...

Pendahuluan

Ketika mengembangkan Production Backend server dengan bahasa Go, salah satu tantangan pertama yang hampir selalu dihadapi oleh sebagian besar pengembang adalah sebagai berikut:

Dokumentasi API, bagaimana caranya...?

Jika sedikit mencari tahu mengenai hal ini, akan disadari bahwa menulis dokumen yang sesuai dengan spesifikasi OpenAPI adalah hal yang menguntungkan, dan secara alami akan mencari library yang terintegrasi dengan OpenAPI. Namun, meskipun keputusan ini telah diambil, masalah berikutnya muncul.

Ada banyak library terkait OpenAPI.. yang mana yang harus saya gunakan...?

Dokumen ini adalah pengantar singkat tentang library yang ditulis untuk pemula Go yang sedang mengalami situasi ini. Dokumen ini ditulis berdasarkan kondisi akhir tahun 2024, dan karena ekosistem bahasa selalu berubah secara dinamis, disarankan untuk menggunakannya sebagai referensi dan selalu memperhatikan perkembangan terbaru.

Strategi Library dalam Menangani OpenAPI

Seperti yang mungkin sudah Anda ketahui, OpenAPI adalah spesifikasi untuk mendefinisikan dan mendokumentasikan REST API dengan jelas. Dengan mendefinisikan endpoint API, permintaan, format respons, dan lain-lain dalam format YAML atau JSON, tidak hanya bagi pengembang, tetapi juga secara otomatis menghasilkan kode frontend dan backend, yang mengurangi pengulangan yang tidak berarti dan sangat membantu mengurangi kesalahan manusia yang kecil.

Untuk mengintegrasikan OpenAPI ini secara alami dengan proyek, library dalam ekosistem Go mengambil tiga strategi utama berikut.

1. Menggabungkan komentar Go menjadi dokumen spesifikasi OpenAPI

Salah satu hal yang rumit saat mengembangkan API sesuai OpenAPI adalah bahwa dokumen aktual dan kode yang mengimplementasikan dokumen tersebut berada di file terpisah di lokasi yang berbeda, sehingga seringkali terjadi situasi di mana kode diperbarui tetapi dokumen tidak, atau dokumen diperbarui tetapi kode tidak.

Sebagai contoh sederhana:

  1. Logika API diubah dalam file ./internal/server/user.go, tetapi
  2. Dokumen aktual berada di ./openapi3.yaml, dan perubahan tersebut mungkin secara tidak sengaja terlewatkan.
  3. Jika Pull Request diajukan tanpa menyadari masalah perubahan ini dan mendapatkan ulasan dari rekan kerja,
  4. Karena reviewer juga tidak melihat perubahan pada ./openapi3.yaml, maka dapat terjadi insiden di mana spesifikasi API tetap sama tetapi implementasi API aktual telah berubah.

Menulis dokumentasi API dalam bentuk komentar Go dapat mengatasi masalah ini sampai batas tertentu. Karena kode dan dokumen berada di satu tempat, komentar dapat diperbarui bersamaan dengan modifikasi kode. Ada alat yang secara otomatis menghasilkan dokumen spesifikasi OpenAPI berdasarkan komentar ini.

Proyek yang representatif adalah Swag. Swag mengurai komentar dalam kode Go untuk menghasilkan dokumen dalam format OpenAPI 2. Cara penggunaannya sederhana. Cukup tulis komentar di atas fungsi handler sesuai format yang ditentukan oleh masing-masing library.

 1// @Summary Membuat pengguna
 2// @Description Membuat pengguna baru.
 3// @Tags Pengguna
 4// @Accept json
 5// @Produce json
 6// @Param user body models.User true "Informasi pengguna"
 7// @Success 200 {object} models.User
 8// @Failure 400 {object} models.ErrorResponse
 9// @Router /users [post]
10func CreateUser(c *gin.Context) {
11    // ...
12}

Ketika komentar seperti ini ditulis, CLI bernama Swag akan mengurai komentar-komentar ini untuk menghasilkan dokumen OpenAPI 2. Umumnya, pekerjaan ini dilakukan selama proses CI, dan dokumen spesifikasi OpenAPI yang dihasilkan akan didistribusikan ke Git Repository, hasil build akhir, atau sistem manajemen dokumen API eksternal terpisah untuk digunakan dalam kolaborasi dengan proyek lain.

Keunggulan:

  • Karena komentar berada bersama kode, kemungkinan perbedaan antara kode aktual dan bentuk dokumen berkurang.
  • Dokumentasi dapat dilakukan dengan mudah dan bebas hanya dengan komentar, tanpa alat terpisah atau konfigurasi yang rumit.
  • Karena komentar tidak memengaruhi logika API aktual, sangat baik untuk menambahkan fungsi sementara yang terlalu sensitif untuk dipublikasikan sebagai dokumen.

Kekurangan:

  • Jumlah baris komentar yang meningkat dapat mengurangi keterbacaan file kode tunggal.
  • Mungkin sulit untuk mengekspresikan semua spesifikasi API dalam bentuk komentar.
  • Karena dokumen tidak memaksa kode, tidak ada jaminan bahwa dokumen OpenAPI dan logika aktual akan sesuai.

2. Membuat Kode Go dari Dokumen Spesifikasi OpenAPI

Ada juga pendekatan di mana Single Source of Truth (SSOT) ditempatkan pada dokumen, bukan pada kode Go. Yaitu, dengan mendefinisikan spesifikasi OpenAPI terlebih dahulu, kemudian membuat kode Go berdasarkan definisi tersebut. Karena spesifikasi API secara langsung menghasilkan kode, hal ini dapat memaksa budaya pengembangan untuk mendesain API terlebih dahulu, dan karena definisi spesifikasi API adalah langkah pertama dalam urutan pengembangan, hal ini memiliki keunggulan untuk mencegah insiden di mana bagian yang terlewatkan baru disadari setelah pengembangan selesai, yang kemudian memerlukan perubahan spesifikasi API dan seluruh kode.

Proyek-proyek representatif yang mengadopsi pendekatan ini adalah oapi-codegen dan OpenAPI Generator. Cara penggunaannya sederhana.

  1. Tulis dokumen YAML atau JSON sesuai spesifikasi OpenAPI.
  2. Jalankan CLI.
  3. Kode stub Go yang sesuai akan dihasilkan.
  4. Sekarang, cukup implementasikan logika detail untuk setiap API agar stub ini dapat digunakan.

Berikut adalah contoh kode yang dihasilkan oleh oapi-codegen:

1// StrictServerInterface merepresentasikan semua handler server.
2type StrictServerInterface interface {
3	// ...
4	// Mengembalikan semua hewan peliharaan
5	// (GET /pets)
6	FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error)
7	// ...
8}

Kode yang dihasilkan oleh oapi-codegen dengan antarmuka di atas sebagai parameter adalah struktur yang melakukan parsing parameter kueri, header, body, serta validasi, dan memanggil metode yang sesuai yang dideklarasikan dalam antarmuka. Pengguna hanya perlu mengimplementasikan implementasi untuk antarmuka di atas, dan tugas yang diperlukan untuk implementasi API akan selesai.

Keunggulan:

  • Karena spesifikasi dibuat terlebih dahulu dan pengembangan dilakukan setelahnya, sangat menguntungkan untuk melakukan pekerjaan secara paralel ketika beberapa tim berkolaborasi.
  • Kode untuk bagian yang sebelumnya merupakan pekerjaan manual berulang akan dihasilkan secara otomatis, sehingga efisiensi kerja meningkat dan masih menguntungkan untuk debugging.
  • Mudah untuk memastikan bahwa dokumen dan bentuk kode selalu konsisten.

Kekurangan:

  • Jika tidak terbiasa dengan spesifikasi OpenAPI itu sendiri, kurva pembelajaran awal mungkin cukup tinggi.
  • Karena bentuk kode yang menangani API dihasilkan secara otomatis oleh proyek, mungkin sulit untuk menyesuaikan jika diperlukan kustomisasi.

Komentar dari penulis. Per Oktober 2024, kode Go yang dihasilkan oleh OpenAPI Generator tidak hanya memaksa logika API tetapi juga bentuk proyek secara keseluruhan, dan struktur proyek kaku, menghasilkan kode yang tidak cocok untuk menambahkan berbagai fungsi yang diperlukan di lingkungan Produksi sebenarnya. Bagi mereka yang mengadopsi pendekatan ini, sangat disarankan untuk menggunakan oapi-codegen. Penulis menggunakan oapi-codegen + echo + StrictServerInterface.

3. Membuat Dokumen Spesifikasi OpenAPI dengan Kode Go

Ketika puluhan atau ratusan orang mengembangkan server yang sama, masalah yang tak terhindarkan muncul adalah kurangnya konsistensi di antara setiap API. Sebagai contoh intuitif, jika spesifikasi untuk lebih dari 100 Endpoint API dideklarasikan dalam satu file YAML OpenAPI, file tersebut akan menjadi monster dengan lebih dari 10.000 baris, dan ketika mendeklarasikan Endpoint API baru, secara tak terhindarkan akan ada deklarasi model yang berulang, beberapa bidang yang hilang, atau penamaan Path yang tidak sesuai dengan konvensi, yang menyebabkan hilangnya konsistensi API secara keseluruhan.

Untuk mengatasi masalah ini, dapat ditunjuk Pemilik terpisah untuk mengelola YAML OpenAPI, atau mengembangkan Linter untuk secara otomatis mendeteksinya selama proses CI, tetapi dengan mendefinisikan Domain-specific language (DSL) dalam bahasa Go, semua API dapat dipaksa untuk memiliki konsistensi yang seragam.

Proyek representatif yang menggunakan teknik ini adalah Kubernetes (dibangun secara internal tanpa library terpisah), dan dapat dicoba menggunakan proyek seperti go-restful, goa. Berikut adalah contoh penggunaan goa:

 1var _ = Service("user", func() {
 2    Method("create", func() {
 3        Payload(UserPayload)
 4        Result(User)
 5        HTTP(func() {
 6            POST("/users")
 7            Response(StatusOK)
 8        })
 9    })
10})

Dengan menulis kode Go yang dapat dikompilasi seperti di atas, Anda mendapatkan keuntungan dari penyelesaian implementasi dan definisi dokumen untuk API POST /users secara bersamaan.

Keunggulan:

  • Karena semuanya berasal dari kode, mudah untuk mempertahankan konsistensi API di seluruh proyek.
  • Dengan memanfaatkan sistem tipe kuat Go, Anda bisa mendapatkan spesifikasi yang lebih akurat dan tidak ambigu daripada menggunakan semua fitur OpenAPI3.

Kekurangan:

  • Harus mempelajari DSL yang didefinisikan oleh setiap kerangka kerja, dan mungkin sulit untuk menerapkannya pada kode yang sudah ada.
  • Karena harus mengikuti aturan yang disarankan oleh kerangka kerja, kebebasan dan fleksibilitas dapat berkurang.

Kesimpulan

Setiap metode memiliki kelebihan dan kekurangannya, dan penting untuk memilih metode yang sesuai dengan kebutuhan proyek dan preferensi tim. Yang paling penting bukanlah metode mana yang terbaik, melainkan melakukan penilaian nilai tentang solusi mana yang paling cocok untuk situasi Anda saat ini, meningkatkan produktivitas pengembangan, dan menikmati pulang cepat serta keseimbangan kerja-hidup yang memuaskan.

Meskipun tulisan ini dibuat pada Oktober 2024, ekosistem Go dan OpenAPI terus berkembang, jadi harap pertimbangkan interval waktu sejak Anda membaca artikel ini dan terus ikuti perkembangan terbaru dari setiap library dan proyek, serta perubahan kelebihan dan kekurangannya.

Semoga hidup Go Anda menyenangkan~ 😘