Anatomi sebuah request

Method, URL, header, dan body, serta apa yang benar-benar diterima server.

Di pelajaran sebelumnya Anda mengirim request dengan mengetik URL di browser. Browser mengisi semua sisanya untuk Anda. Pelajaran ini membongkar sebuah request agar Anda tahu apa saja bagiannya, karena setiap tes yang Anda tulis akan mengatur sebagian bagian itu dengan sengaja lalu memeriksa reaksi server.

Request HTTP punya empat bagian:

  • method, yang menyebut jenis tindakan yang Anda inginkan
  • URL, yang menyebut pada benda apa, di server mana, tindakan itu dilakukan
  • header, yang membawa informasi tambahan tentang request
  • body opsional, yang membawa data yang Anda kirim

Seperti apa request di jaringan

HTTP/1.1 adalah protokol teks. Sebelum dienkripsi, sebuah request hanyalah beberapa baris teks biasa. Ini request yang dikirim curl untuk https://api.testingapis.com/api/echo?color=red. Anda bisa melihatnya sendiri dengan menjalankan curl dengan -v (verbose): baris yang diawali > adalah yang terkirim.

Request mentah
GET /api/echo?color=red HTTP/1.1
Host: api.testingapis.com
User-Agent: curl/8.18.0
Accept: */*

Baris pertama adalah baris request: method, path beserta query string-nya, dan versi protokol. Setiap baris sesudahnya adalah header, berupa nama dan nilai yang dipisahkan titik dua. Baris kosong mengakhiri header. Jika ada body, ia datang setelah baris kosong itu. Versi HTTP yang lebih baru (HTTP/2 dan HTTP/3) mengirim informasi yang sama dalam format biner, tetapi bagian-bagiannya identik, dan setiap alat tetap menampilkannya kepada Anda dalam bentuk teks ini.

Melihat apa yang diterima server

Cara termudah mempelajari request adalah mengirimnya ke server yang memberi tahu apa yang ia terima. /api/echo melakukan persis itu. Ia menerima method apa pun dan membalas dengan deskripsi request Anda. Kirim yang ini:

GET/api/echo?color=red&size=10

Berikut balasan untuk curl, dipangkas ke field yang menarik. Jika Anda mengirimnya dari halaman, header-nya akan menjadi header browser Anda.

JSON
{
  "method": "GET",
  "url": "http://api.testingapis.com/api/echo?color=red&size=10",
  "path": "/api/echo",
  "queryString": "?color=red&size=10",
  "query": { "color": "red", "size": "10" },
  "headers": {
    "Accept": "*/*",
    "Host": "api.testingapis.com",
    "User-Agent": "curl/8.18.0",
    "Accept-Encoding": "gzip, br",
    "Cf-Ipcountry": "IN",
    "X-Forwarded-For": "203.0.113.7, 172.71.198.178, 10.30.107.46",
    "X-Forwarded-Proto": "https"
  },
  "contentType": null,
  "contentLength": 0,
  "body": null
}

Ada dua hal yang layak dilihat lagi. Server melihat URL-nya sebagai http://, bukan https://. Dan ia menerima header yang tidak pernah Anda kirim, seperti Cf-Ipcountry dan X-Forwarded-For. Request Anda melewati CDN dan load balancer sebelum sampai ke aplikasi, dan masing-masing menulis ulang atau menambahkan sesuatu. Alamat pertama di X-Forwarded-For adalah alamat Anda (yang di atas hanya contoh). Ini normal di sistem produksi, dan itulah alasan endpoint echo berguna: ia menunjukkan apa yang tiba, bukan apa yang Anda kira Anda kirim.

Method

Method adalah kata kerjanya. GET meminta data. POST mengirim data untuk membuat sesuatu. PUT, PATCH, dan DELETE mengubah atau menghapus sesuatu. Bilah alamat browser hanya bisa mengirim GET, karena itu Anda butuh alat lain untuk sisanya. Method punya pelajarannya sendiri, Method HTTP, jadi untuk sekarang cukup ketahui bahwa URL yang sama bisa melakukan hal berbeda tergantung method-nya.

URL

Pecah URL ini menjadi bagian-bagiannya:

URL
https://api.testingapis.com/api/Products?category=books&limit=5
BagianNilaiArti
SkemahttpsCara terhubung. https adalah HTTP di dalam koneksi terenkripsi.
Hostapi.testingapis.comServer mana. Juga dikirim sebagai header Host.
Path/api/ProductsResource mana di server itu.
Query stringcategory=books&limit=5Parameter tambahan, setelah ?, dipisahkan &.

URL juga bisa membawa port (:8080 setelah host) dan fragment (#section di akhir). Anda akan sering melihat port di lingkungan uji dan lokal. Fragment tidak pernah sampai ke server sama sekali: browser menyimpannya.

Parameter path dan parameter query

Nilai bisa dibawa di path atau di query string. Di /api/Products/1, 1 adalah parameter path. Ia menunjuk satu produk tertentu, dan dokumentasi menulis path-nya sebagai /api/Products/{id}. Di /api/Products?limit=5, limit adalah parameter query. Parameter query biasanya menyaring, mengurutkan, atau membagi hasil per halaman, dan biasanya opsional. Pembagian itu konvensi, bukan aturan, jadi periksa dokumentasi setiap API.

Path sering membedakan huruf besar dan kecil, dan nama parameter query biasanya juga. Itu tergantung framework server, jadi lakukan tes cepat pada setiap API baru: kirim /api/products alih-alih /api/Products dan lihat apa yang terjadi.

Percent-encoding

Beberapa karakter punya tugas di dalam URL. ? memulai query string, & memisahkan parameter, # memulai fragment, / memisahkan segmen path, dan spasi sama sekali tidak diizinkan. Untuk mengirim salah satunya sebagai data, Anda menggantinya dengan % dan nilai heksadesimal byte-nya. Spasi menjadi %20 dan & menjadi %26. Ini disebut percent-encoding, atau URL encoding.

Misalnya Anda ingin mencari "red shoes" dan menyaring dengan tag yang nilainya persis teks a&b. Jika di-encode, ini berhasil:

GET/api/echo?q=red%20shoes&tag=a%26b
Response yang dipangkas
{
  "queryString": "?q=red%20shoes&tag=a%26b",
  "query": { "q": "red shoes", "tag": "a&b" }
}

Sekarang kirim tag-nya tanpa meng-encode ampersand:

GET/api/echo?tag=a&b
Response yang dipangkas
{
  "queryString": "?tag=a&b",
  "query": { "tag": "a", "b": "" }
}

Kini server melihat dua parameter: tag dengan nilai a, dan parameter kosong bernama b. Tidak ada error, tidak ada peringatan. Request-nya "berhasil" dan datanya salah. Ini kelompok bug nyata pada klien yang membangun URL dengan menempelkan string, dan itulah sebabnya kolom pencarian adalah tempat yang bagus untuk mengetik ampersand, tanda plus, garis miring, dan teks non-Inggris saat pengujian. URL encoder di situs ini melakukan konversinya jika Anda perlu melakukannya secara manual.

Header

Header adalah pasangan nama dan nilai yang mendeskripsikan request. Nama header tidak membedakan huruf besar dan kecil, jadi content-type dan Content-Type berarti sama. Sebagian besar klien menambahkan beberapa header secara otomatis. Yang paling sering akan Anda atur atau periksa adalah ini:

HeaderYang dinyatakanContoh
Content-TypeFormat body yang Anda kirim.application/json
AcceptFormat yang bersedia Anda terima.application/json
User-AgentKlien mana yang mengirim request.curl/8.18.0
AuthorizationKredensial, misalnya token.Bearer abc123
HostSitus mana di server. Klien mengisinya dari URL.api.testingapis.com

Accept penting saat API bisa menjawab dalam lebih dari satu format. /api/formats/negotiatemasuk untuk melihat mengembalikan pengguna yang sama sebagai JSON secara bawaan, dan sebagai XML jika Anda memintanya:

GET/api/formats/negotiate
Request ini memakai endpoint untuk anggota yang sudah masuk.MasukBuat akun gratis

Bandingkan XML itu dengan JSON yang Anda dapat tanpa header tersebut. Keduanya membawa tujuh field yang sama, ditulis dengan cara masing-masing format: daftar roles menjadi elemen role yang berulang, dan manager yang null menjadi elemen kosong bertanda xsi:nil. Saat API menawarkan beberapa format, uji masing-masing dan jangan berasumsi semuanya cocok. Saat pelajaran ini pertama kali ditulis, versi XML pengguna ini kehilangan tiga field.

Authorization dibahas lengkap di Autentikasi dan otorisasi. Satu hal yang perlu diketahui sejak sekarang: jangan pernah menempelkan token asli ke tangkapan layar, laporan bug, atau koleksi yang dibagikan. Token itu kata sandi.

Body

Request GET biasanya tidak punya body. POST, PUT, dan PATCH biasanya punya, karena mereka mengirim data ke server. Body bisa dalam format apa saja, dan header Content-Type memberi tahu server cara membacanya. Di sebagian besar API saat ini, body-nya JSON. Perintah ini mengirim objek JSON kecil ke endpoint echo dengan curl:

Terminal
curl -X POST https://api.testingapis.com/api/echo \
  -H "Content-Type: application/json" \
  -d '{"title":"Dune","year":1965}'
Response yang dipangkas
{
  "method": "POST",
  "path": "/api/echo",
  "query": {},
  "contentType": "application/json",
  "contentLength": 28,
  "body": "{\"title\":\"Dune\",\"year\":1965}",
  "json": { "title": "Dune", "year": 1965 }
}

Server membaca header-nya, melihat application/json, lalu mem-parse 28 byte itu menjadi objek. Anda bisa mengirim request yang sama dari sini:

POST/api/echo
{"title":"Dune","year":1965}

Saat Content-Type dan body tidak cocok

Sekarang kirim body sejenis dengan curl, tetapi tanpa header itu:

Terminal
curl -X POST https://api.testingapis.com/api/echo \
  -d '{"title":"Dune"}'
Response yang dipangkas
{
  "contentType": "application/x-www-form-urlencoded",
  "contentLength": 16,
  "body": "{\"title\":\"Dune\"}",
  "json": null,
  "form": { "{\"title\":\"Dune\"}": "" }
}

Opsi -d milik curl secara bawaan memakai application/x-www-form-urlencoded, format yang dipakai formulir HTML. Server memercayai header-nya, mencoba membaca body sebagai formulir, dan berakhir dengan satu field formulir yang namanya adalah seluruh teks JSON. Tidak ada error yang kembali. Banyak server sungguhan berperilaku sama, dan yang lain mengembalikan 415 Unsupported Media Type. Content-Typeyang hilang atau salah adalah salah satu alasan paling umum sebuah request "terlihat benar" tetapi tetap gagal, jadi itulah hal pertama yang diperiksa saat server mengabaikan data Anda.

Jika header-nya benar tetapi JSON-nya rusak, server yang baik akan mengatakannya. Berikut sebagian response echo untuk body {"title":"Dune",}, yang punya koma berlebih di akhir:

Response yang dipangkas
"json": null,
"jsonError": "The JSON object contains a trailing comma at the end which is not supported in this mode. Change the reader options. LineNumber: 0 | BytePositionInLine: 16."

Latihan

Gunakan /api/echo untuk menjawab setiap pertanyaan. Lihat response-nya setiap kali, jangan menebak.

  • Kirim /api/echo?name=Zoë&city=São Paulo dari bilah alamat browser Anda. Apa yang diubah browser pada URL sebelum mengirimnya, dan menjadi apa server men-decode-nya?
  • Kirim /api/echo?id=1&id=2. Bagaimana server merepresentasikan parameter yang muncul dua kali? Framework yang berbeda tidak sepakat soal ini, sehingga ini pertanyaan yang bagus untuk setiap API yang Anda uji.
  • Kirim POST dengan body JSON dan Content-Type: text/plain. Apakah server tetap mem-parse JSON-nya?
  • Coba /api/echo/user-agent dari browser dan dari curl. Mengapa sebuah API peduli mana yang Anda gunakan?

Berlatih dan melangkah lebih jauh