
Thwacknya adalah:
README ini sedang dalam proses. Anda juga dapat mengajukan pertanyaan kepada saya di Twitter.
$ npm i thwackatau
$ yarn add thwack Axios sangat bagus ketika dirilis pada masa lalu. Ini memberi kami pembungkus berbasis janji di sekitar XMLHttpRequest , yang sulit digunakan. Namun hal tersebut sudah lama terjadi dan zaman telah berubah — browser kini menjadi lebih pintar. Mungkin sudah waktunya solusi pengambilan data Anda mengikuti?
Thwack dibangun dari awal dengan mempertimbangkan browser modern. Karena itu, ia tidak memiliki bagasi seperti yang dimiliki Axios. Axios berbobot sekitar ~5k gzip. Thwack, di sisi lain, ramping ~1,5k.
Keduanya mendukung API yang sama, namun terdapat beberapa perbedaan — terutama pada options — namun secara umum, keduanya dapat digunakan secara bergantian untuk banyak aplikasi.
Thwack tidak mencoba menyelesaikan setiap masalah, seperti yang dilakukan Axios, namun memberikan solusi untuk 98% dari apa yang benar-benar dibutuhkan pengguna. Inilah yang membuat Thwack memiliki jejak yang sangat ringan.
Gores itu. Thwack memberikan tingkat kekuatan yang sama dengan Axios dengan ukuran yang jauh lebih kecil. Dan sistem acara berbasis janji Thwack lebih mudah digunakan.
Metode berikut tersedia di semua instans Thwack.
thwack(url: string [,options: ThwackOptions]): Promise<ThwackResponse>;
thwack.request(options: ThwackOptions): Promise<ThwackResponse>
thwack.get(url: string [,options: ThwackOptions]): Promise<ThwackResponse>;
thwack.delete(url: string [,options: ThwackOptions]): Promise<ThwackResponse>;
thwack.head(url: string [,options: ThwackOptions]): Promise<ThwackResponse>;
thwack.post(url: string, data:any [,options: ThwackOptions]): Promise<ThwackResponse>;
thwack.put(url: string, data:any [,options: ThwackOptions]): Promise<ThwackResponse>;
thwack.patch(url: string, data:any [,options: ThwackOptions]): Promise<ThwackResponse>;
thwack.create(options: ThwackOptions): ThwackInstance;
Metode create membuat (da!) instance anak baru dari instance Thwack saat ini dengan options yang diberikan.
thwack.getUri(options: ThwackOptions): string;
Resolusi URL Thwacks sesuai dengan RFC-3986. Axios tidak. Ini didukung oleh @thwack/resolve .
Thwack mendukung jenis acara berikut: request , response , data , dan error .
Untuk informasi lebih lanjut tentang sistem acara Thwack, lihat acara Thwack di bawah.
thwack.addEventListener(type: string, callback: (event:ThwackEvent) => Promise<any> ): void;
thwack.removeEventListener(type: string, callback: (event:ThwackEvent) => Promise<any> ): void;
Thwack memiliki fungsi pembantu berikut untuk membuat permintaan secara bersamaan. Sebagian besar ditujukan untuk kompatibilitas Axios. Lihat bagian "Cara" di bawah untuk contoh penggunaan.
thwack.all(Promise<ThwackResponse>[])
thwack.spread(callback<results>)
Argumen options memiliki properti berikut.
urlIni bisa berupa URL yang sepenuhnya memenuhi syarat atau URL relatif.
baseURL Menentukan URL dasar yang akan digunakan untuk membuat URL yang sepenuhnya memenuhi syarat dari url di atas. Harus berupa URL absolut atau undefined . Defaultnya adalah origin + pathname halaman web saat ini jika dijalankan di browser atau undefined di Node atau React Native.
Misalnya, jika Anda melakukan ini:
thwack ( 'foo' , {
baseURL : 'http://example.com' ,
} ) ;URL yang diambil akan menjadi:
http://example.com/foo
method Sebuah string yang berisi salah satu metode HTTP berikut: get , post , put , patch , delete , atau head .
data Jika method adalah post , put , atau patch , ini adalah data yang akan digunakan untuk membuat isi permintaan.
headersDi sinilah Anda dapat menempatkan header permintaan HTTP opsional apa pun. Setiap header yang Anda tentukan di sini digabungkan dengan nilai header instance apa pun.
Misalnya, jika kita menyetel instance Thwack seperti ini:
const api = thwack . create ( {
headers : {
'x-app-name' : 'My Awesome App' ,
} ,
} ) ;Kemudian nanti, saat Anda menggunakan instance tersebut, Anda melakukan panggilan seperti ini:
const { data } = await api . get ( 'foo' , {
headers : {
'some-other-header' : 'My Awesome App' ,
} ,
} ) ;Header yang akan dikirimkan adalah:
x-app-name: My Awesome App
some-other-header': 'My Awesome App'
defaultsHal ini memungkinkan Anda membaca/mengatur opsi default untuk instance ini dan, pada dasarnya, semua instance turunan.
Contoh:
thwack . defaults . baseURL = 'https://example.com/api' ; Misalnya, defaults adalah objek yang sama yang diteruskan ke create . Misalnya, berikut ini akan menampilkan "https://example.com/api".
const instance = thwack . create ( {
baseURL : 'https://example.com/api' ,
} ) ;
console . log ( instance . defaults . baseURL ) ; Perhatikan juga bahwa pengaturan defaults pada sebuah instance (atau bahkan meneruskan options ) ke sebuah instance TIDAK mempengaruhi induknya. Jadi untuk contoh berikut, thwack.defaults.baseURL akan tetap menjadi "https://api1.example.net/".
thwack . defaults . baseURL = 'https://api1.example.net/' ;
const instance = thwack . create ( ) ;
instance . defaults . baseURL = 'https://example.com/api' ;
console . log ( thwack . defaults . baseURL ) ;params Ini adalah objek opsional yang berisi pasangan kunci/nilai yang akan digunakan untuk membuat URL pengambilan. Apakah ada segmen :key dari baseURL atau url , segmen tersebut akan diganti dengan nilai kunci yang cocok. Misalnya, jika Anda melakukan ini:
thwack ( 'orders/:id' , {
params : { id : 123 } ,
baseURL : 'http://example.com' ,
} ) ;URL yang diambil akan menjadi:
http://example.com/orders/123
Jika Anda tidak menentukan :name , atau ada lebih banyak param daripada :name , maka kunci/nilai yang tersisa akan ditetapkan sebagai parameter pencarian (yaitu ?key=value ).
maxDepth Tingkat maksimum permintaan rekursif yang dapat dibuat dalam panggilan sebelum Thwack menimbulkan kesalahan. Ini digunakan untuk mencegah panggilan balik peristiwa menyebabkan perulangan rekursif, Ini jika mengeluarkan request lain tanpa perlindungan yang tepat. Bawaan = 3.
responseType Secara default, Thwack akan secara otomatis menentukan cara mendekode data respons berdasarkan nilai header respons content-type . Namun, jika server merespons dengan nilai yang salah, Anda dapat mengganti parser dengan menyetel responseType . Nilai yang valid adalah arraybuffer , document (yaitu formdata ), json , text , stream , dan blob . Defaultnya otomatis.
Apa yang dikembalikan oleh Thwack ditentukan oleh tabel berikut. Kolom "metode pengambilan" adalah yang diselesaikan di data . Jika Anda tidak menentukan responseType , Thwack akan secara otomatis menentukan metode pengambilan berdasarkan content-type dan tabel responseParserMap (lihat di bawah).
| Tipe Konten | responseType | metode fetch |
|---|---|---|
application/json | json | response.json() |
multipart/form-data | formdata | response.formData() |
text/event-stream | stream | meneruskan response.body sebagai data tanpa pemrosesan |
blob | response.blob() | |
arraybuffer | response.arrayBuffer() | |
*/* | text | response.text() |
Catatan:
streamsaat ini tidak didukung di React Native karena #27741
responseParserMap Cara lain yang berguna untuk menentukan parser respon mana yang akan digunakan adalah dengan responseParserMap . Ini memungkinkan Anda mengatur pemetaan antara content-type yang dihasilkan dari header respons dan tipe parser.
Thwack menggunakan peta berikut sebagai default, yang memungkinkan decoding json dan formdata . Jika tidak ada yang cocok, parser respons defaultnya adalah text . Anda dapat menentukan default dengan mengatur kunci */* khusus.
{
"application/json" : " json " ,
"multipart/form-data" : " formdata " ,
"*/*" : " text "
} ; Nilai apa pun yang Anda tentukan di responseParserMap digabungkan ke dalam peta default. Artinya, Anda dapat mengganti nilai default dan/atau menambahkan nilai baru.
Katakanlah, misalnya, Anda ingin mengunduh gambar ke dalam blob. Anda dapat mengatur baseURL ke titik akhir API dan responseParserMap yang akan mengunduh gambar jenis apa pun sebagai blob, namun tetap mengizinkan unduhan json (karena ini adalah default untuk content-type: application/json ).
import thwack from 'thwack' ;
thwack . defaults . responseParserMap = { 'image/*' : 'blob' } ; URL apa pun yang Anda unduh dengan tipe konten image/* (misalnya image/jpeg , image/png , dll) akan diurai dengan parser blob .
const getBlobUrl = async ( url ) => {
const blob = ( await thwack . get ( url ) ) . data ;
const objectURL = URL . createObjectURL ( blob ) ;
return objectURL ;
} ;Lihat contoh ini berjalan di CodeSandbox.
Perhatikan bahwa Anda dapat menggunakan teknik ini untuk hal lain selain gambar.
Seperti yang Anda lihat, menggunakan responseParserMap adalah cara terbaik untuk menghilangkan kebutuhan untuk mengatur responseType untuk panggilan Thwack yang berbeda.
validateStatus Fungsi opsional ini digunakan untuk menentukan kode status apa yang digunakan Thwack untuk mengembalikan janji atau lemparan. Itu melewati status respons. Jika fungsi ini mengembalikan kebenaran, janji terselesaikan, jika tidak, janji akan ditolak.
Fungsi default muncul untuk status apa pun yang tidak ada di 2xx (yaitu 200-299)
paramsSerializer Ini adalah fungsi opsional yang akan dipanggil Thwack untuk membuat serialisasi params . Misalnya, jika diberi objek {a:1, b:2, foo: 'bar'} , objek tersebut harus diserialkan ke string a=1&b=2&foo=bar .
Bagi kebanyakan orang, serializer default seharusnya berfungsi dengan baik. Ini terutama untuk kompatibilitas edge case dan Axios.
Perhatikan bahwa serializer default mengurutkan parameter berdasarkan abjad, yang merupakan praktik yang baik untuk diikuti. Namun, jika ini tidak berhasil untuk situasi Anda, Anda dapat memutar serializer Anda sendiri.
resolver Ini adalah fungsi yang dapat Anda berikan untuk mengganti perilaku penyelesai default. resolver mengambil dua argumen: url dan baseURL yang harus tidak ditentukan, atau URL absolut. Seharusnya tidak ada alasan bagi Anda untuk mengganti penyelesai, tetapi ini adalah jalan keluar jika diperlukan.
status number yang mewakili 3 digit kode status HTTP yang diterima.
ok boolean yang disetel ke true adalah kode status dalam rentang 2xx (yaitu sukses). Nilai ini tidak dipengaruhi oleh validateStatus .
statusText Sebuah string yang mewakili teks kode status . Anda harus menggunakan kode status (atau ok ) dalam logika program apa pun.
headersObjek kunci/nilai dengan header HTTP yang dikembalikan. Setiap header duplikat akan digabungkan menjadi satu header yang dipisahkan dengan titik koma.
data Ini akan menyimpan isi respons HTTP yang dikembalikan setelah dialirkan dan dikonversi. Satu-satunya pengecualian adalah jika Anda menggunakan responseType dari stream , dalam hal ini data disetel langsung ke elemen body .
Jika ThwackResponseError dilempar, data akan menjadi representasi teks biasa dari isi respons.
options Objek options lengkap yang memproses permintaan. options ini akan sepenuhnya digabungkan dengan instance induk mana pun, serta dengan defaults .
response Objek Response HTTP lengkap seperti yang dikembalikan oleh fetch atau response dari panggilan balik peristiwa sintetis.
Jika respon dari permintaan Thwack menghasilkan kode status non-2xx (misalnya 404 Not Found) maka ThwackResponseError akan dilempar.
Catatan: Ada kemungkinan bahwa jenis kesalahan lain dapat terjadi (misalnya callback pendengar peristiwa yang buruk), jadi praktik terbaiknya adalah menginterogasi kesalahan yang tertangkap untuk melihat apakah kesalahan tersebut bertipe
ThwackResponseError.
try {
const { data } = await thwack . get ( someUrl )
} catch ( ex ) {
if ( ex instanceof thwack . ThwackResponseError )
const { status , message } = ex ;
console . log ( `Thwack status ${ status } : ${ message } ` ) ;
} else {
throw ex ; // If not, rethrow the error
}
} ThwackResponseError memiliki semua properti dari JavaScript Error normal ditambah properti thwackResponse dengan properti yang sama dengan status sukses.
Instance yang dibuat di Thwack didasarkan pada instance induknya. Opsi default orang tua diturunkan melalui instance. Ini berguna untuk menyiapkan opsi di induk yang dapat memengaruhi turunan, seperti baseURL ,
Sebaliknya, orang tua dapat menggunakan addEventListener untuk memantau anak-anak mereka (lihat Cara mencatat setiap panggilan API di bawah untuk contohnya).

Dikombinasikan dengan instance, sistem event Thwack inilah yang membuat Thwack sangat kuat. Dengan itu, Anda dapat mendengarkan berbagai acara.
Berikut adalah alur acara untuk semua acara. SEPERTI yang Anda lihat, ada kemungkinan kode Anda masuk ke loop tanpa akhir, jika panggilan balik Anda secara membabi buta mengeluarkan request() tanpa memeriksa apakah sudah melakukannya, jadi berhati-hatilah.

request Setiap kali bagian mana pun dari aplikasi memanggil salah satu metode pengambilan data, peristiwa request akan dipicu. Setiap pendengar akan mendapatkan objek ThwackRequestEvent yang memiliki options panggilan di event.options . Pemroses peristiwa ini dapat melakukan sesuatu yang sederhana seperti (mencatat peristiwa) atau rumit seperti mencegah permintaan dan mengembalikan respons dengan (data tiruan)
// callback will be called for every request made in Thwack
thwack . addEventListener ( 'request' , callback ) ;Perhatikan bahwa callback bisa bersifat
asyncsehingga Anda dapat menunda Thwack sehingga Anda dapat, misalnya, keluar dan mengambil data dari URL yang berbeda sebelum melanjutkan.
response Peristiwa ini dipicu setelah header HTTP diterima, tetapi sebelum isi dialirkan dan diurai. Pendengar akan menerima objek ThwackResponseEvent dengan kunci thwackResponse yang disetel ke responsnya.
data Acara ini dipecat setelah tubuh dialirkan dan diurai. Ini diaktifkan hanya jika pengambilan mengembalikan kode status 2xx. Pendengar akan menerima objek ThwackDataEvent dengan kunci thwackResponse yang disetel ke responsnya.
error Acara ini dipecat setelah tubuh dialirkan dan diurai. Ini diaktifkan jika pengambilan mengembalikan kode status non-2xx. Pendengar akan menerima objek ThwackErrorEvent dengan kunci thwackResponse yang disetel ke responsnya.
Thwack akan berfungsi di NodeJS, tetapi memerlukan polyfill untuk window.fetch . Untungnya, ada polyfill luar biasa bernama node-fetch yang dapat Anda gunakan.
Jika Anda menggunakan NodeJS versi 10, Anda juga memerlukan polyfill untuk Array#flat dan Object#fromEntries . NodeJS versi 11+ memiliki metode ini dan tidak memerlukan polyfill.
Anda dapat menyediakan polyfill ini sendiri, atau menggunakan salah satu dari impor praktis berikut ini. Jika Anda menjalankan NodeJS 11+, gunakan:
import thwack from 'thwack/node' ; // NodeJS version 12+Jika Anda menjalankan NodeJS 10, gunakan:
import thwack from 'thwack/node10' ; // NodeJS version 10 Jika Anda ingin menyediakan polyfill ini sendiri, maka untuk menggunakan Thwack, Anda harus mengimpor dari thwack/core dan menyetel fetch sebagai default untuk fetch .
import thwack from 'thwack/code' ;
thwack . defaults . fetch = global . fetch ; Ini harus dilakukan di kode startup aplikasi Anda, biasanya index.js .
Catatan:
responseTypeblobtidak didukung di NodeJS.
Thwack kompatibel dengan React Native dan tidak memerlukan polyfill tambahan. Lihat di bawah untuk contoh aplikasi yang ditulis dalam React Native.
Catatan: React Native tidak mendukung
streamkarena #27741
Anda dapat menggunakan thwack.all() dan thwack.spread() untuk membuat permintaan secara bersamaan. Data kemudian disajikan ke panggilan balik Anda sebagai satu larik.
Di sini kami menampilkan informasi untuk dua pengguna GitHub.
function displayGitHubUsers ( ) {
return thwack
. all ( [
thwack . get ( 'https://api.github.com/users/donavon' ) ,
thwack . get ( 'https://api.github.com/users/revelcw' ) ,
] )
. then (
thwack . spread ( ( ... results ) => {
const output = results
. map (
( { data } ) => ` ${ data . login } has ${ data . public_repos } public repos`
)
. join ( 'n' ) ;
console . log ( output ) ;
} )
) ;
} Perhatikan bahwa ini hanyalah fungsi pembantu. Jika Anda menggunakan async / await Anda dapat menulis ini tanpa bantuan Thwack menggunakan Promise.all .
async function displayGitHubUsers ( ) {
const results = await Promise . all ( [
thwack . get ( 'https://api.github.com/users/donavon' ) ,
thwack . get ( 'https://api.github.com/users/revelcw' ) ,
] ) ;
const output = results
. map ( ( { data } ) => ` ${ data . login } has ${ data . public_repos } public repos` )
. join ( 'n' ) ;
console . log ( output ) ;
}Anda dapat melihatnya berjalan langsung di CodeSandbox.
(Demo terinspirasi oleh postingan blob ini di axios/fetch)
Gunakan AbortController untuk membatalkan permintaan dengan meneruskan signal di opsi thwack .
Di browser, Anda dapat menggunakan AbortController bawaan.
import thwack from 'thwack' ;
const controller = new AbortController ( ) ;
const { signal } = controller ;
thwack ( url , { signal } ) . then ( handleResponse ) . catch ( handleError ) ;
controller . abort ( ) ;Di NodeJS, Anda dapat menggunakan sesuatu seperti abort-controller.
import thwack from 'thwack' ;
import AbortController from 'abort-controller' ;
const controller = new AbortController ( ) ;
const { signal } = controller ;
thwack ( url , { signal } ) . then ( handleResponse ) . catch ( handleError ) ;
controller . abort ( ) ; Jika Anda ingin melakukan beberapa tindakan pada pembatalan permintaan, Anda juga dapat mendengarkan acara abort pada signal :
signal . addEventListener ( 'abort' , handleAbort ) ; Tambahkan addEventListener('request', callback) dan catat setiap permintaan ke konsol.
import thwack from 'thwack' ;
thwack . addEventListener ( 'request' , ( event ) => {
console . log ( 'hitting URL' , thwack . getUri ( event . options ) ) ;
} ) ;Jika Anda menggunakan React, berikut adalah Hook yang dapat Anda "gunakan" di Aplikasi Anda yang akan menghasilkan hal yang sama.
import { useEffect } from 'react' ;
import thwack from 'thwack' ;
const logUrl = ( event ) => {
const { options } = event ;
const fullyQualifiedUrl = thwack . getUri ( options ) ;
console . log ( `hitting ${ fullyQualifiedUrl } ` ) ;
} ;
const useThwackLogger = ( ) => {
useEffect ( ( ) => {
thwack . addEventListener ( 'request' , logUrl ) ;
return ( ) => thwack . removeEventListener ( 'request' , logUrl ) ;
} , [ ] ) ;
} ;
export default useThwackLogger ;Berikut cuplikan kode cara menggunakannya.
const App = ( ) = {
useThwackLogger ( )
return (
< div >
...
</ div >
)
} Katakanlah Anda memiliki aplikasi yang meminta beberapa data pengguna. Jika aplikasi mencapai URL tertentu (misalnya users ) dan menanyakan ID pengguna tertentu (misalnya 123 ), Anda ingin mencegah permintaan tersebut mengenai server dan malah meniru hasilnya.
status di ThwackResponse defaultnya adalah 200, jadi kecuali Anda perlu meniru respons yang tidak OK, Anda hanya perlu mengembalikan data .
thwack . addEventListener ( 'request' , async ( event ) => {
const { options } = event ;
if ( options . url === 'users' && options . params . id === 123 ) {
// tells Thwack to use the returned value instead of handling the event itself
event . preventDefault ( ) ;
// stop other listeners (if any) from further processing
event . stopPropagation ( ) ;
// because we called `preventDefault` above, the caller's request
// will be resolved to this `ThwackResponse` (defaults to status of 200 and ok)
return new thwack . ThwackResponse (
{
data : {
name : 'Fake Username' ,
email : '[email protected]' ,
} ,
} ,
options
) ;
}
} ) ; Seringkali diinginkan untuk mengubah DTO (Data Transfer Object) menjadi sesuatu yang lebih mudah dikonsumsi oleh klien. Dalam contoh di bawah ini, kami mengubah DTO kompleks menjadi firstName , lastName , avatar , dan email . Elemen data lain yang dikembalikan dari panggilan API, namun tidak diperlukan oleh aplikasi, akan diabaikan.
Anda dapat melihat contoh konversi DTO, pencatatan, dan pengembalian data palsu di aplikasi contoh ini.

Anda dapat melihat kode sumber di CodeSandbox.
Dalam contoh ini, kita memiliki React Hook yang memuat gambar sebagai URL Blob. Ini menyimpan URL ke pemetaan URL Blob dalam penyimpanan sesi. Setelah dimuat, setiap penyegaran halaman akan langsung memuat gambar dari URL Blob.
const useBlobUrl = ( imageUrl ) => {
const [ objectURL , setObjectURL ] = useState ( '' ) ;
useEffect ( ( ) => {
let url = sessionStorage . getItem ( imageUrl ) ;
async function fetchData ( ) {
if ( ! url ) {
const { data } = await thwack . get ( imageUrl , {
responseType : 'blob' ,
} ) ;
url = URL . createObjectURL ( data ) ;
sessionStorage . setItem ( imageUrl , url ) ;
}
setObjectURL ( url ) ;
}
fetchData ( ) ;
} , [ imageUrl ] ) ;
return objectURL ;
} ;Lihat contoh ini di CodeSandbox
Saat ini Anda memiliki titik akhir REST di https://api.example.com . Misalkan Anda telah menerbitkan titik akhir REST baru ke URL yang berbeda dan ingin mulai merutekan 2% lalu lintas jaringan secara perlahan ke server baru ini.
Catatan: biasanya ini akan ditangani oleh penyeimbang beban Anda di back-end. Ini ditampilkan di sini untuk tujuan demonstrasi saja.
Kita dapat melakukannya dengan mengganti options.url di pendengar acara permintaan sebagai berikut.
thwack . addEventListener ( 'request' , ( event ) => {
if ( Math . random ( ) >= 0.02 ) {
return ;
}
// the code will be executed for approximately 2% of the requests
const { options } = event ;
const oldUrl = thwack . getUri ( options ) ;
const url = new URL ( '' , oldUrl ) ;
url . origin = 'https://api2.example.com' ; // point the origin at the new servers
const newUrl = url . href ; // Get the fully qualified URL
event . options = { ... event . options , url : newUrl } ; // replace `options`]
} ) ; Selain use-thwack , menulis aplikasi pengambilan data untuk React Native sangatlah mudah.
Lihat seluruh aplikasi yang berjalan di Expo.

Thwack sangat terinspirasi oleh Axios. Terima kasih Matt!
Berlisensi di bawah MIT
Terima kasih kepada orang-orang hebat ini (kunci emoji):
Donavon Barat ? | Jeremy Tice | Yuraima Estevez | Jeremy Bargar | Brooke Scarlett Yalof | Karl Horky | Koji |
Tom Byrer | Ian Sutherland | Blake Yoder | Ryan Hinchey | Miro Dojkic | Santicevic |
Proyek ini mengikuti spesifikasi semua kontributor. Kontribusi apa pun diterima!