Backend untuk frontend, atau How Yandex.Market membuat API tanpa kruk

Mengapa beberapa API lebih nyaman digunakan daripada yang lain? Apa yang bisa kita lakukan sebagai penyedia front-end di pihak kita untuk bekerja dengan API dengan kualitas yang dapat diterima? Hari ini saya akan memberi tahu pembaca Habr tentang opsi teknis dan tentang langkah-langkah organisasi yang akan membantu penyedia front-end dan back-end menemukan bahasa yang sama dan membangun kerja yang efektif.



Musim gugur ini, Yandex.Market berusia 18 tahun. Selama ini, antarmuka afiliasi Market telah berkembang. Singkatnya, ini adalah panel admin tempat toko dapat mengunggah katalog, bekerja dengan bermacam-macam, mengikuti statistik, menanggapi ulasan, dll. Kekhasan proyek adalah Anda harus banyak berinteraksi dengan berbagai backend. Namun, data tidak selalu dapat diperoleh di satu tempat, dari satu backend tertentu.


Gejala Masalah


Jadi, bayangkan, ada semacam masalah. Manajer pergi dengan tugas kepada para desainer - mereka menggambar tata letak. Lalu ia pergi ke back-end - mereka membuat beberapa pena dan menulis daftar parameter dan format respons pada wiki internal.

Kemudian manajer pergi ke front-end dengan kata-kata "Saya membawa API untuk Anda" dan menawarkan untuk dengan cepat skrip semuanya, karena, menurutnya, hampir semua pekerjaan telah dilakukan.


Anda melihat dokumentasi dan melihat ini:


β„– |   ---------------------- 53 | feed_shoffed_id 54 | fesh 55 | filter-currency 56 | showVendors 

Tidak melihat sesuatu yang aneh? Kasing Unta, Ular, dan Kebab dalam satu pena. Saya tidak berbicara tentang parameter fesh. Apa itu fesh? Kata seperti itu bahkan tidak ada. Coba tebak sebelum Anda membuka spoiler.


Spoiler

Fesh adalah filter menurut ID toko. Anda dapat melewati beberapa pengidentifikasi yang dipisahkan oleh koma. ID dapat didahului dengan tanda minus, yang berarti bahwa toko ini harus dikeluarkan dari hasil.


Pada saat yang sama, dari JavaSctipt, tentu saja, saya tidak dapat mengakses properti dari objek seperti itu melalui notasi bertitik. Belum lagi fakta bahwa jika Anda memiliki lebih dari 50 parameter di satu tempat, maka, jelas, dalam hidup Anda, Anda berpaling ke tempat lain.


Ada banyak opsi untuk API yang tidak nyaman. Contoh klasik - API mencari dan mengembalikan hasil:


 result: [ {id: 1, name: 'IPhone 8'}, {id: 2, name: 'IPhone 8 Plus'}, {id: 3, name: 'IPhone X'}, ] result: {id: 1, name: 'IPhone 8'} result: null 

Jika barang ditemukan, kami mendapatkan array. Jika satu produk ditemukan, maka kita mendapatkan objek dengan produk ini. Jika tidak ada yang ditemukan, maka yang terbaik adalah nol. Dalam kasus terburuk, backend merespons dengan 404 atau bahkan 400 (Permintaan Buruk).


Situasi lebih mudah. Misalnya, Anda perlu mendapatkan daftar toko di satu backend, dan pengaturan toko di yang lain. Di beberapa pena tidak ada data yang cukup, dalam beberapa data ada terlalu banyak. Memfilter semua ini pada klien atau membuat beberapa permintaan ajax adalah ide yang buruk.


Jadi apa yang bisa menjadi solusi untuk masalah ini? Apa yang bisa kita lakukan sebagai penyedia front-end di pihak kita untuk bekerja dengan API dengan kualitas yang dapat diterima?


Frontend backend


Kami menggunakan klien React / Redux di antarmuka mitra. Di bawah klien terdapat Node.js, yang melakukan banyak hal tambahan, misalnya, melemparkannya ke halaman InitialState untuk Editor. Jika Anda memiliki rendering sisi server, tidak masalah dengan kerangka kerja klien yang mana, kemungkinan besar, itu dirender oleh sebuah node. Tetapi bagaimana jika Anda melangkah lebih jauh dan tidak secara langsung menghubungi klien di backend, tetapi membuat API proksi Anda pada node, yang secara maksimal disesuaikan dengan kebutuhan klien?
Teknik ini disebut BFF (Backend For Frontend). Istilah ini pertama kali diperkenalkan oleh SoundCloud pada tahun 2015, dan idenya dapat secara skematis digambarkan sebagai berikut:



Dengan demikian, Anda berhenti beralih dari kode klien langsung ke API. Setiap pegangan, setiap metode API nyata yang Anda duplikasi pada node dan dari klien pergi secara eksklusif ke node. Dan node sudah memproksi permintaan ke API nyata dan mengembalikan respons kepada Anda.


Ini tidak hanya berlaku untuk permintaan-mendapatkan primitif, tetapi secara umum untuk semua permintaan, termasuk dengan data multi-bagian / formulir. Misalnya, toko mengunggah file .xls dengan katalognya melalui formulir di situs. Jadi, dalam implementasi ini, direktori tidak dimuat secara langsung ke API, tetapi ke pegangan Nod Anda, yang proksi streaming ke backend nyata.


Ingat contoh itu dengan hasil ketika backend mengembalikan nol, array atau objek? Sekarang kita bisa mengembalikannya ke normal - sesuatu seperti ini:


 function getItems (response) { if (isNull(response)) return [] if (isObject(response)) return [response] return response } 

Kode ini terlihat mengerikan. Karena dia mengerikan. Tetapi kita masih perlu melakukan ini. Kami punya pilihan: melakukannya di server atau di klien. Saya memilih server.


Kami juga dapat memetakan semua kotak kebab dan ular ini dalam gaya yang nyaman bagi kami dan segera meletakkan nilai default jika perlu.


 query: { 'feed_shoffer_id': 'feedShofferId', 'pi-from': 'piFrom', 'show-urls': ({showUrls = 'offercard'}) => showUrls, } 

Apa keuntungan lain yang kita dapatkan?


  1. Penyaringan . Klien hanya menerima apa yang ia butuhkan, tidak lebih, tidak kurang.
  2. Agregasi Tidak perlu membuang jaringan klien dan baterai untuk membuat beberapa permintaan ajax. Peningkatan kecepatan yang terlihat karena membuka koneksi merupakan operasi yang mahal.
  3. Caching Panggilan agregat berulang Anda tidak akan menarik siapa pun lagi, tetapi hanya mengembalikan 304 Tidak Dimodifikasi.
  4. Menyembunyikan data. Misalnya, Anda mungkin memiliki token yang diperlukan di antara backend dan tidak boleh pergi ke klien. Klien mungkin tidak memiliki hak untuk tahu tentang keberadaan token ini, belum lagi isinya.
  5. Layanan microser . Jika Anda memiliki monolit di bagian belakang, maka BFF adalah langkah pertama untuk layanan microser.

Sekarang tentang kontra.


  1. Meningkatkan kesulitan . Abstraksi apa pun adalah lapisan lain yang perlu dikodekan, disebarkan, didukung. Bagian lain yang bergerak dari mekanisme yang mungkin gagal.
  2. Duplikasi pegangan. Misalnya, beberapa titik akhir dapat melakukan jenis agregasi yang sama.
  3. BFF adalah lapisan batas yang harus mendukung perutean umum, pembatasan hak pengguna, pencatatan kueri, dll.

Untuk meratakan minus ini, cukup mematuhi aturan sederhana. Yang pertama adalah memisahkan front-end dan logika bisnis. BFF Anda tidak boleh mengubah logika bisnis API inti. Kedua, layer Anda seharusnya hanya mengkonversi data jika benar-benar diperlukan. Kami tidak berbicara tentang API komprehensif mandiri, tetapi hanya tentang proksi yang mengisi kesenjangan, memperbaiki kekurangan backend.


GraphQL


Masalah serupa diselesaikan oleh GraphQL. Dengan GraphQL, alih-alih banyak titik akhir "bodoh", Anda memiliki satu pena pintar yang dapat bekerja dengan permintaan kompleks dan menghasilkan data dalam bentuk yang diminta klien.


Pada saat yang sama, GraphQL dapat bekerja di atas REST, yaitu sumber data bukan basis data, tetapi API sisanya. Karena sifat deklaratif GraphQL, karena semua ini berteman dengan React dan Editor, klien Anda menjadi lebih mudah.


Bahkan, saya melihat GraphQL sebagai implementasi BFF dengan protokol dan bahasa query yang ketat.


Ini adalah solusi yang sangat baik, tetapi memiliki beberapa kelemahan, khususnya, dengan tipifikasi, dengan diferensiasi hak, dan secara umum ini merupakan pendekatan yang relatif baru. Oleh karena itu, kami belum beralih ke sana, tetapi di masa mendatang menurut saya cara yang paling optimal untuk membuat API.


Teman terbaik selamanya


Tidak ada solusi teknis yang akan bekerja dengan benar tanpa perubahan organisasi. Anda masih memerlukan dokumentasi, jaminan bahwa format respons tidak akan berubah tiba-tiba, dll.


Harus dipahami bahwa kita semua berada di kapal yang sama. Untuk pelanggan yang abstrak, apakah itu manajer atau manajer Anda, pada umumnya, tidak ada bedanya - Anda memiliki GraphQL di sana atau BFF. Lebih penting baginya bahwa masalah diselesaikan dan kesalahan tidak muncul pada prod. Baginya, tidak ada banyak perbedaan karena kesalahan siapa kesalahan terjadi pada produk - melalui kesalahan bagian depan atau belakang. Karena itu, Anda perlu bernegosiasi dengan para backders.


Selain itu, kelemahan di bagian belakang yang saya bicarakan di awal laporan tidak selalu muncul karena tindakan jahat seseorang. Mungkin saja parameter fesh juga memiliki beberapa arti.



Perhatikan tanggal komit. Ternyata baru-baru ini fesh merayakan ulang tahun ketujuh belas.


Lihat beberapa pengidentifikasi aneh di sebelah kiri? Ini SVN, hanya karena tidak ada gita pada tahun 2001. Bukan github sebagai layanan, tetapi gith sebagai sistem kontrol versi. Dia muncul hanya pada tahun 2005.


Dokumentasi


Jadi, yang kita butuhkan bukanlah bertengkar dengan back-end, tetapi untuk menyetujui. Ini hanya dapat dilakukan jika kita menemukan satu sumber kebenaran. Sumber itu harus berupa dokumentasi.


Yang paling penting di sini adalah menulis dokumentasi sebelum kita mulai mengerjakan fungsionalitas. Seperti halnya perjanjian pranikah, lebih baik menyepakati semua yang ada di pantai.


Bagaimana cara kerjanya? Secara relatif, tiga akan: manajer, front-end dan back-end. Fronteder fasih dalam bidang subjek, sehingga partisipasinya sangat penting. Mereka berkumpul dan mulai berpikir tentang API: dengan cara apa, jawaban apa yang harus dikembalikan, hingga nama dan format bidang.


Kesombongan


Pilihan yang baik untuk dokumentasi API adalah format Swagger , sekarang disebut OpenAPI. Lebih baik menggunakan Swagger dalam format YAML, karena, tidak seperti JSON, lebih baik dibaca oleh manusia, tetapi tidak ada perbedaan untuk mesin.


Akibatnya, semua perjanjian diperbaiki dalam format Swagger dan diterbitkan dalam repositori bersama. Dokumentasi untuk backend penjualan harus dalam panduan.


Master dilindungi dari komit, kode masuk ke dalamnya hanya melalui kumpulan permintaan, Anda tidak dapat mendorongnya. Perwakilan dari tim depan berkewajiban melakukan peninjauan terhadap kumpulan permintaan, tanpa peningkatannya, kode tidak akan diberikan kepada master. Ini melindungi Anda dari perubahan API yang tidak terduga tanpa pemberitahuan sebelumnya.


Jadi Anda berkumpul, tulis Swagger, jadi Anda benar-benar menandatangani kontrak. Mulai saat ini, Anda sebagai front-end dapat memulai pekerjaan Anda tanpa menunggu pembuatan API nyata. Lagi pula, apa gunanya pemisahan antara klien dan server, jika kita tidak bisa bekerja secara paralel dan pengembang klien harus menunggu pengembang server? Jika kita memiliki "kontrak", maka kita dapat memparalelkan masalah ini dengan aman.


Faker.js


Faker hebat untuk tujuan ini. Ini adalah pustaka untuk menghasilkan sejumlah besar data palsu. Ini dapat menghasilkan berbagai jenis data: tanggal, nama, alamat, dll., Semua ini terlokalisasi dengan baik, ada dukungan untuk bahasa Rusia.


Pada saat yang sama, si penipu berteman dengan kesombongan, dan Anda dapat dengan tenang meningkatkan server Mock, yang, berdasarkan skema Kesombongan, akan menghasilkan jawaban palsu kepada Anda dengan cara yang diperlukan.


Validasi


Swagger dapat dikonversi menjadi skema json, dan dengan bantuan alat-alat seperti ajv Anda dapat memvalidasi respons backend langsung di runtime, di BFF Anda, dan melaporkan penguji, pendukung sendiri, jika ada perbedaan, dll.


Misalkan penguji menemukan beberapa jenis bug di situs, misalnya, ketika tombol diklik, tidak ada yang terjadi. Apa yang dilakukan penguji? Dia meletakkan tiket di front-end: "ini tombol Anda, tidak ditekan, perbaiki."


Jika ada validator antara Anda dan belakang, tester akan tahu bahwa tombol tersebut benar-benar ditekan, hanya backend yang mengirim jawaban yang salah. Salah - ini adalah respons yang tidak diharapkan front, yaitu tidak sesuai dengan "kontrak". Dan di sini sudah perlu untuk memperbaiki bagian belakang atau mengubah kontrak.


Kesimpulan


  1. Kami secara aktif terlibat dalam desain API. Kami merancang API agar nyaman digunakan setelah 17 tahun.
  2. Kami memerlukan dokumentasi Swagger. Tidak ada dokumentasi - operasi back-end tidak selesai.
  3. Ada dokumentasi - kami menerbitkannya di git, dan setiap perubahan dalam API harus diperbarui oleh perwakilan tim depan.
  4. Kami meningkatkan server palsu dan mulai bekerja di depan tanpa menunggu API yang sebenarnya.
  5. Kami meletakkan simpul di bawah frontend dan memvalidasi semua jawaban. Plus, kami mendapatkan kemampuan untuk mengumpulkan, menormalkan, dan menyimpan data.

Lihat juga


β†’ Bagaimana membangun API seperti REST di proyek besar
β†’ Backend Di Frontend
β†’ Menggunakan GraphQL sebagai Implementasi Pola BFF

Source: https://habr.com/ru/post/id428141/


All Articles