QA 10: API testing (1) — REST, JSON, status kodlar va Postman amaliyoti
🧪 QA Engineer — Zero to Hero
QA 10: API testing (1) — REST, JSON, status kodlar va Postman amaliyoti
Holat: 2026-yil oktabr. Bu darsda REST API'ning tuzilishi, method'lar, status kodlar, JSON va autentifikatsiya asoslarini o'rganamiz, so'ng
curlva Postman bilan haqiqiy API'ni testlaymiz. Postman bo'yicha ma'lumotlar Postman Docs'ning joriy (v12) versiyasiga asoslangan; darsdagi Postman collection'i Newman 6.2.3 bilan restful-booker'ga qarshi ishga tushirilib, 18 ta assertion'ning hammasi o'tgani tekshirilgan.
Bu darsdan keyin siz: istalgan REST API hujjatini o'qib, uni
curlva Postman bilan mustaqil testlay olasiz.
- method, status kod va header'larni "ko'rib turib" tushunasiz;
- JSON va so'rov qismlarini (path, query, header, body) to'g'ri tuza olasiz;
- API key, Basic, Bearer/JWT va cookie autentifikatsiyasini farqlaysiz;
- Postman'da collection, environment, variable va skriptlar bilan to'liq CRUD testini yozasiz;
- testlarni Newman bilan terminalda (va keyinchalik CI'da) ishga tushirasiz.
Mundarija
- API nima va QA uchun nega muhim
- REST printsiplari va endpoint dizayni
- Method'lar, CRUD va idempotentlik
- Status kodlar — QA uchun to'liq jadval
- JSON asoslari
- So'rov qismlari: path, query, header, body
- Autentifikatsiya asoslari
- Swagger / OpenAPI hujjatini o'qish
- curl bilan birinchi API testlar
- Postman asoslari: collection, environment, variable
- Postman skriptlari: Pre-request va Post-response
- Collection Runner va data-driven testlar
- Newman — Postman'ni terminalda ishga tushirish
- restful-booker g'alatiliklari: bug'mi yoki xususiyat?
- Amaliy mashqlar
- Xulosa
- Manbalar
1. API nima va QA uchun nega muhim {#api-nima}
API (Application Programming Interface) — dasturlar bir-biri bilan gaplashadigan "shartnoma". Restoran menyusiga o'xshaydi: menyuda nima buyurish mumkinligi (endpoint'lar), qanday so'rash (method, parametrlar) va nima olib kelinishi (javob formati) yozilgan. Oshxona ichida nima bo'layotganini mijoz bilmaydi va bilishi shart ham emas.
DemoBozor'da web sayt, iOS va Android ilova — uchalasi ham bitta API'ga murojaat qiladi. Demak, API'dagi bitta bug uchta platformada birdaniga bug bo'lib chiqadi. Shuning uchun API testlash QA uchun eng foydali ko'nikmalardan biri:
| UI orqali testlash | API orqali testlash |
|---|---|
| Sekin: sahifa yuklanishi, animatsiyalar | Tez: bitta so'rov — millisekundlar |
| UI o'zgarsa test buziladi | API shartnomasi kamroq o'zgaradi |
| Faqat UI ruxsat bergan qiymatlarni kiritasiz | Istalgan qiymatni yuborasiz (manfiy narx, 10 000 belgilik ism) |
| Bug'ning qaysi qatlamda ekanini aniqlash qiyinroq | Back-end'ni to'g'ridan-to'g'ri tekshirasiz |
API turlari: REST (eng keng tarqalgan, bu darsning mavzusi), GraphQL, gRPC, eski tizimlarda SOAP, real vaqt uchun WebSocket. GraphQL, WebSocket va gRPC'ning QA uchun xususiyatlari QA 11 da.
🎯 Intervyuda: "Nega API testlash kerak, UI testlar yetmaydimi?" — API testlar tezroq, barqarorroq, back-end mantiqni UI cheklovlarisiz tekshiradi va bug'ni aniq qatlamga bog'laydi. Test piramidasida ular UI testlardan pastda, ya'ni ko'proq bo'lishi kerak.
2. REST printsiplari va endpoint dizayni {#rest}
REST (Representational State Transfer) — Roy Fielding 2000-yilda dissertatsiyasida ta'riflagan arxitektura uslubi. QA uchun eng muhim g'oyalari:
- Resurs — har bir "narsa" (mahsulot, buyurtma, foydalanuvchi) o'z manziliga (URI) ega:
/products/1042. - Representation — resurs odatda JSON ko'rinishida uzatiladi.
- Bir xil interfeys — resurs ustidagi amal HTTP method bilan ifodalanadi, URL'da fe'l bo'lmaydi.
- Stateless — har bir so'rov o'zi uchun kerakli hamma narsani (masalan, token) olib keladi; server oldingi so'rovni "eslamaydi".
- Client-server, keshlanadigan, qatlamli tizim — client server ichini bilmaydi, javoblar keshlanishi mumkin, oraliqda proxy/CDN bo'lishi mumkin.
Yaxshi va yomon endpoint'lar
| Yomon | Yaxshi (REST uslubi) | Izoh |
|---|---|---|
GET /getProducts | GET /products | Fe'l method'da, URL'da ot |
POST /deleteOrder?id=5 | DELETE /orders/5 | Amal turi — method |
GET /product/5 va GET /products | GET /products/5 va GET /products | Bir xil ko'plik shakli |
GET /orders/5/getItems | GET /orders/5/items | Ichma-ich resurs |
/v1products | /api/v1/products | Versiya alohida segmentda |
QA nuqtai nazaridan endpoint nomlari "go'zallik" emas: aralash uslub — hujjat va SDK'larda xatolarga, dasturchilar orasida noto'g'ri tushunishga olib keladi. Yangi API dizaynini review qilishda bunday nomuvofiqliklarni ko'rsating.
3. Method'lar, CRUD va idempotentlik {#methods}
API so'rovi va javobining anatomiyasi hamda method, CRUD va idempotentlik jadvali
| Method | CRUD | Safe | Idempotent | Odatiy muvaffaqiyat kodi | Body |
|---|---|---|---|---|---|
GET | Read | ✅ | ✅ | 200 | Yo'q |
POST | Create | ❌ | ❌ | 201 (+ Location) | Bor |
PUT | Update (to'liq almashtirish) | ❌ | ✅ | 200 yoki 204 | Bor |
PATCH | Update (qisman) | ❌ | Kafolatlanmaydi | 200 yoki 204 | Bor |
DELETE | Delete | ❌ | ✅ | 200 yoki 204 | Odatda yo'q |
HEAD | Faqat header'lar | ✅ | ✅ | 200 | Yo'q |
OPTIONS | Ruxsat etilgan method'lar, CORS preflight | ✅ | ✅ | 200/204 | Yo'q |
- Safe — server holatini o'zgartirmaydi (faqat o'qiydi).
- Idempotent — bir xil so'rovni 1 marta yoki 10 marta yuborish server holatiga bir xil ta'sir qiladi.
DELETE /cart/items/7ikki marta yuborilsa ham, natijada element baribir o'chgan bo'ladi.
QA uchun amaliy oqibat: tarmoq uzilib, ilova so'rovni avtomatik qayta yuborsa, idempotent bo'lmagan POST /orders ikkita buyurtma yaratishi mumkin. Real misol: restful-booker'ga bir xil POST /booking ni ikki marta yuborganimizda ikki xil bookingid (1611 va 1623) qaytdi — ya'ni ikkita booking yaratildi. Booking yoki to'lov uchun bu jiddiy risk. Ba'zi API'lar (ayniqsa to'lov tizimlari) buning oldini olish uchun mijozdan Idempotency-Key kabi header kutadi — loyihangizda shunday mexanizm bormi, so'rang va testlang.
PUT va PATCH farqi
PUT— resursni to'liq almashtiradi: nazariyada yuborilmagan ixtiyoriy maydon o'chishi yoki standart qiymatga qaytishi kerak.PATCH— faqat yuborilgan maydonlarni o'zgartiradi.
restful-booker'da tekshirdik: PATCH bilan faqat {"firstname":"Bobur"} yuborilganda boshqa maydonlar joyida qoldi — to'g'ri. Lekin PUT da additionalneeds maydoni yuborilmaganida ham u "Breakfast" bo'lib saqlanib qoldi — ya'ni bu API'da PUT aslida "birlashtirish" (merge) kabi ishlaydi. Bu hujjat va HTTP semantikasi bo'yicha savol: jamoangiz qaysi xatti-harakatni kutishini aniqlab, test'ni shunga yozing.
4. Status kodlar — QA uchun to'liq jadval {#status-codes}
| Kod | Nomi | Qachon | DemoBozor misoli | QA eslatmasi |
|---|---|---|---|---|
200 | OK | Muvaffaqiyatli o'qish/yangilash | GET /products/1042 | Body'ni ham tekshiring — 200 ichida xato bo'lishi mumkin |
201 | Created | Yangi resurs yaratildi | POST /orders | Location header'i bormi |
204 | No Content | Muvaffaqiyat, body yo'q | DELETE /cart/items/7 | Body bo'sh bo'lishi kerak |
301 / 302 | Moved / Found | Yo'naltirish | http:// → https:// | Yo'naltirish zanjiri cheksiz emasmi |
304 | Not Modified | Kesh hamon dolzarb | If-None-Match bilan GET | QA 9 dagi kesh tajribasi |
400 | Bad Request | So'rov noto'g'ri tuzilgan | Buzilgan JSON | Xato xabari tushunarlimi |
401 | Unauthorized | Autentifikatsiya yo'q yoki yaroqsiz | Token yo'q/muddati o'tgan | "Kimligingiz noma'lum" |
403 | Forbidden | Kimligingiz ma'lum, lekin ruxsat yo'q | Xaridor admin endpoint'iga | "Siz kimligingizni bilaman, lekin mumkin emas" |
404 | Not Found | Resurs yo'q | GET /orders/999999 | Boshqa birovning resursi uchun ham 404 qaytarish mumkin (ma'lumot oshkor bo'lmasligi uchun) |
405 | Method Not Allowed | Bu resursda bu method yo'q | DELETE /products | Javobda Allow header'i bo'lishi kerak |
409 | Conflict | Holat ziddiyati | Ro'yxatdan o'tgan telefon bilan qayta ro'yxat | Xabar aniq bo'lsin |
415 | Unsupported Media Type | Body formati qo'llab-quvvatlanmaydi | JSON o'rniga text/plain | 500 emas, aynan 415 kutiladi |
422 | Unprocessable Content | Format to'g'ri, qiymatlar qoidaga zid | quantity: 120 (ruxsat 1–99) | Qaysi maydon xato — javobda ko'rsatilsinmi |
429 | Too Many Requests | Limitdan oshdi | 3 noto'g'ri SMS kod | Retry-After header'i bormi |
500 | Internal Server Error | Serverda kutilmagan xato | Har qanday ishlov berilmagan holat | Deyarli har doim bug; stack trace oshkor bo'lmasin |
502 | Bad Gateway | Proxy orqadagi xizmatdan yaroqsiz javob oldi | API konteyneri qulagan | Infra bilan birga ko'riladi |
503 | Service Unavailable | Vaqtincha ishlamaydi | Texnik ishlar | Retry-After bo'lishi mumkin |
504 | Gateway Timeout | Proxy javobni kutib charchadi | Sekin hisobot so'rovi | Timeout chegaralari |
🧠 Esda tuting:
401= "siz kimsiz?",403= "kimligingizni bilaman, lekin ruxsat yo'q". Toolshop API'da buni o'zingiz ko'rasiz: tokensizGET /users/me→401, oddiy xaridor tokeni bilan admin'ga tegishliGET /users→403(QA 11).
🎯 Intervyuda: "
400va422farqi?" —400: so'rovni umuman tushunib bo'lmaydi (buzilgan JSON, noto'g'ri sintaksis).422: so'rov to'g'ri tuzilgan, lekin qiymatlar biznes qoidalariga zid (masalan, miqdor 1–99 oralig'idan tashqarida). Ko'p jamoalar400ni ikkalasi uchun ham ishlatadi — muhimi, API ichida izchil bo'lsin.
5. JSON asoslari {#json}
JSON — API'larning asosiy ma'lumot formati. Atigi 6 ta tip bor:
| Tip | Misol |
|---|---|
| string | "Choynak 1.7 L" |
| number | 450000, 4.5 |
| boolean | true, false |
| null | null |
| object | {"id": 1042, "name": "Choynak"} |
| array | [1, 2, 3] |
DemoBozor buyurtmasi JSON'da (xayoliy):
{
"id": 58231,
"status": "PAID",
"paymentMethod": "UZCARD",
"promoCode": null,
"items": [
{
"productId": 1042,
"name": "Elektr choynak",
"quantity": 1,
"unitPrice": 289000
},
{
"productId": 2210,
"name": "Paxta ko'ylak",
"quantity": 2,
"unitPrice": 95000
}
],
"subtotal": 479000,
"deliveryFee": 0,
"total": 479000,
"createdAt": "2026-10-09T14:05:00+05:00"
}
QA nimaga e'tibor beradi:
- Tip:
"quantity": "2"(string) va"quantity": 2(number) — boshqa-boshqa narsa. Front-end"2" + 1qilsa"21"chiqadi. - **
null, yo'q maydon va bo'sh qator** — uch xil holat:"promoCode": null,promoCodeumuman yo'q,"promoCode": "". API hujjati qaysi biri qachon bo'lishini aytishi kerak. - Sana formati — ISO 8601 va vaqt zonasi (
+05:00, Toshkent). Zona yo'q sanalar — klassik bug manbai. - Pul — so'mni butun son sifatida saqlash (
289000) xavfsizroq; kasr sonlar yaxlitlash xatolariga olib kelishi mumkin. - Sintaksis xatolari: oxirgi elementdan keyin vergul, bitta qo'shtirnoq (
'name'), izoh (// ...) — JSON'da bularning hammasi taqiqlangan.
6. So'rov qismlari: path, query, header, body {#request-parts}
PATCH https://api.demobozor.example/api/v1/cart/items/7?notify=false
└──────────── host ─────┘└──── path ────────┘└─ query ──┘
Headers: Authorization: Bearer <token>
Content-Type: application/json
Body: {"quantity": 3}
| Qism | Nima uchun | Misol |
|---|---|---|
| Path parametr | Aniq resursni ko'rsatish | /booking/{id} → /booking/252 |
| Query parametr | Filtr, saralash, sahifalash | ?firstname=Aziz&lastname=Karimov |
| Header | Metama'lumot: format, auth, til | Content-Type, Authorization, Accept-Language |
| Body | Yaratiladigan/o'zgaradigan ma'lumot | JSON, form-data, fayl |
Body turlari: application/json (eng ko'p), application/x-www-form-urlencoded (oddiy web formalar), multipart/form-data (fayl yuklash). **Content-Type header'i body turiga mos bo'lishi shart** — aks holda server body'ni o'qiy olmaydi. Real tajriba: restful-booker'ga to'g'ri JSON'ni Content-Type: text/plain bilan yuborsangiz, 500 Internal Server Error qaytadi (14-bo'lim).
Accept header'i esa client qaysi formatda javob kutishini aytadi: restful-booker'da Accept: application/xml bilan GET /booking/{id} XML qaytaradi.
7. Autentifikatsiya asoslari {#auth}
Autentifikatsiya — "siz kimsiz?" savoli; avtorizatsiya — "sizga nima mumkin?" savoli. API'larda eng ko'p uchraydigan usullar:
| Usul | Qanday yuboriladi | Misol | QA eslatmasi |
|---|---|---|---|
| API key | Header yoki query | X-API-Key: abc123 | Kalit URL'da bo'lsa, loglarda qolib ketadi |
| Basic | Authorization: Basic base64(login:parol) | restful-booker PATCH | Base64 — shifrlash emas |
| Bearer token | Authorization: Bearer <token> | Toolshop API | Token muddati, bekor qilinishi |
| Cookie | Cookie: token=... | restful-booker PUT/DELETE | Cookie atributlari (QA 9) |
| OAuth 2.0 | Token avtorizatsiya serveri orqali olinadi | "Google bilan kirish" | Oqimlar: authorization code (+PKCE), client credentials |
Base64 — shifr emas
echo 'YWRtaW46cGFzc3dvcmQxMjM=' | base64 -d
# admin:password123
restful-booker hujjatidagi Basic header'i bir buyruq bilan ochildi. Shuning uchun Basic faqat HTTPS ustida ishlatilishi kerak.
JWT tuzilishi
Ko'p Bearer token'lar JWT (JSON Web Token): nuqta bilan ajratilgan uch qism — header.payload.signature. Header va payload — base64url'da kodlangan oddiy JSON, ya'ni shifrlanmagan; signature esa token o'zgartirilmaganini tasdiqlaydi.
Toolshop API'dan olingan haqiqiy token'ni o'z kompyuteringizda ochamiz:
TOKEN=$(curl -s -X POST https://api.practicesoftwaretesting.com/users/login \
-H 'Content-Type: application/json' -H 'Accept: application/json' \
-d '{"email":"customer@practicesoftwaretesting.com","password":"welcome01"}' \
| node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).access_token))')
node -e 'const p = process.argv[1].split(".")[1]; console.log(JSON.parse(Buffer.from(p, "base64url").toString()))' "$TOKEN"
# {
# iss: 'https://api.practicesoftwaretesting.com/users/login',
# iat: 1791566303,
# exp: 1791566603,
# ...
# role: 'user'
# }
exp - iat = 300 — token atigi 5 daqiqa yashaydi. Bundan darhol test g'oyalari chiqadi: 5 daqiqadan keyin so'rov nima qaytaradi (401 kutiladi)? Ilova token'ni avtomatik yangilaydimi (refresh)? Payload'dagi role qiymatini o'zgartirib yuborsak, server signature'ni tekshirib rad etadimi (QA 11)?
⚠️ Diqqat: Real (production yoki ishxona) token'ini jwt.io kabi onlayn dekoderlarga joylamang — u amal qilish muddati davomida sizning nomingizdan kirish kaliti. Yuqoridagidek lokal buyruq bilan oching.
8. Swagger / OpenAPI hujjatini o'qish {#openapi}
OpenAPI — REST API'ni mashina o'qiy oladigan formatda (YAML/JSON) tasvirlash standarti. Swagger UI shu faylni interaktiv sahifaga aylantiradi. Toolshop API hujjati, masalan, OpenAPI 3.2.0 formatida yozilgan (2026-yil oktabr holati).
Mashq uchun klassik Swagger Petstore'ni oching: https://petstore.swagger.io (Swagger 2.0) yoki https://petstore3.swagger.io (OpenAPI 3). Hujjatda nimani qidiramiz:
| Hujjat qismi | Petstore'dagi misol | Undan qanday test chiqadi |
|---|---|---|
| Tag'lar (guruhlar) | pet, store, user | Qamrov rejasini guruhlarga bo'lish |
| Endpoint | GET /pet/{petId} | Har endpoint uchun test to'plami |
| Parametr | petId — path, integer, int64, majburiy | abc, -1, 0, juda katta son |
| Enum | findByStatus: available, pending, sold | Ro'yxatdan tashqari qiymat |
| Majburiy maydonlar | Pet modelida name, photoUrls | Har birisiz yuborish |
| Javoblar | 200, 400 Invalid ID supplied, 404 Pet not found | Har bir kod uchun alohida test |
| Xavfsizlik | api_key, petstore_auth (OAuth) | Kalitsiz/noto'g'ri kalit bilan |
| "Try it out" | So'rovni brauzerdan yuborish | Tez qo'lda tekshiruv |
Real topilma (2026-yil oktabr): hujjatga ko'ra noto'g'ri ID uchun 400 Invalid ID supplied kutiladi. Amalda:
curl -s https://petstore.swagger.io/v2/pet/abc -H 'Accept: application/json'
# {"code":404,"type":"unknown","message":"java.lang.NumberFormatException: For input string: \"abc\""}
Bitta javobda ikkita muammo: (1) hujjat 400 desa ham server 404 qaytaryapti — hujjat va amaliyot mos emas; (2) javobda ichki Java exception nomi oshkor bo'lyapti — kichik xavfsizlik topilmasi (texnologiya haqida ma'lumot sizib chiqadi). Mana shunday "hujjat vs haqiqat" solishtiruvi — API testlashning asosi.
9. curl bilan birinchi API testlar {#curl}
Restful-booker — API testlashni mashq qilish uchun ochiq API (hujjati: https://restful-booker.herokuapp.com/apidoc/index.html). Ma'lumotlar vaqti-vaqti bilan tozalanadi, shuning uchun testlar o'z booking'ini o'zi yaratishi kerak. Quyidagi barcha javoblar haqiqiy (qisqartirilgan).
1. Server tirikmi?
curl -i https://restful-booker.herokuapp.com/ping
# HTTP/2 201
# Created
2. Token olish
curl -s -X POST https://restful-booker.herokuapp.com/auth \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"password123"}'
# {"token":"30d598abd9f88b0"}
Bash'da token'ni o'zgaruvchiga saqlab olamiz:
BASE=https://restful-booker.herokuapp.com
TOKEN=$(curl -s -X POST $BASE/auth -H 'Content-Type: application/json' \
-d '{"username":"admin","password":"password123"}' \
| python3 -c 'import sys, json; print(json.load(sys.stdin)["token"])')
echo $TOKEN
3. Booking yaratish (Create)
curl -s -X POST $BASE/booking \
-H 'Content-Type: application/json' -H 'Accept: application/json' \
-d '{"firstname":"Aziz","lastname":"Karimov","totalprice":450,"depositpaid":true,
"bookingdates":{"checkin":"2026-11-01","checkout":"2026-11-05"},
"additionalneeds":"Breakfast"}'
# HTTP status: 200
# {"bookingid":252,"booking":{"firstname":"Aziz","lastname":"Karimov","totalprice":450,...}}
4. O'qish (Read), yangilash (Update), o'chirish (Delete)
ID=252 # o'zingizdagi bookingid
curl -s $BASE/booking/$ID -H 'Accept: application/json'
# 200 {"firstname":"Aziz","lastname":"Karimov","totalprice":450,...}
# Tokensiz PUT — rad etilishi kerak
curl -s -o /dev/null -w "%{http_code}\n" -X PUT $BASE/booking/$ID \
-H 'Content-Type: application/json' -d '{"firstname":"X"}'
# 403
# Cookie token bilan PUT (to'liq body)
curl -s -X PUT $BASE/booking/$ID \
-H 'Content-Type: application/json' -H 'Accept: application/json' \
-H "Cookie: token=$TOKEN" \
-d '{"firstname":"Aziz","lastname":"Karimov","totalprice":500,"depositpaid":true,
"bookingdates":{"checkin":"2026-11-01","checkout":"2026-11-06"},
"additionalneeds":"Breakfast"}'
# 200 {"firstname":"Aziz",...,"totalprice":500,...}
# Basic auth bilan PATCH (faqat bitta maydon)
curl -s -X PATCH $BASE/booking/$ID \
-H 'Content-Type: application/json' -H 'Accept: application/json' \
-H 'Authorization: Basic YWRtaW46cGFzc3dvcmQxMjM=' \
-d '{"totalprice":520}'
# 200 {...,"totalprice":520,...}
curl -s -i -X DELETE $BASE/booking/$ID -H "Cookie: token=$TOKEN"
# HTTP/2 201
# Created
curl -s -o /dev/null -w "%{http_code}\n" $BASE/booking/$ID
# 404
💡 Maslahat:
curlbuyruqlarini README yoki bug report'ga qo'shing — dasturchi ularni nusxalab, sizning holatingizni bir soniyada takrorlaydi. DevTools'dagi Copy as cURL xuddi shu formatni beradi (QA 9).
10. Postman asoslari: collection, environment, variable {#postman-basics}
Postman — API'larni qo'lda va avtomatik testlash uchun eng mashhur grafik vosita. Desktop ilovani yuklab o'rnating (web versiyasi ham bor).
🇺🇿 Mahalliy kontekst: 2026-yil martidan Postman'ning bepul (Free) rejasi faqat bitta foydalanuvchi uchun: jamoaviy workspace'lar pullik rejalarga (Solo, Team, Enterprise) o'tdi. O'rganish uchun Free yetarli. Jamoada bepul ishlash kerak bo'lsa — Bruno (ochiq kodli, collection'larni git'da saqlaydi), Hoppscotch yoki Insomnia. Tushunchalar (collection, environment, variable, skript) bir xil, shu darsdagi bilimlar to'g'ridan-to'g'ri o'tadi.
Asosiy tushunchalar
| Tushuncha | Ma'nosi |
|---|---|
| Workspace | Loyiha uchun ish maydoni |
| Collection | So'rovlar to'plami (folder'larga bo'linadi) — test suite'ingiz |
| Request | Bitta so'rov: method, URL, header'lar, body, skriptlar |
| Environment | O'zgaruvchilar to'plami: local, staging, prod — bitta tugma bilan almashtiriladi |
| Variable | {{baseUrl}} kabi qo'yiladigan qiymat |
| History | Yuborilgan so'rovlar tarixi |
O'zgaruvchilar va ularning sohasi (scope)
Postman'da 5 ta scope bor (kengdan torga): global → collection → environment → data → local. Bir xil nomli o'zgaruvchi bir nechta scope'da bo'lsa, eng tor scope'dagi qiymat ishlatiladi.
| Scope | Qachon ishlatiladi | Skriptda |
|---|---|---|
| Global | Barcha collection'lar uchun umumiy (kamdan-kam kerak) | pm.globals.set/get |
| Collection | Collection ichidagi umumiy qiymatlar: token, bookingId | pm.collectionVariables.set/get |
| Environment | Muhitga bog'liq: baseUrl, login | pm.environment.set/get |
| Data | Runner'dagi CSV/JSON fayldan har iteratsiya uchun | pm.iterationData.get |
| Local | Faqat joriy so'rov/run davomida | pm.variables.set |
pm.variables.get("x") esa barcha scope'lardan eng torining qiymatini qaytaradi.
Postman'ning yangi versiyalarida o'zgaruvchining ikki qiymati shared value (bulutga sinxronlanadi, jamoa ko'radi) va local value (faqat sizning kompyuteringizda) deb ataladi; eski hujjatlarda ular initial va current value edi. Parol va token'lar uchun Postman Vault'dan foydalaning.
⚠️ Diqqat:
prodenvironment'ida yaratish/o'chirish testlarini ishga tushirmang. Ko'p jamoalar prod environment'ini umuman collection'ga qo'shmaydi yoki uni faqat o'qish (GET) testlari bilan cheklaydi.
Environment fayli (eksport ko'rinishi)
{
"name": "restful-booker-public",
"values": [
{
"key": "baseUrl",
"value": "https://restful-booker.herokuapp.com",
"enabled": true
},
{ "key": "username", "value": "admin", "enabled": true },
{ "key": "password", "value": "password123", "enabled": true }
]
}
So'rov URL'ida endi {{baseUrl}}/booking yozamiz — environment'ni staging ga almashtirsangiz, barcha so'rovlar o'sha serverga ketadi.
11. Postman skriptlari: Pre-request va Post-response {#postman-scripts}
Har bir request, folder va collection'ning Scripts tab'ida ikkita bo'lim bor:
- Pre-request — so'rov yuborilishidan oldin ishlaydi: o'zgaruvchi tayyorlash, sana generatsiya qilish, token bo'lmasa so'rovni o'tkazib yuborish.
- Post-response — javob kelgandan keyin: assertion'lar (testlar) va keyingi so'rov uchun qiymatlarni saqlash. Eski versiyalarda bu alohida Tests tab'i edi (v11 dan boshlab Scripts ichida).
Ishlash tartibi: avval collection, keyin folder, so'ng request darajasidagi skriptlar. Natijalar javob panelidagi Test Results tab'ida ko'rinadi. Assertion'lar Chai kutubxonasining BDD sintaksisida yoziladi (pm.expect(x).to.eql(y)).
pm API — eng kerakli qismlar
| Kod | Nima qiladi |
|---|---|
pm.test("nom", () => { ... }) | Bitta test (assertion'lar guruhi) |
pm.expect(qiymat).to.eql(...) | Chai assertion |
pm.response.to.have.status(200) | Status kod |
pm.response.code | Status kod raqami |
pm.response.json() | Body'ni JSON sifatida olish |
pm.response.headers.get("Content-Type") | Header qiymati |
pm.response.responseTime | Javob vaqti (ms) |
pm.response.to.have.jsonSchema(schema) | JSON Schema bo'yicha tekshirish (QA 11) |
pm.collectionVariables.set("k", v) | Collection o'zgaruvchisini saqlash |
pm.iterationData.get("k") | Data fayldagi joriy qator qiymati |
pm.execution.skipRequest() | Pre-request'da: so'rovni yubormaslik |
pm.execution.setNextRequest("nom") | Collection run'da keyingi so'rovni tanlash |
pm.sendRequest(...) | Skript ichidan qo'shimcha so'rov yuborish |
To'liq CRUD collection (tekshirilgan)
Collection 9 ta so'rovdan iborat: 01 Ping → 02 Auth → 03 Booking yaratish → 04 O'qish → 05 PUT tokensiz (negative) → 06 PUT → 07 PATCH (Basic Auth) → 08 DELETE → 09 O'chirilganini tekshirish. URL'larda {{baseUrl}}, body'larda {{checkin}}, {{checkout}}, header'da Cookie: token={{token}} ishlatiladi. Quyida har bir so'rovning skriptlari — aynan Newman'da o'tgan versiyalari.
02 Auth — Post-response:
pm.test("Status 200", () => {
pm.response.to.have.status(200);
});
const body = pm.response.json();
pm.test("Token qaytdi (faqat statusga ishonmaymiz!)", () => {
pm.expect(body.token, "token maydoni").to.be.a("string").and.not.be.empty;
});
pm.collectionVariables.set("token", body.token);
Nega "faqat statusga ishonmaymiz"? Chunki restful-booker noto'g'ri parol uchun ham 200 qaytaradi — faqat body'da {"reason":"Bad credentials"} bo'ladi. Faqat statusni tekshiradigan test bu holatda yashil bo'lib qolardi.
03 Booking yaratish — Pre-request:
// Bugundan 30 va 35 kun keyingi sanalar (YYYY-MM-DD)
const addDays = (days) => {
const d = new Date();
d.setDate(d.getDate() + days);
return d.toISOString().slice(0, 10);
};
pm.collectionVariables.set("checkin", addDays(30));
pm.collectionVariables.set("checkout", addDays(35));
Body (raw → JSON):
{
"firstname": "Aziz",
"lastname": "Karimov",
"totalprice": 450,
"depositpaid": true,
"bookingdates": { "checkin": "{{checkin}}", "checkout": "{{checkout}}" },
"additionalneeds": "Breakfast"
}
03 Booking yaratish — Post-response:
pm.test("Status 200 (restful-booker 201 emas, 200 qaytaradi)", () => {
pm.response.to.have.status(200);
});
const body = pm.response.json();
pm.test("bookingid — raqam", () => {
pm.expect(body.bookingid).to.be.a("number");
});
pm.test("Yuborilgan ma'lumot o'zgarmay qaytdi", () => {
pm.expect(body.booking.firstname).to.eql("Aziz");
pm.expect(body.booking.totalprice).to.eql(450);
pm.expect(body.booking.bookingdates.checkin).to.eql(
pm.collectionVariables.get("checkin"),
);
});
const schema = {
type: "object",
required: ["bookingid", "booking"],
properties: {
bookingid: { type: "integer" },
booking: {
type: "object",
required: [
"firstname",
"lastname",
"totalprice",
"depositpaid",
"bookingdates",
],
properties: {
firstname: { type: "string" },
lastname: { type: "string" },
totalprice: { type: "integer" },
depositpaid: { type: "boolean" },
bookingdates: {
type: "object",
required: ["checkin", "checkout"],
properties: {
checkin: { type: "string" },
checkout: { type: "string" },
},
},
},
},
},
};
pm.test("Javob JSON Schema'ga mos", () => {
pm.response.to.have.jsonSchema(schema);
});
pm.collectionVariables.set("bookingId", body.bookingid);
04 O'qish — Post-response (URL: {{baseUrl}}/booking/{{bookingId}}):
pm.test("Status 200", () => {
pm.response.to.have.status(200);
});
pm.test("Content-Type — JSON", () => {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
pm.test("Javob vaqti 3000 ms dan kam", () => {
pm.expect(pm.response.responseTime).to.be.below(3000);
});
const booking = pm.response.json();
pm.test("Ma'lumot to'g'ri saqlangan", () => {
pm.expect(booking.lastname).to.eql("Karimov");
pm.expect(booking.depositpaid).to.be.true;
});
05 PUT tokensiz (negative), 06 PUT va 07 PATCH:
// 05 — Cookie'siz PUT
pm.test("Tokensiz PUT rad etiladi (403)", () => {
pm.response.to.have.status(403);
});
// 06 — header: Cookie: token={{token}}, body'da totalprice: 500
pm.test("Status 200", () => {
pm.response.to.have.status(200);
});
pm.test("Narx 500 ga yangilandi", () => {
pm.expect(pm.response.json().totalprice).to.eql(500);
});
// 07 — Authorization tab: Basic Auth ({{username}} / {{password}}), body: {"totalprice": 520}
pm.test("Status 200", () => {
pm.response.to.have.status(200);
});
pm.test("Faqat narx o'zgardi, ism joyida", () => {
const b = pm.response.json();
pm.expect(b.totalprice).to.eql(520);
pm.expect(b.firstname).to.eql("Aziz");
});
08 DELETE va 09 O'chirilganini tekshirish:
// restful-booker o'chirishda 201 Created qaytaradi — bu "quirk".
// Odatiy REST'da 200 yoki 204 kutiladi, shuning uchun uchalasini qabul qilamiz.
pm.test("O'chirish muvaffaqiyatli", () => {
pm.expect(pm.response.code).to.be.oneOf([200, 201, 204]);
});
pm.test("O'chirilgan booking topilmaydi (404)", () => {
pm.response.to.have.status(404);
});
🧠 Esda tuting: Yaxshi API test'i bitta assertion bilan cheklanmaydi: status + header + body qiymatlari + sxema + (kerak bo'lsa) vaqt. Va eng muhimi — yon ta'sir: o'chirilgan narsa haqiqatan yo'qolganini alohida GET bilan tekshirish.
Ko'p uchraydigan xatolar
- Faqat statusni tekshirish (yuqoridagi
200 + Bad credentialsmisoli). - ID'ni qo'lda yozib qo'yish (
/booking/252) — ertaga u booking o'chib ketadi. ID har doim oldingi so'rovdan olinsin. - Testlarni bir-biriga yashirin bog'lash: 4-so'rov faqat 3-sidan keyin ishlaydi, lekin bu hech qayerda yozilmagan.
- Token va parollarni collection'ning shared qiymatlariga yozib, eksport qilib yuborish.
- Umumiy (shared) staging'da juda qattiq
responseTimechegarasi — test "beqaror" bo'lib qoladi. Performance'ni alohida o'lchang (QA 23).
12. Collection Runner va data-driven testlar {#runner}
Collection Runner butun collection'ni ketma-ket ishga tushiradi: iteratsiyalar soni, so'rovlar orasidagi kechikish va data fayl (CSV yoki JSON) tanlash mumkin. Natijada qaysi test o'tdi, qaysi yiqildi — jadval ko'rinishida chiqadi.
Data-driven test — bitta so'rovni turli ma'lumotlar bilan ko'p marta ishga tushirish. bookings.csv:
firstname,lastname,totalprice
Aziz,Karimov,450
Malika,Yusupova,1200
Sardor,Tursunov,0
So'rov body'si CSV ustunlarini {{...}} bilan oladi (totalprice qo'shtirnoqsiz — son bo'lib ketishi uchun):
{
"firstname": "{{firstname}}",
"lastname": "{{lastname}}",
"totalprice": {{totalprice}},
"depositpaid": true,
"bookingdates": { "checkin": "2026-12-01", "checkout": "2026-12-03" }
}
Post-response:
const sent = {
firstname: pm.iterationData.get("firstname"),
totalprice: Number(pm.iterationData.get("totalprice")),
};
const body = pm.response.json();
pm.test(`${sent.firstname}: status 200`, () => {
pm.response.to.have.status(200);
});
pm.test(`${sent.firstname}: narx o'zgarmay saqlandi`, () => {
pm.expect(body.booking.totalprice).to.eql(sent.totalprice);
});
Runner'da data fayl sifatida bookings.csv ni tanlasangiz — 3 ta iteratsiya, 6 ta assertion. Haqiqiy loyihada CSV'ga chegaraviy qiymatlarni qo'yasiz (EP/BVA — QA 5): 0, manfiy, juda katta son, bo'sh ism, 50 belgilik ism va hokazo.
Oqimni boshqarish (faqat collection run'da ishlaydi, oddiy Send'da e'tiborga olinmaydi):
// Pre-request: token bo'lmasa, so'rovni umuman yubormaymiz
if (!pm.environment.get("token")) {
pm.execution.skipRequest();
}
// Post-response: keyingi qadamni tanlash
pm.execution.setNextRequest("09 O'chirilganini tekshirish");
13. Newman — Postman'ni terminalda ishga tushirish {#newman}
Newman — Postman collection'larini buyruq qatoridan ishga tushiradigan rasmiy vosita. U testlaringizni CI'ga (GitHub Actions va boshqalar) olib kirishning eng oddiy yo'li (QA 21).
Postman'da collection va environment'ni eksport qiling (... → Export, Collection v2.1 formati), so'ng:
# Node.js loyihasida bir marta o'rnatish
npm init -y
npm i -D newman
# Collection'ni environment bilan ishga tushirish
npx newman run restful-booker.postman_collection.json \
-e restful-booker.postman_environment.json
Haqiqiy natija (qisqartirilgan):
→ 02 Auth — token olish
POST https://restful-booker.herokuapp.com/auth [200 OK, 774B, 413ms]
✓ Status 200
✓ Token qaytdi (faqat statusga ishonmaymiz!)
...
→ 08 DELETE
DELETE https://restful-booker.herokuapp.com/booking/2930 [201 Created, 747B, 407ms]
✓ O'chirish muvaffaqiyatli
┌─────────────────────────┬───────────────────┬───────────────────┐
│ │ executed │ failed │
├─────────────────────────┼───────────────────┼───────────────────┤
│ requests │ 9 │ 0 │
│ assertions │ 18 │ 0 │
└─────────────────────────┴───────────────────┴───────────────────┘
Foydali parametrlar:
| Parametr | Vazifasi |
|---|---|
-e env.json | Environment fayli |
-d bookings.csv | Data fayl (data-driven) |
-n 3 | Iteratsiyalar soni |
-r cli,junit --reporter-junit-export results/junit.xml | Hisobot formatlari: konsol + JUnit XML (CI uchun) |
--bail | Birinchi xatoda to'xtash |
--delay-request 200 | So'rovlar orasida 200 ms kutish |
--timeout-request 10000 | Bitta so'rov uchun timeout (ms) |
--env-var "baseUrl=https://..." | Environment o'zgaruvchisini buyruqdan berish |
Newman hamma test o'tsa 0, birortasi yiqilsa 1 exit code bilan tugaydi — CI pipeline shu bo'yicha "qizil" yoki "yashil" bo'ladi.
🎯 Intervyuda: "Postman testlarini qanday avtomatlashtirasiz?" — Collection'ni eksport qilib, Newman bilan CI'da ishga tushiraman; environment'ni CI secret'laridan beraman; JUnit hisobotini CI'ga yuklayman. Murakkab loyihalarda esa API testlarni kod sifatida yozaman (Playwright
request— QA 20).
14. restful-booker g'alatiliklari: bug'mi yoki xususiyat? {#quirks}
Restful-booker — "API testlashni mashq qilish uchun bepul API" (README'dagi ta'rif). Undagi g'alatiliklar ataylab qilinganmi yoki yo'qmi — README'da aytilmagan. Muhimi boshqa: QA ularni topa olishi va to'g'ri tasniflashi kerak. 2026-yil oktabrda kuzatilgan holatlar:
| # | Kuzatuv | Hujjatda | HTTP odati | QA bahosi |
|---|---|---|---|---|
| 1 | GET /ping → 201 Created | 201 | 200 (hech narsa yaratilmadi) | Hujjatga mos, odatga zid — past ustuvorlik |
| 2 | POST /booking → 200 | 200 | 201 + Location | Odatga zid; client'lar 201 ni kutsa muammo |
| 3 | Noto'g'ri parol bilan POST /auth → 200 + {"reason":"Bad credentials"} | Xato holati yozilmagan | 401 | Bug: status bo'yicha ishlaydigan client'lar xatoni "ko'rmaydi" |
| 4 | DELETE /booking/{id} → 201 Created | 201 | 200/204 | Hujjatga mos, semantikaga zid |
| 5 | Mavjud bo'lmagan ID'ga PUT/PATCH/DELETE → 405, Allow header'isiz | — | 404 | Bug: noto'g'ri kod va 405 uchun majburiy header yo'q |
| 6 | Tokensiz PUT → 403 | — | 401 | Munozarali: "siz kimsiz" holati uchun 401 to'g'riroq |
| 7 | Accept: application/xml → XML body, lekin Content-Type: text/html | XML qo'llab-quvvatlanadi | application/xml | Bug: client javobni noto'g'ri talqin qiladi |
| 8 | Content-Type: text/plain bilan yaroqli JSON → 500 | — | 415 | Bug: server xatoni ushlamayapti |
| 9 | Javob header'ida x-powered-by: Express | — | Yashirilgani yaxshi | Kichik xavfsizlik topilmasi (texnologiya oshkor) |
💡 Maslahat: Bunday holatni bug report'ga yozayotganda uch narsani solishtiring: hujjat nima deydi, standart/odat (RFC 9110) nima deydi va amalda nima bo'lyapti. Agar hujjat ham "201" desa — bu kod xatosi emas, API dizayni masalasi; uni product owner yoki arxitektor bilan muhokama qilish uchun ko'taring. Batafsil negative testlar va topilmalar: QA 11.
15. Amaliy mashqlar {#mashqlar}
Mashq 1: Status kodni toping
Har bir holat uchun eng to'g'ri status kodni yozing:
- DemoBozor'da yangi buyurtma muvaffaqiyatli yaratildi.
- Savatchadagi element o'chirildi, javobda body yo'q.
- Token muddati o'tgan.
- Xaridor
GET /api/v1/admin/usersga murojaat qildi. quantity: 120yuborildi (ruxsat 1–99), JSON to'g'ri.- SMS kodni 4-marta noto'g'ri kiritish urinishi (3 tadan keyin blok).
- JSON body'da yopilmagan qavs.
- To'lov xizmati javob bermadi, gateway kutib, vaqt tugadi.
<details> <summary>💡 Javobni ko'rish</summary>
201 Created(+Location: /api/v1/orders/{id})204 No Content401 Unauthorized403 Forbidden422 Unprocessable Content(ba'zi jamoalar400ishlatadi — API ichida izchil bo'lsa, qabul qilinadi)429 Too Many Requests(+Retry-After, masalan 900 soniya = 15 daqiqa) — yoki jamoa kelishgan maxsus kod; muhimi, hujjatda yozilgan bo'lsin400 Bad Request504 Gateway Timeout
</details>
Mashq 2: Idempotentlik
Qaysi so'rovlarni tarmoq uzilganda avtomatik xavfsiz qayta yuborish mumkin? Nega?
GET /products?query=choynak, POST /orders, PUT /profile, DELETE /cart/items/7, PATCH /cart/items/7 {"quantity": "+1"}
<details> <summary>💡 Javobni ko'rish</summary>
GET— ha (safe va idempotent).PUT /profile— ha (bir xil to'liq holatni qayta yozadi).DELETE /cart/items/7— ha (ikkinchi marta ham natija — element yo'q; javob kodi404bo'lishi mumkin, lekin holat bir xil).POST /orders— yo'q: ikkita buyurtma yaratilishi mumkin (restful-booker'da ikki marta POST → ikki xilbookingid). Himoya:Idempotency-Keyyoki server tomonda dublikat tekshiruvi.PATCH ... "+1"— yo'q: har yuborishda miqdor oshadi.{"quantity": 3}kabi absolyut qiymat yuborilsa idempotent bo'lardi.
</details>
Mashq 3: GET uchun Post-response testlari
GET {{baseUrl}}/booking/{{bookingId}} uchun testlar yozing: status 200; Content-Type JSON; firstname va lastname — bo'sh bo'lmagan string; totalprice — 0 dan katta yoki teng butun son; checkout sanasi checkin dan keyin.
<details> <summary>💡 Javobni ko'rish</summary>
pm.test("Status 200", () => {
pm.response.to.have.status(200);
});
pm.test("JSON qaytdi", () => {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
const b = pm.response.json();
pm.test("Ism va familiya bo'sh emas", () => {
pm.expect(b.firstname).to.be.a("string").and.not.be.empty;
pm.expect(b.lastname).to.be.a("string").and.not.be.empty;
});
pm.test("Narx — manfiy bo'lmagan butun son", () => {
pm.expect(Number.isInteger(b.totalprice)).to.be.true;
pm.expect(b.totalprice).to.be.at.least(0);
});
pm.test("checkout checkin'dan keyin", () => {
pm.expect(
new Date(b.bookingdates.checkout) > new Date(b.bookingdates.checkin),
).to.be.true;
});
Eslatma: restful-booker manfiy narx va teskari sanalarni qabul qiladi — shuning uchun ba'zi booking'larda oxirgi ikki test yiqiladi. Bu test xatosi emas, API'dagi validatsiya yo'qligining isboti (QA 11).
</details>
Mashq 4: DemoBozor savatchasi uchun CRUD ketma-ketligi
Xayoliy DemoBozor API'sida savatcha elementlari uchun to'liq test ketma-ketligini (qadamlar va kutilgan kodlar) tuzing. Kamida bitta negative qadam qo'shing.
<details> <summary>💡 Javobni ko'rish</summary>
| # | So'rov | Kutilgan natija |
|---|---|---|
| 1 | POST /api/v1/auth/verify (telefon + OTP) | 200, accessToken saqlanadi |
| 2 | GET /api/v1/cart | 200, savatcha bo'sh (yoki boshlang'ich holat qayd etiladi) |
| 3 | POST /api/v1/cart/items {productId: 1042, quantity: 2} | 201, element ID saqlanadi |
| 4 | GET /api/v1/cart | 200, element bor, quantity = 2, summa to'g'ri |
| 5 | PATCH /api/v1/cart/items/{id} {quantity: 99} | 200, quantity = 99 (yuqori chegara) |
| 6 | PATCH ... {quantity: 100} | 422 (yoki 400), miqdor o'zgarmagan |
| 7 | DELETE /api/v1/cart/items/{id} | 204 |
| 8 | GET /api/v1/cart | 200, element yo'q |
| 9 | Token'siz GET /api/v1/cart | 401 |
</details>
Mashq 5: Promo-kod uchun data fayl
DemoBozor qoidasi: promo-kod 6–12 belgi, faqat A–Z va 0–9 (katta harf). Data-driven test uchun CSV tuzing: code va expected (valid/invalid) ustunlari, kamida 8 qator.
<details> <summary>💡 Javobni ko'rish</summary>
code,expected,izoh
ABC12,invalid,5 belgi (pastki chegaradan 1 kam)
ABC123,valid,6 belgi (pastki chegara)
ABCDEFGH1234,valid,12 belgi (yuqori chegara)
ABCDEFGH12345,invalid,13 belgi
abc123,invalid,kichik harf
ABC 123,invalid,probel
ABC-123,invalid,maxsus belgi
OʻZBEK1,invalid,lotin bo'lmagan harf (ʻ)
,invalid,bo'sh qiymat
Post-response'da pm.iterationData.get("expected") ga qarab kutilgan status kodni tanlaysiz (masalan, valid → 200, invalid → 422).
</details>
Mashq 6: JWT'ni lokal oching
Toolshop API'dan token oling (customer@practicesoftwaretesting.com / welcome01) va uni lokal dekod qiling. role nima? Token necha soniya yashaydi? Shu ma'lumotdan kamida 2 ta test g'oyasi chiqaring.
<details> <summary>💡 Javobni ko'rish</summary>
7-bo'lim dagi buyruqlar bilan: role: 'user', exp - iat = 300 soniya (5 daqiqa).
Test g'oyalari:
- 5 daqiqadan keyin
GET /users/me→401qaytishi kerak. - Token'siz va buzilgan token bilan
GET /users/me→401(Toolshop'da tekshirilgan). - Oddiy foydalanuvchi token'i bilan admin endpoint'i (
GET /users) →403(tekshirilgan). - Payload'dagi
roleniadminga o'zgartirib (signature eskicha qoladi) yuborsangiz → server rad etishi kerak (401). Buni faqat test muhitida va ruxsat bilan qiling.
</details>
Xulosa {#xulosa}
- API — client va server o'rtasidagi shartnoma; bitta API bug'i web, iOS va Android'da birdaniga ko'rinadi.
- REST: resurslar (otlar) + method'lar (fe'llar). Method'ning safe/idempotent xususiyatlari qayta yuborish va dublikat buyurtma kabi real risklarni belgilaydi.
- Status kodni bilish — yarim jang:
401vs403,400vs422,500deyarli har doim bug. - JSON'da tip,
null/yo'q maydon/bo'sh qator farqi va sana zonalari — eng ko'p bug manbalari. - Base64 shifr emas; JWT payload'i ochiq o'qiladi — real token'larni onlayn dekoderlarga bermang.
- Postman: collection + environment + variable scope'lari + Pre-request/Post-response skriptlari = to'liq avtomatik API test; Newman uni terminal va CI'ga olib chiqadi.
- "Hujjat vs standart vs amaliyot" solishtiruvi — API'dagi topilmalarni to'g'ri tasniflash kaliti.
Keyingi dars: QA 11: API testing (2) — Test dizayn, negative testlar, JSON Schema, Auth, Mock va Contract testing
Manbalar {#manbalar}
- Roy Fielding — Representational State Transfer (REST), dissertatsiya 5-bob
- RFC 9110 — HTTP Semantics (method'lar, status kodlar)
- RFC 6585 — Additional HTTP Status Codes (429)
- MDN — HTTP request methods
- MDN — Idempotent
- MDN — Safe (HTTP methods)
- MDN — HTTP response status codes
- RFC 7519 — JSON Web Token (JWT)
- RFC 6749 — The OAuth 2.0 Authorization Framework
- JWT.io — Introduction to JSON Web Tokens
- OpenAPI Specification (latest)
- Swagger Petstore (v2)
- Swagger Petstore (OpenAPI 3)
- Restful-booker API hujjati
- Restful-booker — GitHub
- Toolshop API hujjati (practicesoftwaretesting.com)
- Postman Docs — Use scripts to add logic and tests
- Postman Docs — Write scripts to test API response data
- Postman Docs — Test script examples
- Postman Docs — pm.test va pm.expect
- Postman Docs — Variables in scripts
- Postman Docs — pm.execution
- Postman Docs — Store and reuse values using variables
- Postman Docs — Manage environments
- Postman Docs — Postman Vault
- Postman Docs — Run collections (Collection Runner)
- Postman Docs — Run collections with data files
- Postman Docs — Run collections using Newman CLI
- Postman Docs — About plans
- Postman Community — Pre-request va Post-response (sobiq Tests) haqida
- Newman — GitHub
- Chai — BDD assertion API
- Bruno
- Hoppscotch
- Insomnia