Azimjon Abdurasulov

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 curl va 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 curl va 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

  1. API nima va QA uchun nega muhim
  2. REST printsiplari va endpoint dizayni
  3. Method'lar, CRUD va idempotentlik
  4. Status kodlar — QA uchun to'liq jadval
  5. JSON asoslari
  6. So'rov qismlari: path, query, header, body
  7. Autentifikatsiya asoslari
  8. Swagger / OpenAPI hujjatini o'qish
  9. curl bilan birinchi API testlar
  10. Postman asoslari: collection, environment, variable
  11. Postman skriptlari: Pre-request va Post-response
  12. Collection Runner va data-driven testlar
  13. Newman — Postman'ni terminalda ishga tushirish
  14. restful-booker g'alatiliklari: bug'mi yoki xususiyat?
  15. Amaliy mashqlar
  16. Xulosa
  17. 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 testlashAPI orqali testlash
Sekin: sahifa yuklanishi, animatsiyalarTez: bitta so'rov — millisekundlar
UI o'zgarsa test buziladiAPI shartnomasi kamroq o'zgaradi
Faqat UI ruxsat bergan qiymatlarni kiritasizIstalgan qiymatni yuborasiz (manfiy narx, 10 000 belgilik ism)
Bug'ning qaysi qatlamda ekanini aniqlash qiyinroqBack-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

YomonYaxshi (REST uslubi)Izoh
GET /getProductsGET /productsFe'l method'da, URL'da ot
POST /deleteOrder?id=5DELETE /orders/5Amal turi — method
GET /product/5 va GET /productsGET /products/5 va GET /productsBir xil ko'plik shakli
GET /orders/5/getItemsGET /orders/5/itemsIchma-ich resurs
/v1products/api/v1/productsVersiya 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

MethodCRUDSafeIdempotentOdatiy muvaffaqiyat kodiBody
GETRead✅✅200Yo'q
POSTCreate❌❌201 (+ Location)Bor
PUTUpdate (to'liq almashtirish)❌✅200 yoki 204Bor
PATCHUpdate (qisman)❌Kafolatlanmaydi200 yoki 204Bor
DELETEDelete❌✅200 yoki 204Odatda yo'q
HEADFaqat header'lar✅✅200Yo'q
OPTIONSRuxsat etilgan method'lar, CORS preflight✅✅200/204Yo'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/7 ikki 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}

KodNomiQachonDemoBozor misoliQA eslatmasi
200OKMuvaffaqiyatli o'qish/yangilashGET /products/1042Body'ni ham tekshiring — 200 ichida xato bo'lishi mumkin
201CreatedYangi resurs yaratildiPOST /ordersLocation header'i bormi
204No ContentMuvaffaqiyat, body yo'qDELETE /cart/items/7Body bo'sh bo'lishi kerak
301 / 302Moved / FoundYo'naltirishhttp:// → https://Yo'naltirish zanjiri cheksiz emasmi
304Not ModifiedKesh hamon dolzarbIf-None-Match bilan GETQA 9 dagi kesh tajribasi
400Bad RequestSo'rov noto'g'ri tuzilganBuzilgan JSONXato xabari tushunarlimi
401UnauthorizedAutentifikatsiya yo'q yoki yaroqsizToken yo'q/muddati o'tgan"Kimligingiz noma'lum"
403ForbiddenKimligingiz ma'lum, lekin ruxsat yo'qXaridor admin endpoint'iga"Siz kimligingizni bilaman, lekin mumkin emas"
404Not FoundResurs yo'qGET /orders/999999Boshqa birovning resursi uchun ham 404 qaytarish mumkin (ma'lumot oshkor bo'lmasligi uchun)
405Method Not AllowedBu resursda bu method yo'qDELETE /productsJavobda Allow header'i bo'lishi kerak
409ConflictHolat ziddiyatiRo'yxatdan o'tgan telefon bilan qayta ro'yxatXabar aniq bo'lsin
415Unsupported Media TypeBody formati qo'llab-quvvatlanmaydiJSON o'rniga text/plain500 emas, aynan 415 kutiladi
422Unprocessable ContentFormat to'g'ri, qiymatlar qoidaga zidquantity: 120 (ruxsat 1–99)Qaysi maydon xato — javobda ko'rsatilsinmi
429Too Many RequestsLimitdan oshdi3 noto'g'ri SMS kodRetry-After header'i bormi
500Internal Server ErrorServerda kutilmagan xatoHar qanday ishlov berilmagan holatDeyarli har doim bug; stack trace oshkor bo'lmasin
502Bad GatewayProxy orqadagi xizmatdan yaroqsiz javob oldiAPI konteyneri qulaganInfra bilan birga ko'riladi
503Service UnavailableVaqtincha ishlamaydiTexnik ishlarRetry-After bo'lishi mumkin
504Gateway TimeoutProxy javobni kutib charchadiSekin hisobot so'roviTimeout chegaralari

🧠 Esda tuting: 401 = "siz kimsiz?", 403 = "kimligingizni bilaman, lekin ruxsat yo'q". Toolshop API'da buni o'zingiz ko'rasiz: tokensiz GET /users/me → 401, oddiy xaridor tokeni bilan admin'ga tegishli GET /users → 403 (QA 11).

🎯 Intervyuda: "400 va 422 farqi?" — 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 jamoalar 400 ni 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:

TipMisol
string"Choynak 1.7 L"
number450000, 4.5
booleantrue, false
nullnull
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" + 1 qilsa "21" chiqadi.
  • **null, yo'q maydon va bo'sh qator** — uch xil holat: "promoCode": null, promoCode umuman 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}
QismNima uchunMisol
Path parametrAniq resursni ko'rsatish/booking/{id} → /booking/252
Query parametrFiltr, saralash, sahifalash?firstname=Aziz&lastname=Karimov
HeaderMetama'lumot: format, auth, tilContent-Type, Authorization, Accept-Language
BodyYaratiladigan/o'zgaradigan ma'lumotJSON, 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:

UsulQanday yuboriladiMisolQA eslatmasi
API keyHeader yoki queryX-API-Key: abc123Kalit URL'da bo'lsa, loglarda qolib ketadi
BasicAuthorization: Basic base64(login:parol)restful-booker PATCHBase64 — shifrlash emas
Bearer tokenAuthorization: Bearer <token>Toolshop APIToken muddati, bekor qilinishi
CookieCookie: token=...restful-booker PUT/DELETECookie atributlari (QA 9)
OAuth 2.0Token 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 qismiPetstore'dagi misolUndan qanday test chiqadi
Tag'lar (guruhlar)pet, store, userQamrov rejasini guruhlarga bo'lish
EndpointGET /pet/{petId}Har endpoint uchun test to'plami
ParametrpetId — path, integer, int64, majburiyabc, -1, 0, juda katta son
EnumfindByStatus: available, pending, soldRo'yxatdan tashqari qiymat
Majburiy maydonlarPet modelida name, photoUrlsHar birisiz yuborish
Javoblar200, 400 Invalid ID supplied, 404 Pet not foundHar bir kod uchun alohida test
Xavfsizlikapi_key, petstore_auth (OAuth)Kalitsiz/noto'g'ri kalit bilan
"Try it out"So'rovni brauzerdan yuborishTez 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: curl buyruqlarini 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

TushunchaMa'nosi
WorkspaceLoyiha uchun ish maydoni
CollectionSo'rovlar to'plami (folder'larga bo'linadi) — test suite'ingiz
RequestBitta so'rov: method, URL, header'lar, body, skriptlar
EnvironmentO'zgaruvchilar to'plami: local, staging, prod — bitta tugma bilan almashtiriladi
Variable{{baseUrl}} kabi qo'yiladigan qiymat
HistoryYuborilgan 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.

ScopeQachon ishlatiladiSkriptda
GlobalBarcha collection'lar uchun umumiy (kamdan-kam kerak)pm.globals.set/get
CollectionCollection ichidagi umumiy qiymatlar: token, bookingIdpm.collectionVariables.set/get
EnvironmentMuhitga bog'liq: baseUrl, loginpm.environment.set/get
DataRunner'dagi CSV/JSON fayldan har iteratsiya uchunpm.iterationData.get
LocalFaqat joriy so'rov/run davomidapm.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: prod environment'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

KodNima 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.codeStatus kod raqami
pm.response.json()Body'ni JSON sifatida olish
pm.response.headers.get("Content-Type")Header qiymati
pm.response.responseTimeJavob 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 credentials misoli).
  • 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 responseTime chegarasi — 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:

ParametrVazifasi
-e env.jsonEnvironment fayli
-d bookings.csvData fayl (data-driven)
-n 3Iteratsiyalar soni
-r cli,junit --reporter-junit-export results/junit.xmlHisobot formatlari: konsol + JUnit XML (CI uchun)
--bailBirinchi xatoda to'xtash
--delay-request 200So'rovlar orasida 200 ms kutish
--timeout-request 10000Bitta 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:

#KuzatuvHujjatdaHTTP odatiQA bahosi
1GET /ping → 201 Created201200 (hech narsa yaratilmadi)Hujjatga mos, odatga zid — past ustuvorlik
2POST /booking → 200200201 + LocationOdatga zid; client'lar 201 ni kutsa muammo
3Noto'g'ri parol bilan POST /auth → 200 + {"reason":"Bad credentials"}Xato holati yozilmagan401Bug: status bo'yicha ishlaydigan client'lar xatoni "ko'rmaydi"
4DELETE /booking/{id} → 201 Created201200/204Hujjatga mos, semantikaga zid
5Mavjud bo'lmagan ID'ga PUT/PATCH/DELETE → 405, Allow header'isiz—404Bug: noto'g'ri kod va 405 uchun majburiy header yo'q
6Tokensiz PUT → 403—401Munozarali: "siz kimsiz" holati uchun 401 to'g'riroq
7Accept: application/xml → XML body, lekin Content-Type: text/htmlXML qo'llab-quvvatlanadiapplication/xmlBug: client javobni noto'g'ri talqin qiladi
8Content-Type: text/plain bilan yaroqli JSON → 500—415Bug: server xatoni ushlamayapti
9Javob header'ida x-powered-by: Express—Yashirilgani yaxshiKichik 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:

  1. DemoBozor'da yangi buyurtma muvaffaqiyatli yaratildi.
  2. Savatchadagi element o'chirildi, javobda body yo'q.
  3. Token muddati o'tgan.
  4. Xaridor GET /api/v1/admin/users ga murojaat qildi.
  5. quantity: 120 yuborildi (ruxsat 1–99), JSON to'g'ri.
  6. SMS kodni 4-marta noto'g'ri kiritish urinishi (3 tadan keyin blok).
  7. JSON body'da yopilmagan qavs.
  8. To'lov xizmati javob bermadi, gateway kutib, vaqt tugadi.

<details> <summary>💡 Javobni ko'rish</summary>

  1. 201 Created (+ Location: /api/v1/orders/{id})
  2. 204 No Content
  3. 401 Unauthorized
  4. 403 Forbidden
  5. 422 Unprocessable Content (ba'zi jamoalar 400 ishlatadi — API ichida izchil bo'lsa, qabul qilinadi)
  6. 429 Too Many Requests (+ Retry-After, masalan 900 soniya = 15 daqiqa) — yoki jamoa kelishgan maxsus kod; muhimi, hujjatda yozilgan bo'lsin
  7. 400 Bad Request
  8. 504 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 kodi 404 bo'lishi mumkin, lekin holat bir xil).
  • POST /orders — yo'q: ikkita buyurtma yaratilishi mumkin (restful-booker'da ikki marta POST → ikki xil bookingid). Himoya: Idempotency-Key yoki 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'rovKutilgan natija
1POST /api/v1/auth/verify (telefon + OTP)200, accessToken saqlanadi
2GET /api/v1/cart200, savatcha bo'sh (yoki boshlang'ich holat qayd etiladi)
3POST /api/v1/cart/items {productId: 1042, quantity: 2}201, element ID saqlanadi
4GET /api/v1/cart200, element bor, quantity = 2, summa to'g'ri
5PATCH /api/v1/cart/items/{id} {quantity: 99}200, quantity = 99 (yuqori chegara)
6PATCH ... {quantity: 100}422 (yoki 400), miqdor o'zgarmagan
7DELETE /api/v1/cart/items/{id}204
8GET /api/v1/cart200, element yo'q
9Token'siz GET /api/v1/cart401

</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:

  1. 5 daqiqadan keyin GET /users/me → 401 qaytishi kerak.
  2. Token'siz va buzilgan token bilan GET /users/me → 401 (Toolshop'da tekshirilgan).
  3. Oddiy foydalanuvchi token'i bilan admin endpoint'i (GET /users) → 403 (tekshirilgan).
  4. Payload'dagi role ni admin ga 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: 401 vs 403, 400 vs 422, 500 deyarli 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}

  1. Roy Fielding — Representational State Transfer (REST), dissertatsiya 5-bob
  2. RFC 9110 — HTTP Semantics (method'lar, status kodlar)
  3. RFC 6585 — Additional HTTP Status Codes (429)
  4. MDN — HTTP request methods
  5. MDN — Idempotent
  6. MDN — Safe (HTTP methods)
  7. MDN — HTTP response status codes
  8. RFC 7519 — JSON Web Token (JWT)
  9. RFC 6749 — The OAuth 2.0 Authorization Framework
  10. JWT.io — Introduction to JSON Web Tokens
  11. OpenAPI Specification (latest)
  12. Swagger Petstore (v2)
  13. Swagger Petstore (OpenAPI 3)
  14. Restful-booker API hujjati
  15. Restful-booker — GitHub
  16. Toolshop API hujjati (practicesoftwaretesting.com)
  17. Postman Docs — Use scripts to add logic and tests
  18. Postman Docs — Write scripts to test API response data
  19. Postman Docs — Test script examples
  20. Postman Docs — pm.test va pm.expect
  21. Postman Docs — Variables in scripts
  22. Postman Docs — pm.execution
  23. Postman Docs — Store and reuse values using variables
  24. Postman Docs — Manage environments
  25. Postman Docs — Postman Vault
  26. Postman Docs — Run collections (Collection Runner)
  27. Postman Docs — Run collections with data files
  28. Postman Docs — Run collections using Newman CLI
  29. Postman Docs — About plans
  30. Postman Community — Pre-request va Post-response (sobiq Tests) haqida
  31. Newman — GitHub
  32. Chai — BDD assertion API
  33. Bruno
  34. Hoppscotch
  35. Insomnia

Markdown manba

iOS Lessons