Postman Derinlemesine: Collection, Environment, Variable Scope'ları, Script'ler, Test'ler, Mock Server ve CLI
Postman collection'ını repo'da tutup CI'da Newman ya da Postman CLI ile koşmak, Mart 2026'dan beri tek kullanıcılı ücretsiz plana karşı en sağlam yol. Bookstore için elle yazılmış v2.1 collection: OpenAPI'den import, variable scope önceliği, shared ve local value farkı, token'ı bir kez alıp saklayan pre-request script, pm.test, data dosyasıyla düşen bir iterasyon, JUnit raporu ve Postman CLI'ın yerel mock'unun neden işe yaramaz veri döndürdüğü gerçek koşularla.
Sürüm notu: Bu yazıdaki kodlar .NET 10 ile derlenip denenmiştir; collection Newman 6.2 ve Postman CLI 1.90 ile, OpenAPI dönüşümü openapi-to-postmanv2 6.4 ile çalıştırılmıştır. Postman desktop uygulamasının ekranları, Native Git ve bulut özellikleri (bulut mock server, Vault, plan sınırları) Postman'in resmi dokümanından aktarılmıştır; bu yazı için Postman hesabı açmadım ve uygulamada oturum açmadım. Plan bilgileri 14 Kasım 2026 tarihlidir.
Önce Tahmin Et
Bir Postman collection'ında isbn adında bir collection variable var, değeri bir kitabın ISBN'i (uluslararası standart kitap numarası): 9780261102217, The Hobbit. Aynı collection'ı şu CSV (virgülle ayrılmış değerler) dosyasıyla, yalnız "Book by ISBN" isteğini dört kez çalıştıracak şekilde koşuyorsun:
isbn,expectedTitle
9780441172719,Dune
9780141439587,Emma
9780261102217,The Hobbit
9780451524935,Animal Farm
Dört iterasyonda hangi kitaplar istenir: dört kez The Hobbit mi, yoksa CSV'deki dört kitap mı? Login her iterasyonda tekrarlanır mı? Bir de son satıra dikkat et: 9780451524935 gerçekten Animal Farm mı? Run'ın çıkış kodu ne olur? Cevaplar "Variable Scope'ları" ve "Collection Runner" bölümlerinde, Newman'ın gerçek çıktısıyla.
Postman'de Neyi Çalıştırabildim, Neyi Dokümandan Anlatıyorum
Postman, ilk yazıdaki matrisin en çok özelliği olan aracı: collection'lar, environment'lar, script'ler, mock server, monitor'lar, ekip workspace'leri. Bunların bir kısmı hesap ve bulut ister. Bu seride kural olarak hesap açmıyorum, bu yüzden ayrımı baştan net yapayım. Gerçek koşu gördüğün her şey (collection'ın kendisi, Newman ve Postman CLI çıktıları, OpenAPI dönüşümü, yerel mock) bu makinede, hesapsız çalıştı. Desktop uygulamasının arayüzü, bulut mock server'ları, Vault ve Native Git'in uygulama tarafı ise Postman Learning Center'dan aktarılıyor.
Bookstore'un collection'ını uygulamada tıklayarak değil, Postman'in Collection v2.1 JSON formatında elle yazdım ve repo'ya postman/ klasörüne koydum: Bookstore.postman_collection.json, dev.postman_environment.json ve veri dosyası books.csv. Uygulamada File, Import ile açılıyor, CI'da da komut satırından koşuyor.
OpenAPI'den Collection Import Etmek
Çoğu ekip işe Bookstore.Api'nin /openapi/v1.json'unu Postman'e import ederek başlar. Uygulamadaki import'u çalıştıramadığım için aynı dönüşümü Postman ekibinin açık kaynak dönüştürücüsü openapi-to-postmanv2 ile yaptım; folder'ları OpenAPI tag'lerine göre kurmasını istedim:
$ curl -s localhost:5080/openapi/v1.json -o openapi.json
$ npx openapi2postmanv2 -s openapi.json -o imported.json -p -O folderStrategy=Tags
Conversion successful, collection written to file
$ jq '{auth, variable, folders: [.item[] | {name, requests: [.item[]? | .name]}]}' imported.json
{
"auth": null,
"variable": [
{
"key": "baseUrl",
"value": "http://localhost:5080"
}
],
"folders": [
{
"name": "Identity",
"requests": [
"/api/auth/login",
"/api/auth/me"
]
},
{
"name": "Catalog",
"requests": [
"/api/books",
"/api/books/:isbn",
"/api/categories",
"/api/books/:isbn/cover",
"/api/books/:isbn/cover"
]
},
{
"name": "Ordering",
"requests": [
"/api/carts",
"Get Cart",
"/api/carts/:cartId/items/:isbn",
"/api/carts/:cartId/items/:isbn",
"/api/orders",
"Get Order"
]
}
]
}
Üç şey dikkat çekiyor. Folder'lar endpoint'lerdeki WithTags("Catalog") çağrılarından geliyor. İstek adları çoğunlukla yol; yalnız WithName("GetCart") ve WithName("GetOrder") verilmiş iki endpoint okunur bir ad almış. İki /api/books/:isbn/cover satırının biri GET, biri PUT ama adlarından ayırt edilmiyor. Endpoint'lere WithSummary("Upload a book cover") gibi açıklamalar eklemek collection'ı da okunur yapar. Üçüncüsü auth: ilk yazıda OpenAPI dokümanına eklediğimiz Bearer security scheme işe yaradı. Korumalı istekler kendiliğinden Bearer auth ile geldi:
$ jq '.item[2].item[4] | {name, auth: .request.auth, body: .request.body.raw}' imported.json
{
"name": "/api/orders",
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{bearerToken}}"
}
]
},
"body": "{\n \"cartId\": \"<uuid>\",\n \"customerName\": \"<string>\",\n \"customerEmail\": \"<string>\"\n}"
}
Import iyi bir iskelet veriyor ama bir başlangıç noktası. Body'ler <string> yer tutucularıyla geliyor, test yok, istekler arasında zincir yok. Asıl sorun güncel tutmak: API değişince yeniden import yeni bir collection üretir, elle eklediğin script'leri ve test'leri taşımaz. İki yol var. Import'u yalnız ilk iskelet için kullanırsın, sonra collection'ı repo'da kod gibi yönetirsin; Bookstore'da bunu yaptım. Ya da Postman'in spec ile collection'ı bağlayan özelliklerine güvenirsin; o zaman da elle yazdığın kısımların nerede durduğunu ekipçe kararlaştırman gerekir.
Variable Scope'ları, Shared ve Local Value
Postman'in dokümanına göre beş variable scope'u var. En genişten en dara: global, collection, environment, data ve local. Aynı ad birden fazla scope'ta varsa en dar olan kazanır, yani öncelik sırası local, data, environment, collection, global. Bookstore collection'ında rolleri şöyle dağıttım:
- Environment (
dev.postman_environment.json): ortama göre değişen her şey:baseUrl,email,password. - Collection: istekler arasında taşınan değerler (
accessToken,cartId,orderUrl) ve varsayılanlar (isbn,expectedTitle). - Data: Collection Runner ya da CLI'a verilen CSV/JSON dosyasındaki satır.
- Local: bir script'in yalnız o istek için koyduğu değer (
pm.variables.set).
Environment dosyası:
{
"id": "2d4c8a1e-7b3f-4e6a-8c2d-5f9e1a0b3c47",
"name": "Bookstore dev",
"values": [
{
"key": "baseUrl",
"value": "http://localhost:5080",
"type": "default",
"enabled": true
},
{
"key": "email",
"value": "ada@example.com",
"type": "default",
"enabled": true
},
{
"key": "password",
"value": "",
"type": "secret",
"enabled": true
}
],
"_postman_variable_scope": "environment"
}
password boş ve secret tipinde. Değer CLI'a --env-var password=... ile, uygulamada da kişinin kendi local value'su olarak giriliyor. Postman burada terimlerini değiştirdi: eski dokümanlarda gördüğün "initial value" ve "current value" yerine artık "shared value" ve "local value" diyor. Shared value Postman bulutuna senkronlanır ve workspace'i gören herkes onu görür. Local value senkronlanmaz. Tipik kaza, bir token'ı ya da şifreyi shared value alanına yazmak. Değer artık bulutta, workspace'in bütün üyelerinde ve environment'ı export eden herkesin dosyasında. Secret tipi değeri arayüzde maskeler ama senkronlanmasını engellemez.
Gerçek secret'lar için Postman Vault var. Local Vault'taki secret'lar yalnız senin Postman'inde durur ve buluta gitmez, bütün planlarda var. Shared Vault ekiple paylaşılır ve Solo, Team ve Enterprise planlarında var. CLI'dan ve CI'dan dış bir vault'a bağlanmak Enterprise planına ait. CI'da bu yüzden en basit yol, değeri pipeline secret'ından --env-var ile vermek.
Script'ler: Token'ı Bir Kez Alıp Saklamak ve pm.test
Collection'ın auth'u Bearer, değeri {{accessToken}}; her istek bunu miras alıyor. Login ve katalog istekleri noauth. Token'ı collection seviyesindeki pre-request script alıyor, her isteğin önünde çalışıyor ve token'ın süresi dolmadıkça yeniden login olmuyor:
// Token'ı bir kez alır, süresinin dolmasına 30 saniye kalana kadar yeniden kullanır.
if (pm.info.requestName === "Login") {
return;
}
const token = pm.collectionVariables.get("accessToken");
const expiresAt = Number(pm.collectionVariables.get("accessTokenExpiresAt") || 0);
if (token && Date.now() < expiresAt - 30000) {
return;
}
pm.sendRequest({
url: pm.variables.replaceIn("{{baseUrl}}/api/auth/login"),
method: "POST",
header: { "Content-Type": "application/json" },
body: {
mode: "raw",
raw: JSON.stringify({ email: pm.variables.get("email"), password: pm.variables.get("password") })
}
}, (error, response) => {
pm.test("automatic login succeeds", () => {
pm.expect(error).to.equal(null);
pm.expect(response.code).to.equal(200);
});
const body = response.json();
pm.collectionVariables.set("accessToken", body.accessToken);
pm.collectionVariables.set("accessTokenExpiresAt", Date.now() + body.expiresIn * 1000);
console.log(`new token for ${pm.variables.get("email")}, expires in ${body.expiresIn}s`);
});
Body'yi JSON.stringify ile kurmak, ikinci yazıda jq -n --arg ile yaptığımızın aynısı: şifrede tırnak olsa da JSON bozulmuyor. expiresIn'i API'nin cevabından okumak, token ömrü değişince script'i değiştirmemek demek.
Post-response script'ler (Postman'in eski adıyla "Tests" sekmesi) pm.test ile assertion yazar ve sonraki isteklere değer bırakır. "Place order" ve "Read order":
pm.test("status is 201 with a Location header", () => {
pm.response.to.have.status(201);
pm.response.to.have.header("Location");
});
pm.collectionVariables.set("orderUrl", pm.response.headers.get("Location"));
// Sipariş id'si "Place order" isteğinin Location header'ından gelir.
pm.variables.set("orderId", pm.collectionVariables.get("orderUrl").split("/").pop());
İkinci parça "Read order"'ın pre-request script'i; orderId'yi local scope'a koyduğu için yalnız o istek boyunca var. URL'si {{baseUrl}}/api/orders/{{orderId}}.
Collection Runner, Newman ve Postman CLI
Uygulamada Collection Runner'ı collection'ın menüsünden açar, environment'ı seçer, istersen bir veri dosyası ve iterasyon sayısı verirsin. Mart 2026'daki plan değişikliğinden beri collection run'ları bütün planlarda sınırsız. Aynı koşunun komut satırı karşılığı iki araçla yapılıyor. Newman yıllardır kullanılan açık kaynak runner. Postman CLI ise Postman'in kendi CLI'ı; Newman'dan taşınma rehberine göre Newman yalnız v2.1 JSON formatını koşabiliyor, Postman CLI v3 YAML (girintiyle yapı kuran, okunabilir veri formatı) formatını da koşuyor ve Postman yeni işler için CLI'ı öneriyor. İkisi de bu makinede proje klasörüne npm install ile kuruldu. Postman CLI'ın paketi kurulumdan sonra bir postinstall script'i çalıştırmak istiyor; kullandığım npm 11.19 install script'lerini varsayılan olarak onaya bağladığı için çalışmadı, CLI yine de çalıştı. Postman CLI'ın yerel dosyayla çalışırken oturum açmayı istemediğini, sonuçları da yalnız oturum açılmışsa buluta gönderdiğini dokümanı söylüyor. Ben oturum açmadım. Bütün collection Newman ile:
$ npx newman run postman/Bookstore.postman_collection.json -e postman/dev.postman_environment.json \
--env-var password=Bookstore-Demo-1 --color off
newman
Bookstore API
❏ Identity
↳ Login
POST http://localhost:5080/api/auth/login [200 OK, 538B, 19ms]
✓ status is 200
✓ token type is Bearer
↳ Me
POST http://localhost:5080/api/auth/login [200 OK, 538B, 1ms]
✓ automatic login succeeds
┌
│ 'new token for ada@example.com, expires in 900s'
└
GET http://localhost:5080/api/auth/me [200 OK, 215B, 4ms]
✓ token belongs to the environment user
❏ Catalog
↳ List books
GET http://localhost:5080/api/books?page=1&pageSize=5 [200 OK, 860B, 154ms]
✓ status is 200
✓ page has at most 5 books
✓ response time is below 500 ms
...
↳ Read order
GET http://localhost:5080/api/orders/6 [200 OK, 334B, 4ms]
✓ order is Placed
┌─────────────────────────┬───────────────────┬──────────────────┐
│ │ executed │ failed │
├─────────────────────────┼───────────────────┼──────────────────┤
│ requests │ 9 │ 0 │
├─────────────────────────┼───────────────────┼──────────────────┤
│ assertions │ 12 │ 0 │
└─────────────────────────┴───────────────────┴──────────────────┘
Pre-request script'in login'i yalnız bir kez yaptığı görülüyor: "Me" isteğinin önünde token yoktu, alındı; sonraki yedi istek aynı token'ı kullandı. Explicit "Login" isteği token'ı saklamıyor, o yalnız login endpoint'inin kendisini test ediyor. Tahmin sorusundaki veri dosyalı koşu:
$ npx newman run postman/Bookstore.postman_collection.json -e postman/dev.postman_environment.json \
--env-var password=Bookstore-Demo-1 --folder "Book by ISBN" -d postman/books.csv --color off
Iteration 1/4
❏ Catalog
↳ Book by ISBN
POST http://localhost:5080/api/auth/login [200 OK, 538B, 27ms]
✓ automatic login succeeds
┌
│ 'new token for ada@example.com, expires in 900s'
└
GET http://localhost:5080/api/books/9780441172719 [200 OK, 389B, 18ms]
✓ 9780441172719 is Dune
Iteration 2/4
↳ Book by ISBN
GET http://localhost:5080/api/books/9780141439587 [200 OK, 382B, 32ms]
✓ 9780141439587 is Emma
Iteration 3/4
↳ Book by ISBN
GET http://localhost:5080/api/books/9780261102217 [200 OK, 389B, 8ms]
✓ 9780261102217 is The Hobbit
Iteration 4/4
↳ Book by ISBN
GET http://localhost:5080/api/books/9780451524935 [200 OK, 378B, 12ms]
1. 9780451524935 is Animal Farm
...
1. AssertionError 9780451524935 is Animal Farm
iteration: 4 expected '1984' to deeply equal 'Animal Farm'
at assertion:0 in test-script
inside "Catalog / Book by ISBN"
$ echo $?
1
Cevaplar: data scope collection scope'tan dar olduğu için her iterasyonda CSV'deki isbn kazandı ve dört farklı kitap istendi. Login yalnız ilk iterasyonda yapıldı, çünkü collection variable'ları run boyunca iterasyonlar arasında korunuyor. 9780451524935 Orwell'in 1984'ü; son satır bilerek yanlış, test düştü ve çıkış kodu 1 oldu. CI'ın ihtiyaç duyduğu sinyal bu.
Aynı collection Postman CLI ile, JUnit raporuyla. Newman'da HTML raporu ayrı bir reporter paketi isterken Postman CLI'da yerleşik geliyor:
$ npx postman collection run postman/Bookstore.postman_collection.json -e postman/dev.postman_environment.json \
--env-var password=Bookstore-Demo-1 -r cli,junit --reporter-junit-export reports/postman-junit.xml --color off
Running your collection...
postman
Bookstore API
Folder Identity
Sub-folder Login
POST http://localhost:5080/api/auth/login [200 OK, 538 B, 12 ms]
Pass status is 200
Pass token type is Bearer
...
Sub-folder Read order
GET http://localhost:5080/api/orders/7 [200 OK, 334 B, 3 ms]
Pass order is Placed
Generating run report [junit]...
Saving run report [junit]...
Report created successfully! Saved to: .../reports/postman-junit.xml
...
| assertions | 12 | 0 |
Parametreler neredeyse aynı: taşınma rehberine göre -e, -d, -n, --env-var, --bail ve -r junit iki araçta da aynı yazılıyor, --folder Postman CLI'da -i oluyor.
Mock Server: Henüz Yazılmamış Endpoint'e Karşı Angular Geliştirmek
Bookstore ekibinde Ayşe, bookstore-web'de sipariş geçmişi sayfasını yazmak istiyor; Emre'nin endpoint'i henüz hazır değil. Postman'in bulut mock server'ı collection'daki kayıtlı örnek cevapları bir URL'den döndürür. Hangi örneğin döneceğini x-mock-response-code gibi header'larla seçersin. Bulut mock hesap gerektirdiği için Postman CLI 1.90'ın yerel mock'unu denedim: postman mock generate bir collection'dan ya da OpenAPI dosyasından çalıştırılabilir bir mock üretiyor:
$ npx postman mock generate openapi.json -o mocks/bookstore --port 4510
✓ mock generated from spec
name: Bookstore.Api | v1
...
source: spec ../../openapi.json · static
Run it with:
postman mock run mocks/bookstore/config.yaml
$ npx postman mock run mocks/bookstore/config.yaml --no-history
Mock server started at http://localhost:4510 (Bookstore.Api | v1)
POST /api/auth/login
GET /api/auth/me
GET /api/books
...
Üretilen default.js sıradan bir Node.js HTTP sunucusu; her endpoint için bir if bloğu ve örnek cevap. Mock'a istek atınca:
$ curl -s localhost:4510/api/orders/7
{"id":-8,"status":"string","placedAtUtc":"2012-08-30T17:44:07.022Z","items":[{"title":"string","unitPrice":0,"quantity":-536594210,"lineTotal":3823123089},{"title":"string","unitPrice":-62.81439162969,"quantity":0,"lineTotal":-51664384133.35143}],"total":0,"currency":"string"}
$ curl -si localhost:4510/api/books/123 -H "x-mock-response-code: 404" | head -1
HTTP/1.1 404 Not Found
$ curl -si -X POST localhost:4510/api/orders | head -1
HTTP/1.1 201 Created
Mock çalışıyor ama verisi işe yaramaz: -536594210 adet, negatif fiyat, "status":"string". Sebep Bookstore.Api'nin OpenAPI dokümanında örnek olmaması; mock da şemadan rastgele değer üretiyor. Ayrıca token istemiyor: Bearer'sız POST /api/orders 201 döndü, gerçek API 401 döner. Angular tarafında 401 akışını mock'la test edemezsin. Mock'u faydalı yapmak için ya OpenAPI dokümanına gerçekçi örnekler eklersin, ya collection'daki isteklere örnek cevapları gerçek API'den kaydedip mock'u collection'dan üretirsin, ya da üretilen dosyayı elle düzenlersin. Son yolda yeniden üretmenin değişikliklerini sileceğini dosyanın kendisi yazıyor. Kod tabanlı mock alternatifleri (WireMock.Net, Prism gibi) Integration ve E2E (uçtan uca) Test serisine kaldı.
Native Git, Planlar ve Ekip İçin Çıkarımlar
Postman v12'nin dokümanına göre Native Git, desktop uygulamasında "Local View" ile collection'ları, environment'ları ve spec'leri repo'daki bir postman/ klasöründe dosya olarak tutuyor. Eşleme .postman/resources.yaml'da duruyor. Collection'lar Collection 3.0 formatında: her istek ayrı bir *.request.yaml dosyası. Ekiple paylaşmak için "Push to Postman Cloud" ile bulut tarafına gönderiliyor. Bu, ilk yazıdaki "bulut collection'ı koddan geride kalır" sorununa Postman'in cevabı. Ama paylaşımın Postman tarafı hâlâ bir workspace ister ve Mart 2026'dan beri ücretsiz plan tek kullanıcılı, takım oluşturamıyor. İki kişi aynı workspace'te çalışacaksa Team planı (yıllık ödemeyle kullanıcı başına aylık 19 dolar) gerekiyor.
Bookstore için çıkardığım kural: collection Git'te yaşar, Postman onu açan bir istemcidir. Repo'daki postman/ klasörü review'dan geçer, CI'da Postman CLI ya da Newman ile koşar; Postman'i kullanmak isteyen geliştirici dosyayı import eder ya da Native Git ile açar. Bulut workspace'i ancak monitor, bulut mock ya da paylaşılan Vault gibi bulutta olması gereken bir şey lazım olduğunda devreye girer, o zaman da maliyetini bilerek.
Üretimde Dikkat
Production environment'ını Postman'de tutuyorsan içinde shared value olarak hiçbir secret durmasın. Environment'ı export eden herkes shared value'ları dosyada açıkça görür. Production'a karşı çalışan collection'ları ayrı tut ve yazma isteklerini çıkar; Runner'da yanlış environment seçmek, bir data dosyasının her satırı için gerçek sipariş oluşturmak demek.
Pre-request script'teki otomatik login production'da tehlikeli olabilir. Script her run'da login olur; login endpoint'inde rate limit ya da hesap kilitleme varsa (token endpoint'lerini korumak API Güvenliği serisinde anlatılıyor) sık koşan bir monitor gerçek bir kullanıcı hesabını kilitleyebilir. Monitor'lar ve CI için insan hesabı değil, ayrı bir servis kimliği kullan.
Script'ler sandbox'ta çalışsa da pm.sendRequest istediği adrese istek atabilir. Dışarıdan alınan bir collection'ı çalıştırmadan önce collection ve folder seviyesindeki script'lere bak; environment'ındaki token'ı başka bir adrese göndermesi bir satırlık iştir.
Sık Düşülen Tuzaklar
Token'ı ya da şifreyi shared value'ya yazmak. Değer buluta gider. Local value, Vault ya da CI'da --env-var kullan; repo'daki environment dosyasında secret alanları boş kalsın.
Test mantığını yalnız Postman'de tutmak. "Ordering more than available returns 409" gibi bir iş kuralını yalnız bir pm.test'te kontrol etmek, kuralı ekibin göremeyeceği bir yere saklamak demek. Bookstore'da aynı kural OrderingTests'te WebApplicationFactory ile test ediliyor. Collection akışın ayakta olduğunu söylesin, iş kuralının sahibi codebase'teki integration test'ler olsun.
Veri dosyasında beklenen değeri kontrol etmemek. Yukarıdaki CSV'nin son satırı gibi yanlış bir beklenti, testi API'nin değil verinin kırdığı bir run üretir. Data dosyalarını da code review'a sok.
Collection variable'larının run'lar arasında kaldığını unutmak. Uygulamada bir önceki run'dan kalan cartId, silinmiş bir sepete istek attırır. Akışın başında ihtiyaç duyduğun variable'ları sıfırla ya da her run'ı temiz bir environment'la başlat.
Küçük Bir Deneme
★☆☆ Collection'ı Newman ile -n 3 parametresiyle üç iterasyon koş ve login'in kaç kez yapıldığını say. Sonra accessTokenExpiresAt karşılaştırmasındaki 30 saniyeyi 899.000 milisaniyeye çıkar ve tekrar say.
★★☆ "Ordering" folder'ına bir istek ekle: Grace'in token'ıyla Ada'nın siparişini okusun ve 200 alsın, ardından Ada'nın token'ıyla başka birinin siparişini okuyup 404 alsın. İkinci kullanıcı için environment'a staffEmail ve staffPassword ekle; token'ı pm.sendRequest ile ayrı bir collection variable'a al.
★★★ Mock'u faydalı hale getir: Bookstore.Api'nin OpenAPI dokümanına bir schema transformer ile OrderView için gerçekçi bir örnek ekle (The Hobbit, 2 adet, 659.80 TRY (Türk lirası)), postman mock generate'i yeniden çalıştır ve GET /api/orders/7'nin artık anlamlı bir sipariş döndürdüğünü gör.
Postman collection'ı repo'ya koyabiliyoruz ama JSON'u elle diff'lemek zor: bir test satırının değişmesi, uzun bir exec array'inde tırnaklı satırlar olarak görünüyor. Bir sonraki yazıda baştan dosya tabanlı tasarlanmış bir istemciye geçiyoruz: Bruno, OpenCollection YAML ve CLI ile GitHub Actions'ta koşan bir collection.