İçeriğe geç
XDD.baby Yazılım Öğrenme
Sözlük Hata rehberi 0/56

Blok 4 · Ders 26

HTTP derinlemesine

İstek ve yanıtın bütün parçaları: metotlar, durum kodları, başlıklar, gövde ve REST mantığı; terminalden istek atmak.

Bu dersin sonunda

  • Bir HTTP isteğinin ve yanıtının bütün parçalarını (metot, yol, başlıklar, gövde, durum kodu) gerçek bir mesajda gösterip adlandırabilirsin
  • Yapılacak işe göre GET, POST, PUT, PATCH ve DELETE arasından doğru metodu seçebilirsin
  • Durum kodunun ilk rakamından sorunun kimde olduğunu söyleyip sık kodları (200, 201, 204, 301, 400, 401, 403, 404, 500) tanıyabilirsin
  • Content-Type başlığıyla JSON gönderebilir, gelen yanıtın türünü okumadan önce denetleyebilirsin
  • REST kurallarına uyan adresler tasarlayıp kötü tasarlanmış bir adresi fark edebilirsin
  • PowerShell'den curl.exe ve Invoke-RestMethod ile istek atabilir, curl takma adı ve tırnak tuzaklarından kaçınabilirsin
Bu sayfada
  1. Hazırlık: klasör ve üç deneme adresi
  2. Terminalden ilk istek: curl.exe
  3. İstek ve yanıtın parçaları
  4. Metotlar: ne yapmak istiyorsun?
  5. Durum kodları: sunucunun kısa cevabı
  6. Başlıklar, gövde ve Content-Type
  7. Authorization: kimliğini göstermek
  8. REST: kaynaklar ve adresler
  9. PowerShell'in kendi aracı: Invoke-RestMethod
  10. Çerez ve oturum: sunucu seni nasıl hatırlar?
  11. Sık hatalar
  12. Görevler
  13. Kendini sına
  14. Kayıt noktası

Bu ders yeni bir bloğun, sunucu tarafının ilk dersi. Şimdiye kadar hep istek atan taraftaydın: tarayıcı ya da fetch. Bu blokta isteği karşılayan tarafı, yani sunucuyu yazacaksın. Sunucu, gelen HTTP mesajını okuyup HTTP mesajıyla cevap veren bir programdır; o yüzden önce bu mesajların dilini iyi bilmen gerekiyor.

Bu derste mesajı açıp her parçasına tek tek bakacaksın: metot, yol, başlıklar, gövde ve durum kodu. Tarayıcı bu parçaları senden saklar, terminal saklamaz. Dersin çoğunda PowerShell'de çalışacak, curl.exe ve Invoke-RestMethod ile gerçek sunuculara istek atacaksın. Sonunda iyi bir API adresinin nasıl tasarlandığını ve bir sitenin seni çerezle nasıl hatırladığını da bileceksin.

Hazırlık: klasör ve üç deneme adresi

Bu dersin dosyalarını ayrı bir klasörde topla. Son iki derste VS Code'da proje klasörleri açıktı; File → Open Folder... ile yeniden C:\kod\ogren'i aç ve terminale yaz:

Terminal — PowerShell
PS C:\kod\ogren> mkdir ders26     Directory: C:\kod\ogren  Mode                 LastWriteTime         Length Name----                 -------------         ------ ----d-----        11.10.2026     15:02                ders26 PS C:\kod\ogren> cd ders26

mkdir'in yazdığı tablo yalnızca "klasör oluşturuldu" diyor; tarih sende farklı olur, geçebilirsin. İstem artık PS C:\kod\ogren\ders26>; bu dersteki bütün komutları burada çalıştır.

Bu derste PowerShell'in sürümü önemli, çünkü göreceğin tuzakların çoğu Windows'la gelen eski sürüme özgü. Hangi sürümü kullandığını sor:

Terminal — PowerShell
PS C:\kod\ogren\ders26> $PSVersionTable.PSVersion Major  Minor  Build  Revision-----  -----  -----  --------5      1      26100  9444

5 ve 1: Windows'la gelen Windows PowerShell 5.1; VS Code'un terminali de varsayılan olarak bunu açar. Build ve Revision sende farklı olabilir. PowerShell 7'yi ayrıca kurduysan VS Code onu açabilir, o zaman ilk sayı 7 çıkar. Ders boyunca "PowerShell 5.1" dediğimiz yerler büyük olasılıkla senin terminalin.

İnternet bağlantısı gerekiyor, çünkü istekleri üç gerçek sunucuya atacaksın:

  • Data Dragon (ddragon.leagueoflegends.com): Riot'un oyun verileri. Yalnızca okumana izin verir.
  • httpbin (httpbin.org): ayna sunucu; ne gönderirsen sana aynen geri anlatır. Metotları, başlıkları ve gövdeleri denemek için.
  • GitHub API (api.github.com): gerçek ve iyi tasarlanmış bir API. Hesap gerekmez; saatte 60 istek hakkın var.

httpbin bir sunucu taklidi yapar: ona "sil" dediğinde hiçbir şey silinmez, yalnızca "şöyle bir istek aldım" diye anlatır. Kendi sunucunu yazana kadar (Ders 27) metotları ve gövdeleri onunla deneyeceksin.

Terminalden ilk istek: curl.exe

Tarayıcıya bir adres yazınca sayfayı görürsün ama mesajın kendisini görmezsin. Hangi başlıklar gitti, sunucu hangi kodla cevap verdi? fetch ile bunları tek tek console.log'la yazdırman gerekir. curl ise adresini verdiğin sunucuya istek atıp gelen yanıtı terminale olduğu gibi yazan küçük bir programdır. Windows 10 ve 11'de hazır gelir, kurman gerekmez. Ders 24'te onu bir kez kalıp olarak kullanmıştın; API belgelerindeki örneklerin çoğu da curl komutuyla yazılır.

İlk isteği at. Komutu sonundaki .exe ile birlikte, curl.exe diye yaz; nedenini hemen aşağıda göreceksin.

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe https://ddragon.leagueoflegends.com/realms/tr.json{"n":{"item":"16.20.1","rune":"7.23.1","mastery":"7.23.1","summoner":"16.20.1","champion":"16.20.1","profileicon":"16.20.1","map":"16.20.1","language":"16.20.1","sticker":"16.20.1"},"v":"16.20.1","l":"tr_TR","cdn":"https://ddragon.leagueoflegends.com/cdn","dd":"16.20.1","lg":"16.20.1","css":"16.20.1","profileiconmax":28,"store":null}

Gelen şey Türkiye sunucusunun ayar dosyası: v güncel oyun sürümü, l dil. Sende sürüm numarası daha büyük olabilir. curl yalnızca gövdeyi, yani yanıtın asıl içeriğini yazdı. Şimdi aynı komuta -i ekle (include, dahil et):

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -i https://ddragon.leagueoflegends.com/realms/tr.jsonHTTP/1.1 200 OKContent-Type: application/jsonContent-Length: 335Connection: keep-aliveAccess-Control-Allow-Origin: *Access-Control-Allow-Methods: GET, HEADAccess-Control-Max-Age: 3000Last-Modified: Tue, 06 Oct 2026 21:17:54 GMTx-amz-server-side-encryption: AES256x-amz-version-id: DdzBYPceetXTplWUhEU8p2wp0dWD2aP.Accept-Ranges: bytesServer: AmazonS3Date: Sun, 11 Oct 2026 13:08:30 GMTETag: "6cd5a3c11e12cf57bb86151cb0be5faa"X-Cache: Hit from cloudfrontVia: 1.1 79d85d2de1f5aa38558ef6bab6274390.cloudfront.net (CloudFront)X-Amz-Cf-Pop: FRA56-P9X-Amz-Cf-Id: fnQc1NsdkE-KrArlsjjLbmlSj4mt9Aly7tZQxlkmX3p2Asu23haDsA==Age: 199 {"n":{"item":"16.20.1","rune":"7.23.1","mastery":"7.23.1","summoner":"16.20.1","champion":"16.20.1","profileicon":"16.20.1","map":"16.20.1","language":"16.20.1","sticker":"16.20.1"},"v":"16.20.1","l":"tr_TR","cdn":"https://ddragon.leagueoflegends.com/cdn","dd":"16.20.1","lg":"16.20.1","css":"16.20.1","profileiconmax":28,"store":null}

Gövdenin üstüne bir sürü satır geldi. İlki HTTP/1.1 200 OK: sunucu "tamam" diyor. Altındaki Ad: değer satırları yanıtın başlıkları; sonra bir boş satır ve tanıdık gövde. Başlıkların çoğu sunucunun ve aradaki önbellek servisinin notları (x-amz-…, X-Cache, Via); seni ilgilendirenleri birazdan ayıklayacağız. Date gibi satırlar ve uzun kimlik kodları sende farklı çıkar.

curl'ün en sık kullanacağın seçenekleri:

SeçenekNe yapar?
-iYanıtın başlıklarını da yazar (include: dahil et).
-IYalnızca başlıkları ister, gövdeyi istemez (büyük I).
-vGiden isteği de gösterir (verbose: ayrıntılı).
-X POSTMetodu seçer; yazmazsan GET gider.
-H "Ad: değer"İsteğe bir başlık ekler (header: başlık).
-d "..."Gövde gönderir (data: veri). -X yazmazsan metodu kendiliğinden POST yapar.
-LYönlendirmeyi takip eder (location: yer).
-b, -c-b çerez gönderir, -c gelen çerezleri dosyaya yazar.

Büyük-küçük harfe dikkat: -i ile -I iki ayrı seçenektir.

Sık hatacurl yazınca Supply values for the following parameters ya da Security Warning çıkıyor

Ne zaman çıkar? Windows'la gelen PowerShell'de (sürüm 5.1) komutu .exe olmadan, yalnızca curl diye yazınca. Bu PowerShell'de curl, gerçek curl programının değil, PowerShell'in kendi Invoke-WebRequest komutunun takma adıdır (alias): bir komuta verilmiş ikinci isim. Invoke-WebRequest senin -i'ni kendi -InFile (gönderilecek dosya) seçeneği sanar, adresi dosya adı olarak oraya koyar ve eksik kalan adresi sorar:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl -i https://ddragon.leagueoflegends.com/realms/tr.json cmdlet Invoke-WebRequest at command pipeline position 1Supply values for the following parameters:Uri:

Seçeneksiz yazarsan bu kez bir güvenlik sorusu gelir (9 Aralık 2025 ve sonrasındaki Windows güncellemeleriyle eklendi; güncel olmayan bir bilgisayarda soru çıkmaz):

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl https://ddragon.leagueoflegends.com/realms/tr.json Security Warning: Script Execution RiskInvoke-WebRequest parses the content of the web page. Script code in the web page might be run when the page isparsed.      RECOMMENDED ACTION:      Use the -UseBasicParsing switch to avoid script code execution.       Do you want to continue? [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"):

Nasıl düzelir? Uri: sorusunda Ctrl+C'ye bas. Enter'a basarsan Cannot find drive. A drive with the name 'https' does not exist. gibi anlamsız bir hata gelir, çünkü adres dosya adı sanılmıştı. Güvenlik sorusunda Enter yeter: varsayılan cevap "Hayır" (N), komut Operation cancelled due to security concerns diyerek durur. Sonra komutu curl.exe diye yeniden yaz. Bir adın nereye gittiğini PowerShell'e sorabilirsin:

Terminal — PowerShell
PS C:\kod\ogren\ders26> Get-Command curl, curl.exe CommandType     Name                                               Version    Source-----------     ----                                               -------    ------Alias           curl -> Invoke-WebRequestApplication     curl.exe                                           8.21.0.0   C:\WINDOWS\system32\curl.exe

curl takma ad, curl.exe gerçek program. curl.exe yazma alışkanlığı hangi PowerShell'de olursan ol doğru programı çalıştırır. Ders 0'da gördüğün gibi PowerShell'in kendi mesajları Türkçe Windows'ta da büyük olasılıkla İngilizce çıkar.

İstek ve yanıtın parçaları

Ders 18'de tarayıcının attığı bir isteğin parçalarına ilk kez bakmıştın. Şimdi aynı parçaları kendi isteğinde göreceksin. İsteği bu kez -v (verbose, ayrıntılı) ile at; curl senin gönderdiğin isteği de yazar:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -v https://ddragon.leagueoflegends.com/realms/tr.json* Host ddragon.leagueoflegends.com:443 was resolved....* using HTTP/1.x> GET /realms/tr.json HTTP/1.1> Host: ddragon.leagueoflegends.com> User-Agent: curl/8.21.0> Accept: */*>* Request completely sent off...< HTTP/1.1 200 OK< Content-Type: application/json< Content-Length: 335< Connection: keep-alive< Access-Control-Allow-Origin: *...< Age: 15<{"n":{"item":"16.20.1","rune":"7.23.1","mastery":"7.23.1","summoner":"16.20.1","champion":"16.20.1","profileicon":"16.20.1","map":"16.20.1","language":"16.20.1","sticker":"16.20.1"},"v":"16.20.1","l":"tr_TR","cdn":"https://ddragon.leagueoflegends.com/cdn","dd":"16.20.1","lg":"16.20.1","css":"16.20.1","profileiconmax":28,"store":null}* Connection #0 to host ddragon.leagueoflegends.com:443 left intact

Üç tür satır var. * ile başlayanlar curl'ün kendi notları (adres bulundu, bağlantı kuruldu, şifreleme yapıldı). > ile başlayanlar bilgisayarından giden istek, < ile başlayanlar sunucudan gelen yanıt. Uzun bölümleri ... ile kısalttık; sende bağlantı satırlarında ağ adresleri de görünür. En sondaki * Connection #0… notu gövdeye yapışık, çünkü gövdenin sonunda satır sonu yok.

İstekistemciden sunucuya POST /maclar HTTP/1.1 metot yol sürüm Host: api.example.com Content-Type: application/json Content-Length: 37 {"sampiyon":"Ahri","kill":7,"olum":2} 1 İstek satırı metot, yol ve sürüm 2 Başlıklar Ad: değer satırları 3 Boş satır 4 Gövdegiden veri Yanıtsunucudan istemciye HTTP/1.1 201 Created sürüm kod açıklama Content-Type: application/json Location: /maclar/42 {"id":42,"sampiyon":"Ahri"} 1 Durum satırı sürüm, durum kodu, açıklama 2 Başlıklar 3 Boş satır 4 Gövdegelen veri
Şekil 26.1 Bir HTTP isteği ve yanıtı parça parça. Şekildeki istek bir maç kaydı gönderiyor, yanıt da kaydın oluşturulduğunu söylüyor.

İsteğin parçaları

Senin bilgisayarından giden > satırları dört parçadan oluşur:

  1. İstek satırı: GET /realms/tr.json HTTP/1.1. Önce metot (GET, "getir"), sonra yol (/realms/tr.json), en sonda protokolün sürümü. Alan adı bu satırda yok; o Host başlığında gider. Tek bir sunucu aynı anda birçok siteye hizmet verebildiği için hangi siteyi istediğini böyle söylersin.
  2. Başlıklar: Host hangi site, User-Agent isteği hangi programın gönderdiği (tarayıcın burada kendi adını yazar), Accept hangi türde cevap kabul ettiğin (*/*, "ne olursa").
  3. Boş satır: "başlıklar bitti" demek.
  4. Gövde: Bu istekte yok. GET bir şey ister, göndermez. Sunucuya veri yollarken, örneğin yeni bir maç kaydında, gövde dolu olur.

Yanıtın parçaları

Sunucudan gelen < satırları da aynı kalıpta:

  1. Durum satırı: HTTP/1.1 200 OK. Sürüm, üç haneli durum kodu ve kısa açıklaması. Durum kodlarına aşağıda ayrı bir bölüm ayırdık.
  2. Başlıklar: Content-Type: application/json gövdenin türü, Content-Length: 335 gövdenin bayt sayısı; Server, Date ve sunucunun başka notları.
  3. Boş satır.
  4. Gövde: 335 baytlık JSON.

Metotlar: ne yapmak istiyorsun?

Maç günlüğünü bir sunucuya taşıdığını düşün. Aynı maç listesiyle dört iş yapacaksın: listeye bakmak, yeni maç eklemek, bir maçı düzeltmek, bir maçı silmek. Her iş için ayrı bir adres uydurmak yerine (/macEkle, /macSil) isteğin ilk sözcüğünü değiştirirsin. O sözcüğe metot denir. Buradaki metot, Ders 5'teki dizi metotlarıyla (push, pop) aynı şey değil: HTTP'de isteğin türünü söyleyen sözcük.

MetotNe yapar?Oyundan
GETOkur, getirir; hiçbir şeyi değiştirmez. Gövde göndermez.Tab'a basıp skor tablosuna bakmak
POSTYeni bir kayıt oluşturur. Yeni kaydın bilgileri gövdede gider.Dükkândan yeni bir eşya almak
PUTVar olan kaydı tümüyle yenisiyle değiştirir. Kaydın tamamı gövdede gider.Rün sayfasını baştan yazıp kaydetmek
PATCHVar olan kaydın bir kısmını değiştirir. Yalnızca değişen alanlar gövdede gider.Rün sayfasında yalnızca bir rünü değiştirmek
DELETEKaydı siler. Genelde gövde göndermez.Envanterdeki eşyayı satmak

İki metodu daha duyacaksın. HEAD, GET'in gövdesiz hâlidir: "yalnızca başlıkları ver". curl'deki -I tam olarak bunu gönderir. OPTIONS'ı ise tarayıcı, başka bir kökene giden bazı isteklerden önce "bu isteğe izin var mı?" diye sormak için kendiliğinden gönderir.

Metodu seçmek: -X

curl varsayılan olarak GET gönderir. Başka bir metot için -X kullan. httpbin'in /anything adresi her metodu kabul eder ve aldığı isteği JSON olarak geri anlatır:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -X DELETE https://httpbin.org/anything/sampiyonlar/teemo{  "args": {},  "data": "",  "files": {},  "form": {},  "headers": {    "Accept": "*/*",    "Host": "httpbin.org",    "User-Agent": "curl/8.21.0",    "X-Amzn-Trace-Id": "Root=1-6acb9026-2abc33dd6fb92a517a57fda7"  },  "json": null,  "method": "DELETE",  "origin": "203.0.113.7",  "url": "https://httpbin.org/anything/sampiyonlar/teemo"}

Hiçbir şey silinmedi; httpbin bir ayna. Yansımada isteğin gerçekten DELETE olarak gittiğini (method), hangi adrese gittiğini (url) ve hangi başlıklarla gittiğini (headers) görüyorsun. Gövde göndermediğin için data boş, json da null. origin senin internet (IP) adresin; derste gerçeğini 203.0.113.7 ile değiştirdik.

PUT ile PATCH farkı

İkisi de var olan bir kaydı değiştirir. Fark, gövdeye yazmadığın alanlara ne olduğunda:

Sunucudaki kayıt isim: "Ahri" hp: 100 mana: 300 PUT {"hp": 120} PATCH {"hp": 120} hp: 120 isim: "Ahri" mana: 300 isim ve mana gitti yalnızca hp değişti isim: "Ahri" hp: 120 mana: 300
Şekil 26.2 Aynı gövde, iki farklı sonuç: PUT kaydı gövdeyle değiştirir, PATCH yalnızca gövdedeki alanı değiştirir.

API'lerin çoğu düzeltmeler için PATCH kullanır, çünkü kaydın tamamını yeniden göndermek gerekmez. PUT kullanan bir API'ye eksik bir kayıt gönderirsen ya alanları kaybedersin ya da sunucu "eksik alan var" diye isteği reddeder.

Sık hata405 METHOD NOT ALLOWED: adres bu metodu kabul etmiyor

Ne zaman çıkar? Bir adrese, onun kabul etmediği bir metotla istek atınca. httpbin'in /post adresi yalnızca POST kabul eder; curl ise -X vermezsen GET gönderir:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -i https://httpbin.org/postHTTP/1.1 405 METHOD NOT ALLOWEDDate: Sun, 11 Oct 2026 13:15:40 GMTContent-Type: text/htmlContent-Length: 178Connection: keep-aliveServer: gunicorn/19.9.0Allow: POST, OPTIONSAccess-Control-Allow-Origin: *Access-Control-Allow-Credentials: true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><title>405 Method Not Allowed</title><h1>Method Not Allowed</h1><p>The method is not allowed for the requested URL.</p>

Durum satırında 405, başlıklarda Allow: POST, OPTIONS (sende sırası OPTIONS, POST olabilir): sunucu hangi metotları kabul ettiğini de söylüyor. Gövde bir HTML sayfası; birazdan onu JSON sanan bir programın nasıl çöktüğünü göreceksin.

Nasıl düzelir? Allow başlığına ya da API'nin belgesine bak ve doğru metodu -X ile seç: curl.exe -X POST https://httpbin.org/post. Her sunucu bu kurala harfi harfine uymaz: Data Dragon'a POST atarsan 405 değil, 403 Forbidden ve bir HTML hata sayfası gelir. Kod farklı, anlam aynı: bu adres o metodu kabul etmiyor.

Durum kodları: sunucunun kısa cevabı

Yanıtın ilk satırındaki üç haneli sayı, programının "işe yaradı mı?" sorusunun cevabıdır. Yanındaki açıklama sunucudan sunucuya değişebilir (Not Found, httpbin'de NOT FOUND); programlar hep sayıya bakar.

İlk rakam Anlamı ve sık kodlar Ne yaparsın? 1xx Bilgi İş sürüyor; nadiren görürsün. Bir şey yapma 2xx Başarılı 200 OK · 201 Created · 204 No Content Devam et 3xx Yönlendirme: başka adrese bak 301 kalıcı · 302 geçici · 304 değişmedi Location'daki adrese git 4xx İstemci hatası: sorun sende 400 · 401 · 403 · 404 · 405 · 409 · 429 İsteğini düzelt 5xx Sunucu hatası: sorun onda 500 · 502 · 503 · 504 Bekle, yeniden dene
Şekil 26.3 Durum kodunun ilk rakamı, sorunun kimde olduğunu ve ne yapman gerektiğini söyler.

Bir kodu okurken önce ilk rakama bak. 4 ile başlıyorsa sorun senin isteğinde: adres, metot, gövde ya da kimlik bilgisi yanlış. Aynı isteği yeniden göndermek bir şey değiştirmez, isteğini düzeltmen gerekir. Tek istisna 429: isteğin doğru ama çok sık; biraz bekleyip yeniden gönderirsin. 5 ile başlıyorsa sorun sunucuda; isteğin doğru olabilir, biraz bekleyip yeniden dene. En sık göreceğin kodlar:

Kod ve adıNe zaman?Oyundan
200 OKİstek başarılı, gövdede cevap var.Maç bulundu.
201 CreatedYeni kayıt oluşturuldu (POST'tan sonra); Location başlığı yeni kaydın adresini verir.Yeni lobi kuruldu.
204 No ContentBaşarılı ama gövde yok (çoğu zaman DELETE'ten sonra).Arkadaş listenden silindi; söylenecek başka şey yok.
301 Moved PermanentlyAdres kalıcı olarak taşındı; yenisi Location'da.Sunucunun adresi değişti, yenisine git.
302 FoundGeçici yönlendirme.Bakım sırasında seni duyuru sayfasına almak.
400 Bad Requestİstek bozuk: eksik alan, geçersiz JSON.Formda doğum tarihi kutusuna harf yazdın.
401 UnauthorizedKim olduğunu söylemedin ya da kimlik bilgin yanlış.Giriş yapmadan profiline bakmaya çalıştın.
403 ForbiddenKim olduğun belli ama bu işe iznin yok.30. seviye olmadan dereceli sıraya girmeye çalıştın.
404 Not FoundBöyle bir adres ya da kayıt yok.Aradığın sihirdar adı yok.
405 Method Not AllowedAdres var ama bu metodu kabul etmiyor.İzleyici modunda yetenek kullanmaya çalıştın.
409 ConflictVar olan bir kayıtla çakışıyor.Seçtiğin sihirdar adı alınmış.
429 Too Many RequestsÇok sık istek attın, biraz bekle.Sohbette çok hızlı yazdığın için susturuldun.
500 Internal Server ErrorSunucunun kodunda bir şey patladı.İstemcide "Beklenmeyen bir hata oluştu".
502 Bad Gateway, 503 Service Unavailable, 504 Gateway TimeoutSunucu ya da arkasındaki servis cevap veremiyor.Sunucular bakımda.

Yönlendirme (redirect): 3xx

3 ile başlayan kodlar "aradığın şey başka yerde" der ve isteği yeni bir adrese yönlendirir (redirect); yeni adres Location başlığındadır. -I ile yalnızca başlıkları iste:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -I http://github.comHTTP/1.1 301 Moved PermanentlyContent-Length: 0Location: https://github.com/

http ile istedin, sunucu "kalıcı olarak https'e taşındım" dedi. Tarayıcı ve fetch Location'daki adrese kendiliğinden gider, sen fark etmezsin bile. curl gitmez; gitmesini istersen -L eklersin.

Bu grupta seni başka bir adrese göndermeyen bir kod var: 304 Not Modified (değişmedi). Dersin başındaki curl.exe -i çıktısında ETag: "6cd5…" diye bir satır vardı; o, dosyanın parmak izi. Tarayıcı aynı dosyayı ikinci kez isterken elindeki kopyanın parmak izini de gönderir. Dosya değişmemişse sunucu gövdesiz, kısa bir 304 döndürür ve tarayıcı kendi önbelleğindeki kopyayı kullanır. Maç tekrarını indirmeden önce "bende bu sürüm var" demek gibi: değişmediyse yeniden indirmezsin. Bu işi tarayıcı kendisi yapar, senin kodun genelde 304 görmez.

"Yönlendirme" sözcüğünü Ders 27'de başka bir anlamda da duyacaksın: sunucunun gelen isteği adresine göre kendi içindeki doğru koda göndermesi (routing). Buradaki yönlendirme ise istemciyi başka bir adrese gönderir.

Kodlar programda: yanit.status

fetch her yanıtın kodunu yanit.status'a, açıklamasını yanit.statusText'e koyar. VS Code'un solundaki dosya listesinde ders26 klasörüne sağ tıkla, New File ile durum.mjs adında bir dosya oluştur ve dört adresi sırayla dene:

durum.mjs — ogren — Visual Studio Code
durum.mjs
const adresler = [    "https://ddragon.leagueoflegends.com/realms/tr.json",    "https://ddragon.leagueoflegends.com/api/Versions.json",    "https://httpbin.org/status/404",    "https://httpbin.org/status/500"] for (const adres of adresler) {    const yanit = await fetch(adres)    console.log(yanit.status, yanit.statusText, yanit.ok)}
PROBLEMSOUTPUTDEBUG CONSOLETERMINAL
PS C:\kod\ogren\ders26> node durum.mjs200 OK true403 Forbidden false404 NOT FOUND false500 INTERNAL SERVER ERROR false
Ln 1, Col 1Spaces: 4UTF-8JavaScript

Dört istek, dört yanıt. fetch hiçbirinde hata fırlatmadı; ok yalnızca 200–299 arasında true.

İkinci adreste versions.json yerine Versions.json yazdık. Çoğu sunucuda yolun büyük-küçük harfi fark eder. Data Dragon olmayan dosya için 404 yerine 403 Forbidden döndürüyor (Ders 15'te de görmüştün); her sunucu kitaba harfi harfine uymaz. O yüzden programın 403'ü de 404'ü de "alamadım" diye karşılayabilmeli.

Programında açıklamaya (statusText) değil, sayıya (status) güven. Açıklamanın sunucudan sunucuya değiştiğini çıktıda da görüyorsun (NOT FOUND büyük harfle). Tarayıcıda boş bile gelebilir: HTTP/2 ile konuşan sitelerde durum satırında açıklama yoktur, statusText boş metin olur.

5xx gerçek hayatta sık görülür: sunucu bir an aşırı yüklenir, bakıma girer ya da arkasındaki servis geç cevap verir. Çoğu zaman aynı istek birkaç saniye sonra düzgün cevap alır. O yüzden 5 ile başlayan bir kod görünce isteğini değiştirmeden önce biraz bekleyip bir kez daha dene.

Başlıklar, gövde ve Content-Type

Sunucuya gövde gönderdiğinde sunucunun onu nasıl okuyacağını bilmesi gerekir: JSON mu, form mu, resim mi? Aynı baytlar farklı türlerde bambaşka anlamlara gelir. Bunu Content-Type başlığı söyler. Yanıtta da aynı başlık senin programına "bu gövde JSON" ya da "bu bir HTML sayfası" der.

Content-TypeGövdede ne var?
application/jsonJSON
text/html; charset=utf-8HTML sayfası, UTF-8 harf kodlamasıyla
text/plainDüz metin
application/xmlXML (Data Dragon'un hata cevabı böyle)
image/pngPNG resim
application/x-www-form-urlencodedHTML formunun varsayılan gönderimi: isim=Ahri&koridor=orta

Sık göreceğin başlıklar:

BaşlıkNerede gider, ne söyler?
Hostİstekte: hangi site.
User-Agentİstekte: isteği gönderen program.
Acceptİstekte: hangi türde cevap istediğin.
Content-Typeİkisinde de: gövdenin türü.
Content-Lengthİkisinde de: gövdenin bayt sayısı.
Authorizationİstekte: kimlik bilgisi (anahtar).
Cookieİstekte: tarayıcının sakladığı çerezler.
Set-CookieYanıtta: "bu çerezi sakla".
LocationYanıtta: yönlendirmede yeni adres, oluşturmada yeni kaydın adresi.
AllowYanıtta: adresin kabul ettiği metotlar.

curl.exe ile JSON göndermek

Sunucuya JSON göndermek üç şey ister: bir metot (POST), Content-Type: application/json başlığı ve geçerli bir JSON gövdesi. PowerShell'de gövdeyi bir dosyaya yazmak en sorunsuz yoldur; nedenini aşağıdaki hata kartında göreceksin. ders26 klasöründe ahri.json adında bir dosya oluştur:

ahri.json
{    "isim": "Ahri",    "koridor": "orta"}

Sonra gönder. -H bir başlık ekler, -d gövde gönderir. @ işareti "bu bir dosya adı, içeriğini gönder" demektir ve tırnak içinde yazılmalıdır:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -X POST https://httpbin.org/anything/sampiyonlar -H "Content-Type: application/json" -d "@ahri.json"{  "args": {},  "data": "{    \"isim\": \"Ahri\",    \"koridor\": \"orta\"}",  "files": {},  "form": {},  "headers": {    "Accept": "*/*",    "Content-Length": "42",    "Content-Type": "application/json",    "Host": "httpbin.org",    "User-Agent": "curl/8.21.0",    "X-Amzn-Trace-Id": "Root=1-6acb9027-4a0ff6e71108bcd5136aeeed"  },  "json": {    "isim": "Ahri",    "koridor": "orta"  },  "method": "POST",  "origin": "203.0.113.7",  "url": "https://httpbin.org/anything/sampiyonlar"}

data, sunucuya giden ham metin. curl -d ile gönderirken dosyadaki satır sonlarını siler; JSON yine geçerli. json, httpbin'in o metni JSON olarak okuyabildiği hâli: doluysa gövde doğru gitmiş demektir. Yansımadaki headers içinde senin eklediğin Content-Type da var.

Sık hataContent-Type unutulunca "json": null: gövde form'a düşmüş

Ne zaman çıkar? curl'e -d ile gövde verip -H "Content-Type: application/json" yazmayı unutunca. curl o zaman gövdeyi bir HTML formu gibi işaretler:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -X POST https://httpbin.org/anything/sampiyonlar -d "@ahri.json"{  "args": {},  "data": "",  "files": {},  "form": {    "{    \"isim\": \"Ahri\",    \"koridor\": \"orta\"}": ""  },  "headers": {    "Accept": "*/*",    "Content-Length": "42",    "Content-Type": "application/x-www-form-urlencoded",    "Host": "httpbin.org",    "User-Agent": "curl/8.21.0",    "X-Amzn-Trace-Id": "Root=1-6acb9028-4c9229ce0e8f347244bfe51e"  },  "json": null,  "method": "POST",  "origin": "203.0.113.7",  "url": "https://httpbin.org/anything/sampiyonlar"}

Sunucu gövdeyi isim=Ahri gibi bir form sandı: bütün JSON'u tek bir alanın adı yaptı, değerini boş bıraktı. json alanı null.

Nasıl düzelir? Gövde gönderen her isteğe gövdenin türünü söyleyen başlığı ekle: -H "Content-Type: application/json". Gerçek bir API bu durumda 400 Bad Request ya da 415 Unsupported Media Type (desteklenmeyen tür) döndürebilir. Kimi sunucu da gövdeyi hiç göremez ve kendi içinde çöküp 500 verir; Ders 28'de kendi sunucunda bunu yaşayacaksın.

Sık hataJSON'u komutun içine yazınca tırnaklar kayboluyor (PowerShell 5.1)

Ne zaman çıkar? Gövdeyi dosyaya koymak yerine komutun içine yazınca. Windows'la gelen PowerShell 5.1, dışarıdaki bir programa (curl.exe gibi) metin verirken metnin içindeki çift tırnakları yutar:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -X POST https://httpbin.org/anything/sampiyonlar -H "Content-Type: application/json" -d '{"isim":"Ahri","koridor":"orta"}'{  "args": {},  "data": "{isim:Ahri,koridor:orta}",  "files": {},  "form": {},  "headers": {    "Accept": "*/*",    "Content-Length": "24",    "Content-Type": "application/json",    "Host": "httpbin.org",    "User-Agent": "curl/8.21.0",    "X-Amzn-Trace-Id": "Root=1-6acb9029-620fbb3d5aef23f91ef8fa89"  },  "json": null,  "method": "POST",  "origin": "203.0.113.7",  "url": "https://httpbin.org/anything/sampiyonlar"}

Sunucuya {isim:Ahri,koridor:orta} gitti. Anahtarlar tırnaksız kaldığı için bu geçerli bir JSON değil, json alanı null. Terminalde hiçbir hata yok; sorunu ancak sunucunun gördüğüne bakınca fark edersin.

Nasıl düzelir? İki sağlam yol var:

  1. Gövdeyi bir dosyaya yaz ve -d "@ahri.json" ile gönder. Her PowerShell sürümünde aynı çalışır.
  2. curl yerine PowerShell'in kendi komutu Invoke-RestMethod'u kullan (aşağıda).

PowerShell 7.3 ve sonrası tırnakları olduğu gibi geçirir; yukarıdaki komut orada sorunsuz çalışır. İnternette tırnakların önüne ters eğik çizgi konmuş örnekler de görürsün: '{\"isim\":\"Ahri\"}'. Bu yazım 5.1'de işe yarar, ama 7.3 ve sonrasında ters eğik çizgiler de sunucuya gider ve JSON yine bozulur. Örneklerin kimisinin çalışıp kimisinin çalışmamasının sebebi bu fark. Dosya yolu ikisinde de çalışır.

Sık hataThe splatting operator '@' cannot be used to reference variables in an expression

Ne zaman çıkar? Dosyadan gövde gönderirken @ahri.json'ı tırnaksız yazınca. İnternetteki curl örnekleri genelde böyle yazılır, ama @ bir sözcüğün başındaysa PowerShell onu kendi özel işareti sanır:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -X POST https://httpbin.org/anything -H "Content-Type: application/json" -d @ahri.jsonAt line:1 char:86+ ... ttpbin.org/anything -H "Content-Type: application/json" -d @ahri.json+                                                                ~~~~~The splatting operator '@' cannot be used to reference variables in an expression. '@ahri' can be used only as an argument to a command. To reference variables in an expression use '$ahri'.    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException    + FullyQualifiedErrorId : SplattingNotPermitted

ParserError: PowerShell komutu daha çalıştırmadan, okurken durdu; istek hiç gitmedi. Mesajın sözünü ettiği "splatting", PowerShell'in kendi bir özelliği; öğrenmen gerekmiyor.

Nasıl düzelir? @ ile başlayan değeri çift tırnak içine al: -d "@ahri.json".

fetch ile JSON göndermek

Programdan JSON göndermek için fetch'e ikinci bir değer verirsin: isteğin ayarlarını taşıyan bir obje. gonder.mjs adında bir dosya oluştur:

gonder.mjs
const yeniMac = { sampiyon: "Ahri", kill: 7, olum: 2, kazandi: true } const yanit = await fetch("https://httpbin.org/anything/maclar", {    method: "POST",    headers: { "Content-Type": "application/json" },    body: JSON.stringify(yeniMac)})console.log(yanit.status, yanit.statusText) const yansima = await yanit.json()console.log(yansima.method)console.log(yansima.headers["Content-Type"])console.log(yansima.json)
Çıktı
200 OKPOSTapplication/json{ kazandi: true, kill: 7, olum: 2, sampiyon: 'Ahri' }

Ayar objesinin üç alanı, curl'deki üç seçeneğin karşılığı:

  • method: "POST" → -X POST. Yazmazsan GET gider.
  • headers: { "Content-Type": "application/json" } → -H. Başlık adını tırnak içinde yazarsın, çünkü içinde tire var.
  • body: JSON.stringify(yeniMac) → -d. Gövde ağdan metin olarak gider; objeyi JSON.stringify ile JSON metnine çevirmen şart.

httpbin json alanındaki anahtarları alfabetik sıraya dizdi; JSON'da anahtarların sırası önemli değildir. Durum kodu 200, çünkü httpbin bir ayna. Gerçek bir API yeni bir kayıt açınca 201 Created döndürür.

Sık hataTypeError: Request with GET/HEAD method cannot have body.

Ne zaman çıkar? fetch'e gövde verip method yazmayı unutunca. fetch'in varsayılan metodu GET'tir ve bir GET isteğinin gövdesi olamaz.

gonder.mjs
const yanit = await fetch("https://httpbin.org/anything/maclar", {    headers: { "Content-Type": "application/json" },    body: JSON.stringify({ sampiyon: "Ahri" })})
Hata çıktısı
node:internal/modules/run_main:107    triggerUncaughtException(    ^ [TypeError: Request with GET/HEAD method cannot have body.] Node.js v24.20.0

Hata senin dosyanı göstermiyor bile; Node'un iç dosyalarından birini gösteriyor. Böyle durumlarda köşeli parantezdeki cümleye güven: "GET ya da HEAD isteğinin gövdesi olamaz."

Nasıl düzelir? Ayar objesine method: "POST" (ya da PUT, PATCH) ekle.

JSON beklerken HTML gelirse

Ders 15'te yanit.ok'a bakmadan json() çağırınca <?xml ile başlayan bir hata almıştın. Aynı hatanın en sık görülen hâli HTML'dir: yanlış metotla, yanlış adresle ya da çökmüş bir sunucuyla konuşunca sunucular çoğu zaman bir HTML hata sayfası döndürür.

Sık hataSyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON

Ne zaman çıkar? Yanıtın türüne bakmadan json() çağırınca, gövde de bir HTML sayfası olunca. Denemek için ders26 klasöründe tur.mjs adında bir dosya oluştur. Burada POST bekleyen adrese GET gidiyor; sunucu 405 ve bir HTML sayfasıyla cevap veriyor:

tur.mjs
const yanit = await fetch("https://httpbin.org/post")const veri = await yanit.json()console.log(veri.json)
Hata çıktısı
<anonymous_script>:1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">^ SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON    at JSON.parse (<anonymous>)    ... Node.js v24.20.0

< HTML'in ilk harfi; JSON hiçbir zaman < ile başlamaz. Mesajda <!DOCTYPE görürsen sunucudan bir web sayfası gelmiş demektir.

Nasıl düzelir? Gövdeyi okumadan önce iki şeye bak: yanit.ok ve Content-Type. Tür JSON değilse gövdeyi yanit.text() ile düz metin olarak oku; hata sayfasının ne dediğini görürsün:

tur.mjs
const yanit = await fetch("https://httpbin.org/post")const tur = yanit.headers.get("content-type") ?? ""console.log(yanit.status, tur) if (yanit.ok && tur.includes("application/json")) {    const veri = await yanit.json()    console.log(veri)} else {    const metin = await yanit.text()    console.log("JSON gelmedi. Gövdenin başı: " + metin.slice(0, 14))}
Çıktı
405 text/htmlJSON gelmedi. Gövdenin başı: <!DOCTYPE HTML

yanit.headers.get("content-type") yanıttaki bir başlığın değerini verir; başlık yoksa null döner, ?? "" o durumda boş metin koyar (Ders 12). Başlık adının büyük-küçük harfi fark etmez.

Authorization: kimliğini göstermek

Şimdiye kadarki adreslerin hepsi herkese açıktı. Senin maç geçmişin ya da GitHub'daki gizli depoların ise yalnızca sana açık olmalı. Sunucu "sen kimsin?" diye sorar; cevabı her istekte Authorization başlığında verirsin. GitHub'da "beni getir" adresi olan /user'a kimliksiz istek at:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -i https://api.github.com/userHTTP/1.1 401 UnauthorizedContent-Type: application/json; charset=utf-8... {  "message": "Requires authentication",  "documentation_url": "https://docs.github.com/rest",  "status": "401"}

401: kim olduğunu söylemedin. Şimdi uydurma bir anahtarla dene. Bearer "taşıyıcı" demek: "bu anahtarı taşıyana izin ver."

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe https://api.github.com/user -H "Authorization: Bearer yanlis-anahtar-123"{  "message": "Bad credentials",  "documentation_url": "https://docs.github.com/rest",  "status": "401"}

Yine 401, ama mesaj farklı: "kimlik bilgilerin hatalı". Gerçek bir anahtarı GitHub hesabının ayarlarından alabilirdin; bu derste gerek yok. Başlığın sunucuya nasıl vardığını httpbin'in /bearer adresiyle gör; bu adres her anahtarı kabul eder:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe https://httpbin.org/bearer -H "Authorization: Bearer deneme-anahtari-123"{  "authenticated": true,  "token": "deneme-anahtari-123"}

REST: kaynaklar ve adresler

Kendi sunucunu yazınca vereceğin ilk kararlardan biri API'nin adresleri, yani uç noktaları olacak. Herkes aklına geleni yazsa bir API'de /getSampiyonlar, /sampiyonEkle, /sil_sampiyon?id=3 gibi adresler birikir ve API'yi kullanan herkes hepsini tek tek ezberlemek zorunda kalır. REST, adresleri ve metotları ortak bir kurala bağlayan bir tasarım biçimidir: adres neyle ilgili olduğunu, metot ne yapılacağını söyler.

/sampiyonlar koleksiyon GETlistele POSTyeni kayıt ekle /sampiyonlar/ahri tek kayıt GETgetir PUTtümünü yaz PATCHkısmen yaz DELETEsil /sampiyonlar/ahri/kostumler alt koleksiyon GETlistele
Şekil 26.4 Bir REST API'nin adres ağacı. Adres kaynağı gösterir, metot ne yapılacağını söyler.

Bu API'ye atılabilecek istekler, anlamları ve başarılı olunca dönen kodlar:

  • GET /sampiyonlar: bütün şampiyonları listele. Başarıda 200.
  • GET /sampiyonlar?rol=buyucu: listeyi süz. Başarıda 200.
  • GET /sampiyonlar/ahri: Ahri'yi getir. Başarıda 200, böyle bir kayıt yoksa 404.
  • POST /sampiyonlar: yeni şampiyon ekle; bilgileri gövdede. Başarıda 201 ve Location başlığı.
  • PUT /sampiyonlar/ahri: Ahri'nin kaydını tümüyle değiştir. Başarıda 200 ya da 204.
  • PATCH /sampiyonlar/ahri: Ahri'nin bir alanını değiştir. Başarıda 200 ya da 204.
  • DELETE /sampiyonlar/ahri: Ahri'yi sil. Başarıda 204.
  • GET /sampiyonlar/ahri/kostumler: Ahri'nin kostümlerini listele. Başarıda 200.

Tasarım kuralları:

  • Adreste ad olsun, fiil olmasın. Fiil zaten metotta: GET /sampiyonlar doğru, /getSampiyonlar yanlış.
  • Koleksiyonlar çoğul: /sampiyonlar, /maclar. Tek kayıt, koleksiyon artı kimlik: /maclar/42.
  • Küçük harf, sözcükler arasında tire: /esya-setleri. Türkçe harf kullanma: adreste ü gibi harfler %C3%BC biçiminde kodlanır ve okunmaz olur.
  • Süzme, sıralama ve sayfalama sorgu dizesinde: /sampiyonlar?rol=buyucu&sirala=isim.
  • Uzantı yazma: /sampiyonlar.json değil, /sampiyonlar. Türü Content-Type söyler.
  • GET hiçbir şeyi değiştirmemeli. Bu kuralın sebebi aşağıda.
Metin✗ Yanlış
GET  /getSampiyonlarPOST /sampiyonEkleGET  /sampiyonSil?ad=teemoPOST /sampiyonlar/ahri/guncelleGET  /Sampiyon_Listesi.json
Metin✓ Doğru
GET    /sampiyonlarPOST   /sampiyonlarDELETE /sampiyonlar/teemoPATCH  /sampiyonlar/ahriGET    /sampiyonlar

Üçüncü satır en tehlikelisi: GET ile silme. Bazı programlar adreslere kendiliğinden GET isteği atar: arama motorlarının botları, sohbet uygulamalarının bağlantı önizlemesi. "Bu bağlantı neymiş" diye baktıkları anda kayıt silinir.

Gerçek bir REST API görmek için GitHub'a bak; adresleri bu kurallarla kurulmuş:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe https://api.github.com/users/octocat{  "login": "octocat",  "id": 583231,  ...  "name": "The Octocat",  "company": "@github",  ...  "public_repos": 8,  ...  "created_at": "2011-01-25T18:44:36Z",  "updated_at": "2026-09-22T11:46:44Z"}

/users bir koleksiyon (GitHub'daki bütün kullanıcılar), /users/octocat içindeki tek kayıt; octocat GitHub'ın deneme hesabı. /users/octocat/repos o kullanıcının depolarını verir. Kendi kullanıcı adını yazarak kendi profilini de görebilirsin. Olmayan bir kullanıcıyı istersen:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -i https://api.github.com/users/bu-oyuncu-yok-26HTTP/1.1 404 Not FoundContent-Type: application/json; charset=utf-8...X-RateLimit-Limit: 60X-RateLimit-Remaining: 58... {  "message": "Not Found",  "documentation_url": "https://docs.github.com/rest",  "status": "404"}

İyi bir API hata durumunda da düzgün bir JSON döndürür: doğru durum kodu ve okunaklı bir mesaj. X-RateLimit-Remaining başlığı bu saat için kaç istek hakkın kaldığını söylüyor; sıfıra inerse 403 ya da 429 alırsın.

Her API REST değildir. Data Dragon bir dosya deposu: adresler .json ile biter ve yalnızca okumaya (GET, HEAD) izin verir; POST atınca 403 döndüğünü yukarıda gördün. Veri okumak için yeterli; kendi API'ni tasarlarken örnek alacağın şey GitHub'ın yapısı.

PowerShell'in kendi aracı: Invoke-RestMethod

curl.exe yanıtı olduğu gibi yazar; içinden tek bir değer almak istersen gözünle aramak zorunda kalırsın. PowerShell'in kendi komutu Invoke-RestMethod gelen JSON'u okuyup bir objeye çevirir. Alanlarına JavaScript'teki gibi noktayla ulaşırsın:

Terminal — PowerShell
PS C:\kod\ogren\ders26> Invoke-RestMethod https://ddragon.leagueoflegends.com/realms/tr.json n              : @{item=16.20.1; rune=7.23.1; mastery=7.23.1; summoner=16.20.1; champion=16.20.1; profileicon=16.20.1;                 map=16.20.1; language=16.20.1; sticker=16.20.1}v              : 16.20.1l              : tr_TRcdn            : https://ddragon.leagueoflegends.com/cdndd             : 16.20.1lg             : 16.20.1css            : 16.20.1profileiconmax : 28store          : PS C:\kod\ogren\ders26> (Invoke-RestMethod https://ddragon.leagueoflegends.com/realms/tr.json).v16.20.1

Komutu parantez içine alıp sonuna .v yazınca yalnızca o alan gelir. Değeri null olan store boş görünür. Gövde göndermek için metodu, türü ve gövdeyi ayrı ayrı verirsin. Gövde PowerShell'in kendi metni olarak kaldığı için tek tırnaklı JSON bozulmadan gider:

Terminal — PowerShell
PS C:\kod\ogren\ders26> (Invoke-RestMethod -Method Post -Uri https://httpbin.org/anything/sampiyonlar -ContentType "application/json; charset=utf-8" -Body '{"isim":"Ahri","koridor":"orta"}').json isim koridor---- -------Ahri orta

Yansımanın yalnızca json alanını istedik: sunucu JSON'u doğru almış. -ContentType'ın sonundaki ; charset=utf-8 önemli; sebebini aşağıdaki Türkçe harf kartında göreceksin.

Durum kodu ve başlıklar: Invoke-WebRequest

Invoke-RestMethod yalnızca gövdeyi verir. Durum kodu ve başlıklar için kardeşi Invoke-WebRequest'i kullan. Windows PowerShell 5.1'de ona her zaman -UseBasicParsing ekle; eklemezsen yukarıdaki hata kartında gördüğün güvenlik sorusu gelir:

Terminal — PowerShell
PS C:\kod\ogren\ders26> Invoke-WebRequest https://ddragon.leagueoflegends.com/realms/tr.json -UseBasicParsing StatusCode        : 200StatusDescription : OKContent           : {"n":{"item":"16.20.1","rune":"7.23.1","mastery":"7.23.1","summoner":"16.20.1","champion":"16.20.1"                    ,"profileicon":"16.20.1","map":"16.20.1","language":"16.20.1","sticker":"16.20.1"},"v":"16.20.1","l                    ":...RawContent        : HTTP/1.1 200 OK                    Connection: keep-alive                    Access-Control-Allow-Origin: *                    Access-Control-Allow-Methods: GET, HEAD                    Access-Control-Max-Age: 3000                    x-amz-server-side-encryption: AES256                    x-amz-version-id: ...Forms             :Headers           : {[Connection, keep-alive], [Access-Control-Allow-Origin, *], [Access-Control-Allow-Methods, GET, HE                    AD], [Access-Control-Max-Age, 3000]...}Images            : {}InputFields       : {}Links             : {}ParsedHtml        :RawContentLength  : 335 PS C:\kod\ogren\ders26> (Invoke-WebRequest https://ddragon.leagueoflegends.com/realms/tr.json -UseBasicParsing).Headers["Content-Type"]application/json

StatusCode durum kodu, Headers başlıklar, Content gövde. Tek bir başlığı köşeli parantezle, adını yazarak alırsın.

Hata gelince

Önemli bir fark var: curl ve fetch kötü bir durum kodunda da yanıtı sana verir. Invoke-RestMethod ve Invoke-WebRequest ise 4xx ya da 5xx görünce hata fırlatır. Yanıtın gövdesi varsa hata mesajı gövdenin kendisidir:

Terminal — PowerShell
PS C:\kod\ogren\ders26> Invoke-RestMethod https://api.github.com/users/bu-oyuncu-yok-26Invoke-RestMethod : {"message":"Not Found","documentation_url":"https://docs.github.com/rest","status":"404"}At line:1 char:1+ Invoke-RestMethod https://api.github.com/users/bu-oyuncu-yok-26+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Sık hataThe remote server returned an error: (404) Not Found. / Uzak sunucu hata döndürdü: (404) Bulunamadı.

Ne zaman çıkar? Invoke-RestMethod ya da Invoke-WebRequest 4xx ya da 5xx bir yanıt alınca ve yanıtın gövdesi boşsa. İlk satır Windows'un diline göre değişir. Türkçe Windows'ta:

Terminal — PowerShell
PS C:\kod\ogren\ders26> Invoke-RestMethod https://httpbin.org/status/404Invoke-RestMethod : Uzak sunucu hata döndürdü: (404) Bulunamadı.At line:1 char:1+ Invoke-RestMethod https://httpbin.org/status/404+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

İngilizce Windows'ta ilk satır Invoke-RestMethod : The remote server returned an error: (404) Not Found. olur. Bu cümleyi PowerShell değil, altındaki .NET kütüphanesi yazar; o yüzden PowerShell'in kendi satırları (At line:1 char:1) İngilizce kalırken bu satır Türkçe çıkabilir. Parantezdeki sayı her dilde aynıdır: durum kodu. Yanındaki açıklamanın iki dildeki hâli:

KodTürkçeİngilizce
400Hatalı İstekBad Request
401OnaylanmadıUnauthorized
403YasakForbidden
404BulunamadıNot Found
405Metoda İzin VerilmiyorMethod Not Allowed
409ÇakışmaConflict
429sunucunun kendi yazdığı (httpbin'de TOO MANY REQUESTS)sunucunun kendi yazdığı
500İç Sunucu HatasıInternal Server Error
503Sunucu KullanılamıyorServer Unavailable

429 için .NET'in hazır bir açıklaması yok; sunucunun durum satırına yazdığı açıklama olduğu gibi gelir.

Nasıl düzelir? Önce parantezdeki sayıya bak ve tablodan anlamını bul: 404 adresi, 401 kimlik bilgisini, 405 metodu kontrol ettirir. Hatanın ayrıntısını görmek istersen aynı isteği curl.exe -i ile at; curl hata fırlatmaz, bütün yanıtı gösterir.

Sık hataTürkçe harfler bozuluyor: Demacia'nın Kudreti, Işık yerine Isik

Ne zaman çıkar? Windows PowerShell 5.1'in web komutlarıyla Türkçe metin alırken ya da gönderirken. İki yönde de olur.

Gelirken: Data Dragon Content-Type: application/json yazar ama karakter kodlamasını (charset=utf-8) söylemez. PowerShell 5.1 bu durumda eski bir Batı Avrupa harf tablosu (ISO-8859-1) kullanır ve UTF-8 ile yazılmış ı iki ayrı işarete bölünür:

Terminal — PowerShell
PS C:\kod\ogren\ders26> (Invoke-RestMethod https://ddragon.leagueoflegends.com/cdn/16.20.1/data/tr_TR/champion/Garen.json).data.Garen.titleDemacia'nın Kudreti

Doğrusu Demacia'nın Kudreti; aynı adrese curl.exe ile bakarsan doğru görürsün. Veri bozuk değil, yalnızca yanlış tabloyla okunmuş.

Giderken: -ContentType'ta charset yazmazsan PowerShell 5.1 gövdeyi de o eski tabloyla gönderir. Tabloda olmayan Türkçe harfler en yakın Latin harfine dönüşür:

Terminal — PowerShell
PS C:\kod\ogren\ders26> (Invoke-RestMethod -Method Post -Uri https://httpbin.org/anything -ContentType "application/json" -Body '{"isim":"Lux","unvan":"Işık Leydisi"}').json isim unvan---- -----Lux  Isik Leydisi

Sunucuya Işık Leydisi değil, Isik Leydisi gitti; hata mesajı da yok.

Nasıl düzelir? Gönderirken -ContentType "application/json; charset=utf-8" yaz; o zaman Işık Leydisi olduğu gibi varır. Türkçe metin içeren yanıtlara bakarken curl.exe kullan ya da Node'da fetch ile oku: yanit.json() gövdeyi her zaman UTF-8 olarak okur.

Dört aracı yan yana koyalım:

  • curl.exe (terminal): gövdeyi olduğu gibi yazar; -i, -I, -v ile başlıkları da gösterir. 4xx ya da 5xx gelince de yanıtı yazar. En iyi olduğu iş: mesajın tamamını görmek, API belgelerindeki örnekleri denemek.
  • Invoke-RestMethod (PowerShell): yalnızca gövdeyi verir, JSON'u objeye çevirir. 4xx ya da 5xx gelince hata fırlatır. En iyi olduğu iş: yanıttan tek bir değer almak.
  • Invoke-WebRequest (PowerShell): StatusCode, Headers ve metin olarak Content verir. 4xx ya da 5xx gelince hata fırlatır. En iyi olduğu iş: durum koduna ve başlıklara bakmak.
  • fetch (JavaScript): yanit.status, yanit.headers.get(), gövde için json() ya da text(). Kötü kodda hata fırlatmaz, yanit.ok false olur. En iyi olduğu iş: programın içinden istek atmak.

Çerez ve oturum: sunucu seni nasıl hatırlar?

HTTP'nin önemli bir özelliği var: her istek kendi başınadır. Sunucu bir önceki isteği hatırlamaz; aynı kişiden ikinci istek geldiğinde de onun için yabancısın. Peki bir siteye giriş yaptıktan sonra her sayfada yeniden şifre sorulmamasını ne sağlıyor? Çerezler.

Tarayıcı Sunucu 1 POST /giris kullanıcı adı ve şifre 2 200 OK Set-Cookie: oturum=a7f3 çerez saklandı 3 GET /maclarim Cookie: oturum=a7f3 4 200 OK Deniz'in maçları oturum defteri a7f3 → Deniz
Şekil 26.5 Giriş yaptıktan sonra sunucu seni oturum çereziyle tanır.

Tarayıcıda 2. ve 3. adımdaki işler kendiliğinden olur: Set-Cookie gelince tarayıcı çerezi saklar, sonraki isteklere Cookie başlığını kendisi ekler. curl'de ise bunları elle yaparsın; böylece ne olduğunu görürsün. httpbin'in /cookies/set adresi istediğin çerezi verir:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -i "https://httpbin.org/cookies/set?tema=koyu"HTTP/1.1 302 FOUNDDate: Sun, 11 Oct 2026 13:16:16 GMTContent-Type: text/html; charset=utf-8Content-Length: 223Connection: keep-aliveServer: gunicorn/19.9.0Location: /cookiesSet-Cookie: tema=koyu; Path=/Access-Control-Allow-Origin: *Access-Control-Allow-Credentials: true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><title>Redirecting...</title><h1>Redirecting...</h1><p>You should be redirected automatically to target URL: <a href="/cookies">/cookies</a>.  If not click the link.

Tek yanıtta iki şey var: 302 ile "/cookies adresine git" diyen bir yönlendirme ve Set-Cookie: tema=koyu. Şimdi çerezleri gösteren adrese istek at:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe https://httpbin.org/cookies{  "cookies": {}}

Boş. curl çerezi saklamadı, sunucu da seni hatırlamadı. Çerezi -b ile kendin gönder; curl onu Cookie başlığına koyar:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe https://httpbin.org/cookies -b "tema=koyu"{  "cookies": {    "tema": "koyu"  }}

Tarayıcının yaptığını curl'e de yaptırabilirsin: -c gelen çerezleri bir dosyaya yazar, -b o dosyadan okur. Bu kez iki çerez isteyelim. Adresteki & yüzünden tırnaklar şart:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -c cerez.txt "https://httpbin.org/cookies/set?tema=koyu&dil=tr"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><title>Redirecting...</title><h1>Redirecting...</h1><p>You should be redirected automatically to target URL: <a href="/cookies">/cookies</a>.  If not click the link.PS C:\kod\ogren\ders26> curl.exe -b cerez.txt https://httpbin.org/cookies{  "cookies": {    "dil": "tr",    "tema": "koyu"  }}
Sık hataThe ampersand (&) character is not allowed

Ne zaman çıkar? İçinde & olan bir adresi tırnaksız yazınca. & PowerShell'de özel bir işarettir; adresin parçası sayılmaz:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -i https://httpbin.org/cookies/set?tema=koyu&dil=trAt line:1 char:54+ curl.exe -i https://httpbin.org/cookies/set?tema=koyu&dil=tr+                                                      ~The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation marks ("&") to pass it as part of a string.    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException    + FullyQualifiedErrorId : AmpersandNotAllowed

Yine bir ParserError: komut okunurken durdu, istek hiç gitmedi.

Nasıl düzelir? Adresi çift tırnak içine al: "https://httpbin.org/cookies/set?tema=koyu&dil=tr". Sorgu dizesi olan adresleri hep tırnakla yazma alışkanlığı edin.

Tarayıcıda çerezleri görmek için F12 ile geliştirici araçlarını aç; Application sekmesinde soldaki Cookies başlığı altında her sitenin çerezleri durur.

Oturum çerezi bir anahtar gibidir: ele geçiren, senin oturumunla istek atar. Bu yüzden sunucular oturum çerezlerine HttpOnly, Secure, SameSite gibi koruma işaretleri koyar; bunları ve gerçek bir giriş sistemini Ders 31'de kuracaksın. cerez.txt gibi dosyaları da Git'e koyma; dersin sonunda onu .gitignore'a ekleyeceksin.

Sık hatalar

Yukarıdaki kartlara ek olarak bu derste karşılaşabileceğin iki hata daha var. Bütün derslerin hataları hata rehberinde toplu durur.

Sık hatacurl: (6) Could not resolve host

Ne zaman çıkar? Alan adını yanlış yazınca ya da internet bağlantın yokken. curl alan adını IP adresine çeviremedi (Ders 18'deki DNS); istek hiç gitmediği için durum kodu da yok.

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -i https://ddragn.leagueoflegends.com/realms/tr.jsoncurl: (6) Could not resolve host: ddragn.leagueoflegends.com

Nasıl düzelir? Mesajdaki alan adını harf harf oku: ddragn değil, ddragon. Ad doğruysa internet bağlantını kontrol et. fetch'te aynı durum TypeError: fetch failed olarak görünür (Ders 15).

Sık hataİnternetten kopyalanan çok satırlı curl komutu: -H : The term '-H' is not recognized

Ne zaman çıkar? API belgelerindeki örnekler çoğu zaman Linux ve macOS'un kabuğu bash için yazılır ve uzun komutu satır sonundaki \ ile böler. PowerShell \'i "komut alt satırda sürüyor" diye anlamaz. Böyle bir örneği terminale yapıştırınca VS Code önce birden çok satır yapıştırdığını söyleyen bir uyarı gösterebilir (görünüşü sürüme göre değişir). Onaylarsan her satır ayrı bir komut olarak, sırayla çalışır:

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -X POST https://httpbin.org/anything/sampiyonlar \{  "args": {},  "data": "",  ...  "method": "POST",  ...}curl: (3) URL rejected: Bad hostnamePS C:\kod\ogren\ders26>   -H "Content-Type: application/json" \-H : The term '-H' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.At line:1 char:3+   -H "Content-Type: application/json" \+   ~~    + CategoryInfo          : ObjectNotFound: (-H:String) [], CommandNotFoundException    + FullyQualifiedErrorId : CommandNotFoundException PS C:\kod\ogren\ders26>   -d '{"isim":"Ahri"}'-d : The term '-d' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.At line:1 char:3+   -d '{"isim":"Ahri"}'+   ~~    + CategoryInfo          : ObjectNotFound: (-d:String) [], CommandNotFoundException    + FullyQualifiedErrorId : CommandNotFoundException

İlk satır tek başına çalıştı: gövdesiz bir POST gitti (data boş, yansımayı kısalttık). Sondaki \ de ikinci bir adres sanıldı (URL rejected: Bad hostname). İkinci ve üçüncü satırlar ise adı -H ve -d olan komutlar sanıldı: is not recognized, "tanınmıyor". Bu, Ders 0'daki node hatasıyla aynı mesaj; PowerShell'in kendi mesajı olduğu için Türkçe Windows'ta da büyük olasılıkla İngilizce görürsün (bu ders Türkçe kurulu bir Windows 11'de denendi).

Nasıl düzelir? Belgedeki örneği uyarlarken üç şeyi değiştir: curl yerine curl.exe yaz, satırları birleştirip \'leri sil, JSON gövdesini bir dosyaya koyup -d "@dosya.json" ile gönder.

Görevler

Görevleri C:\kod\ogren\ders26 klasöründe yap. Önce kendin dene; takılırsan ipuçlarını sırayla aç, çözüme en son bak.

Görev 1

Başlıkları oku

Bu kez gövdeyi değil, yalnızca başlıkları iste. Data Dragon'un sürüm listesine (https://ddragon.leagueoflegends.com/api/versions.json) yalnızca başlıkları isteyen bir istek at ve çıktıdan şu dört soruyu cevapla:

  1. Durum kodu kaç, ne anlama geliyor?
  2. Gövdenin türü ne?
  3. Gövde kaç bayt?
  4. Tarayıcıya hangi metotlara izin verdiğini söylüyor?

Sonra adresteki versions.json'ı Versions.json yap ve aynı soruları yeniden cevapla.

İpucu 1

Yalnızca başlıkları isteyen seçenek büyük I: curl.exe -I <adres>.

İpucu 2

Durum kodu ilk satırda. Tür Content-Type'ta, uzunluk Content-Length'te yazıyor. Tarayıcıya söylenen metotlar, adında Methods geçen bir CORS başlığında.

Çözümü göster
Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -I https://ddragon.leagueoflegends.com/api/versions.jsonHTTP/1.1 200 OKContent-Type: application/jsonContent-Length: 5219Connection: keep-aliveAccess-Control-Allow-Origin: *Access-Control-Allow-Methods: GET, HEADAccess-Control-Max-Age: 3000Last-Modified: Tue, 06 Oct 2026 21:17:54 GMTx-amz-server-side-encryption: AES256x-amz-version-id: UR812qMn2N6hyOXrawAE8DdWblr01Ls7Accept-Ranges: bytesServer: AmazonS3Date: Sun, 11 Oct 2026 13:12:37 GMTETag: "35a090c11e950879280872355d11a0ee"X-Cache: Hit from cloudfrontVia: 1.1 e98c62aea2ca07ecaab1da797bdc7fb8.cloudfront.net (CloudFront)X-Amz-Cf-Pop: BUD50-P3X-Amz-Cf-Id: U3MFJhIG8-JsNnN9Yj9jemMTuo7b2uakppBZHUSwPoGFI5SAHRBhsg==Age: 183
  1. 200 OK: istek başarılı.
  2. application/json: gövde JSON.
  3. 5219 bayt. Sende daha büyük olabilir; her yamada listeye yeni bir sürüm eklenir.
  4. Access-Control-Allow-Methods: GET, HEAD. Bu bir CORS başlığı: tarayıcıya "başka kökenden gelen sayfalar bu metotlarla istek atabilir" der. 405 kartındaki Allow gibi "sunucu yalnızca bunları kabul eder" anlamına gelmek zorunda değil, ama Data Dragon'da ikisi aynı: POST atınca 403 geldiğini 405 kartında gördün.

Gövde görünmedi, çünkü -I bir HEAD isteği gönderir: "yalnızca başlıkları ver".

Sınır denemesi: Versions.json ile sonuç değişir.

Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -I https://ddragon.leagueoflegends.com/api/Versions.jsonHTTP/1.1 403 ForbiddenContent-Type: application/xmlConnection: keep-aliveAccess-Control-Allow-Origin: *Access-Control-Allow-Methods: GET, HEADAccess-Control-Max-Age: 3000Server: AmazonS3Date: Sun, 11 Oct 2026 13:34:29 GMTX-Cache: Error from cloudfrontVia: 1.1 4d1daf728c8f336e79bd83ec18bb8cb0.cloudfront.net (CloudFront)X-Amz-Cf-Pop: MRS52-P1X-Amz-Cf-Id: 6D2KSTgvyZRkoaGEmRBlxsrvGuyGnpH8cMDXmSqOzPp3JD_Lzp5RvA==

Tek harf farkıyla dosya bulunamadı: durum 403, tür application/xml, Content-Length yok. Yol büyük-küçük harfe duyarlı ve Data Dragon olmayan dosya için 404 yerine 403 veriyor. Tarayıcıya söylenen metotlar yine GET ve HEAD.

Görev 2

Kendi GitHub profilin

Ders 7'de bir GitHub hesabı açtın. Invoke-RestMethod ile hesabının üç bilgisini ayrı ayrı yazdır: açık depo sayısı (public_repos), hesabın açılış zamanı (created_at) ve profil adresi (html_url). Kendi adınla denemeden önce octocat ile dene; şu çıktıyı almalısın (değerler zamanla değişebilir):

Metin
82011-01-25T18:44:36Zhttps://github.com/octocat

Sonra olmayan bir kullanıcı adı dene. Ne görüyorsun, durum kodu kaç?

İpucu 1

Adres https://api.github.com/users/ ve arkasına kullanıcı adı.

İpucu 2

Komutu parantez içine alıp sonuna alanın adını yaz: (Invoke-RestMethod <adres>).public_repos. Her bilgi için ayrı bir komut.

İpucu 3

Olmayan kullanıcıda Invoke-RestMethod hata fırlatır. Kırmızı mesajın ilk satırındaki JSON'a bak.

Çözümü göster
Terminal — PowerShell
PS C:\kod\ogren\ders26> (Invoke-RestMethod https://api.github.com/users/octocat).public_repos8PS C:\kod\ogren\ders26> (Invoke-RestMethod https://api.github.com/users/octocat).created_at2011-01-25T18:44:36ZPS C:\kod\ogren\ders26> (Invoke-RestMethod https://api.github.com/users/octocat).html_urlhttps://github.com/octocatPS C:\kod\ogren\ders26> Invoke-RestMethod https://api.github.com/users/bu-oyuncu-yok-26Invoke-RestMethod : {"message":"Not Found","documentation_url":"https://docs.github.com/rest","status":"404"}...

Olmayan kullanıcıda gelen kırmızı hatanın devamını Hata gelince bölümünde görmüştün; burada kısalttık. Durum kodu 404; GitHub bunu hata gövdesine koyduğu JSON'un status alanında da yazıyor.

Dikkat: her komut ayrı bir istek attı; saatlik 60 hakkından dördü gitti. GitHub'dan 5 ile başlayan bir kod gelirse birkaç saniye bekleyip komutu yeniden çalıştır.

Görev 3

Durum kodunun grubu

grup.mjs adında bir dosyaya, bir durum kodunu alıp grubunun adını döndüren durumGrubu(kod) fonksiyonunu yaz:

  • 100–199: "bilgi", 200–299: "başarılı", 300–399: "yönlendirme", 400–499: "istemci hatası", 500–599: "sunucu hatası"
  • Bu aralıkların dışındaki her sayı: "geçersiz kod"

Sonra [99, 100, 200, 204, 299, 301, 404, 429, 499, 500, 503, 599, 600] dizisindeki her kodu dene. Beklenen çıktı:

Metin
99 geçersiz kod100 bilgi200 başarılı204 başarılı299 başarılı301 yönlendirme404 istemci hatası429 istemci hatası499 istemci hatası500 sunucu hatası503 sunucu hatası599 sunucu hatası600 geçersiz kod
İpucu 1

Önce aralığın dışını ele: kod < 100 || kod > 599 ise hemen "geçersiz kod" döndür (Ders 6'daki erken çıkış).

İpucu 2

İlk rakam Math.floor(kod / 100): 404 / 100 sonucu 4.04, aşağı yuvarlayınca 4.

İpucu 3

İlk rakama göre bir else if zinciri kur. Başka bir yol: grup adlarını sırayla bir diziye koy ve ilkRakam - 1 sıradaki elemanı döndür.

Çözümü göster
grup.mjs
function durumGrubu(kod) {    if (kod < 100 || kod > 599) {        return "geçersiz kod"    }    const ilkRakam = Math.floor(kod / 100)    if (ilkRakam === 1) {        return "bilgi"    } else if (ilkRakam === 2) {        return "başarılı"    } else if (ilkRakam === 3) {        return "yönlendirme"    } else if (ilkRakam === 4) {        return "istemci hatası"    } else {        return "sunucu hatası"    }} const kodlar = [99, 100, 200, 204, 299, 301, 404, 429, 499, 500, 503, 599, 600]for (const kod of kodlar) {    console.log(kod, durumGrubu(kod))}
Çıktı
99 geçersiz kod100 bilgi200 başarılı204 başarılı299 başarılı301 yönlendirme404 istemci hatası429 istemci hatası499 istemci hatası500 sunucu hatası503 sunucu hatası599 sunucu hatası600 geçersiz kod

Sınır değerleri: 99 ve 600 aralığın hemen dışı; 100, 299, 499, 599 grupların ilk ya da son kodları. Sınır denetimini sona bıraksaydın 600 için Math.floor 6 verir ve else onu "sunucu hatası" sayardı. 404.5 gibi küsuratlı bir sayı da "istemci hatası" der; gerçek kodlar hep tam sayıdır.

Görev 4

Maç günlüğü API'si: tasarla ve dene

Ders 23'teki maç günlüğünü bir sunucuya taşıdığını düşün. Her maçın bir kimliği (id), şampiyonu, kill ve ölüm sayısı ve sonucu var. Şu altı iş için metot ve adres yaz; başarıda hangi durum kodunun dönmesi gerektiğini de ekle:

  1. Bütün maçları listele.
  2. Yalnızca Jinx'le oynanan maçları listele.
  3. 7 numaralı maçı getir.
  4. Yeni bir maç ekle.
  5. 7 numaralı maçın yalnızca ölüm sayısını 4 yap.
  6. 7 numaralı maçı sil.

Sonra 4. ve 5. maddeyi httpbin'e gönder: adresin başına https://httpbin.org/anything ekle, gövdeleri mac.json ve olum.json dosyalarından ver. Yansımadaki method, url ve json senin tasarımınla aynı olmalı.

İpucu 1

Koleksiyon /maclar, tek maç /maclar/7. Süzme sorgu dizesinde yapılır.

İpucu 2

Yeni kayıt POST ve 201; kaydın bir kısmını düzeltmek PATCH; silmek DELETE ve çoğu zaman 204.

İpucu 3

Beşinci madde için önce olum.json dosyasını oluştur ({ "olum": 4 }), sonra: curl.exe -X PATCH https://httpbin.org/anything/maclar/7 -H "Content-Type: application/json" -d "@olum.json".

Çözümü göster
  1. Bütün maçlar: GET /maclar → 200
  2. Jinx maçları: GET /maclar?sampiyon=Jinx → 200
  3. 7 numaralı maç: GET /maclar/7 → 200
  4. Yeni maç: POST /maclar → 201 ve yeni kaydın adresiyle Location: /maclar/<yeni id>
  5. Ölüm sayısını düzelt: PATCH /maclar/7 → 200 ya da 204
  6. Maçı sil: DELETE /maclar/7 → 204

İki dosya:

mac.json
{    "sampiyon": "Jinx",    "kill": 12,    "olum": 3,    "kazandi": true}
olum.json
{ "olum": 4 }
Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -X POST https://httpbin.org/anything/maclar -H "Content-Type: application/json" -d "@mac.json"{  "args": {},  "data": "{    \"sampiyon\": \"Jinx\",    \"kill\": 12,    \"olum\": 3,    \"kazandi\": true}",  "files": {},  "form": {},  "headers": {    "Accept": "*/*",    "Content-Length": "73",    "Content-Type": "application/json",    "Host": "httpbin.org",    "User-Agent": "curl/8.21.0",    "X-Amzn-Trace-Id": "Root=1-6acb9067-477fe4be4f9c56d02fd5ac2b"  },  "json": {    "kazandi": true,    "kill": 12,    "olum": 3,    "sampiyon": "Jinx"  },  "method": "POST",  "origin": "203.0.113.7",  "url": "https://httpbin.org/anything/maclar"}PS C:\kod\ogren\ders26> curl.exe -X PATCH https://httpbin.org/anything/maclar/7 -H "Content-Type: application/json" -d "@olum.json"{  "args": {},  "data": "{ \"olum\": 4 }",  "files": {},  "form": {},  "headers": {    "Accept": "*/*",    "Content-Length": "13",    "Content-Type": "application/json",    "Host": "httpbin.org",    "User-Agent": "curl/8.21.0",    "X-Amzn-Trace-Id": "Root=1-6acb9068-0e4f1add39e7f0b55bf0095f"  },  "json": {    "olum": 4  },  "method": "PATCH",  "origin": "203.0.113.7",  "url": "https://httpbin.org/anything/maclar/7"}

Sınır durumları: gerçek bir API'de olmayan bir maç (/maclar/999) için GET, PATCH ve DELETE 404 döndürmeli; httpbin ayna olduğu için her yola 200 der. Aynı POST'u iki kez gönderirsen gerçek bir API iki ayrı maç açar; aynı PATCH'i iki kez göndermek ise sonucu değiştirmez.

Görev 5

Çıkış yapmak: çerezi silmek

Bir sitede Çıkış yap'a bastığında sunucu tarayıcına "oturum çerezini sil" der. Bunu httpbin'le dene; çerezleri dersteki gibi cerez.txt dosyasında tut. Her adımda curl.exe'ye hangi seçenekleri vereceğini sen bul.

  1. https://httpbin.org/cookies/set?oturum=x9k2 adresinden gelen çerezi cerez.txt'ye yaz. Bu adımda dosyadaki çerezleri gönderme. Dosyaya yazan seçenek dosyayı baştan yazar; dersteki eski çerezler (tema, dil) böylece dosyadan çıkar.
  2. cerez.txt'deki çerezle https://httpbin.org/cookies adresine istek at.
  3. Çıkış yap: https://httpbin.org/cookies/delete?oturum adresine cerez.txt'deki çerezi gönder, gelen değişikliği yine cerez.txt'ye yaz ve yanıtın başlıklarını da göster. Set-Cookie satırında sunucu çerezi nasıl siliyor?
  4. 2. adımdaki isteği yeniden at. Çerez nereye gitti?

2. adımda şunu görmelisin:

Metin
{  "cookies": {    "oturum": "x9k2"  }}
İpucu 1

Gelen çerezleri dosyaya yazmak -c, dosyadakileri göndermek -b, başlıkları göstermek -i. Bir komutta üçünü birden verebilirsin.

İpucu 2

3. adımın komutu: curl.exe -i -b cerez.txt -c cerez.txt "https://httpbin.org/cookies/delete?oturum". Set-Cookie satırındaki Expires (son kullanma tarihi) hangi yılı gösteriyor?

Çözümü göster
Terminal — PowerShell
PS C:\kod\ogren\ders26> curl.exe -c cerez.txt "https://httpbin.org/cookies/set?oturum=x9k2"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><title>Redirecting...</title><h1>Redirecting...</h1><p>You should be redirected automatically to target URL: <a href="/cookies">/cookies</a>.  If not click the link.PS C:\kod\ogren\ders26> curl.exe -b cerez.txt https://httpbin.org/cookies{  "cookies": {    "oturum": "x9k2"  }}PS C:\kod\ogren\ders26> curl.exe -i -b cerez.txt -c cerez.txt "https://httpbin.org/cookies/delete?oturum"HTTP/1.1 302 FOUNDDate: Sun, 11 Oct 2026 22:51:28 GMTContent-Type: text/html; charset=utf-8Content-Length: 223Connection: keep-aliveServer: gunicorn/19.9.0Location: /cookiesSet-Cookie: oturum=; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Path=/Access-Control-Allow-Origin: *Access-Control-Allow-Credentials: true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><title>Redirecting...</title><h1>Redirecting...</h1><p>You should be redirected automatically to target URL: <a href="/cookies">/cookies</a>.  If not click the link.PS C:\kod\ogren\ders26> curl.exe -b cerez.txt https://httpbin.org/cookies{  "cookies": {}}

Sunucu çerezi kendisi silemez, çünkü çerez senin bilgisayarında durur. Onun yerine aynı adla boş bir çerez gönderir ve son kullanma tarihini geçmişe, 1970'e çeker; Max-Age=0 da "ömrü sıfır saniye" der. curl, tarayıcı gibi, süresi geçmiş çerezi atar ve cerez.txt'ye artık yazmaz. 4. adımda sunucuya hiç çerez gitmedi: oturum kapandı.

Sınır durumu: 3. adımda -c cerez.txt'yi unutursan silme talimatı yine gelir, ama curl onu dosyaya işlemez. 4. adım o zaman hâlâ "oturum": "x9k2" gösterir. Tarayıcı bu işi kendiliğinden yapar; curl'de her şeyi sen söylersin.

Görev 6

Güvenli JSON alıcı

jsonal.mjs adında bir dosyaya jsonAl(adres) adında bir async fonksiyon yaz:

  • Yanıt başarısızsa, mesajı İstek başarısız: 403 Forbidden biçiminde (kod ve açıklama) olan bir hata fırlatsın.
  • Durum 204 ise gövde olmadığı için null döndürsün.
  • Content-Type JSON değilse, mesajı JSON bekleniyordu, gelen tür: text/html; charset=utf-8 biçiminde olan bir hata fırlatsın.
  • Bunların hiçbiri değilse JSON'u okuyup döndürsün.

Sonra aşağıdaki beş adresi sırayla dene. Her biri için ya Tamam: ve gelen değerin türünü (gövde yoksa gövde yok) ya da Olmadı: ve hatanın mesajını yazdır.

Metin
https://ddragon.leagueoflegends.com/realms/tr.jsonhttps://httpbin.org/status/204https://httpbin.org/htmlhttps://httpbin.org/status/429https://ddragon.leagueoflegends.com/api/Versions.json

Beklenen çıktı:

Metin
Tamam: objectTamam: gövde yokOlmadı: JSON bekleniyordu, gelen tür: text/html; charset=utf-8Olmadı: İstek başarısız: 429 TOO MANY REQUESTSOlmadı: İstek başarısız: 403 Forbidden
İpucu 1

Sıra önemli: önce yanit.ok, sonra 204, en son tür. 204'te ok zaten true.

İpucu 2

Türü yanit.headers.get("content-type") ile al; başlık yoksa null gelir, ?? "" ile boş metne çevir. Sonra includes("application/json").

İpucu 3

Döngüde her çağrıyı try / catch içine al (Ders 13); catch'te hata.message'ı yazdır. try'ın içinde veri === null ise "gövde yok", değilse typeof veri yazdır (Ders 23'teki typeof).

Çözümü göster
jsonal.mjs
async function jsonAl(adres) {    const yanit = await fetch(adres)    if (!yanit.ok) {        throw new Error("İstek başarısız: " + yanit.status + " " + yanit.statusText)    }    if (yanit.status === 204) {        return null    }    const tur = yanit.headers.get("content-type") ?? ""    if (!tur.includes("application/json")) {        throw new Error("JSON bekleniyordu, gelen tür: " + tur)    }    return await yanit.json()} const adresler = [    "https://ddragon.leagueoflegends.com/realms/tr.json",    "https://httpbin.org/status/204",    "https://httpbin.org/html",    "https://httpbin.org/status/429",    "https://ddragon.leagueoflegends.com/api/Versions.json"] for (const adres of adresler) {    try {        const veri = await jsonAl(adres)        if (veri === null) {            console.log("Tamam: gövde yok")        } else {            console.log("Tamam:", typeof veri)        }    } catch (hata) {        console.log("Olmadı:", hata.message)    }}
Çıktı
Tamam: objectTamam: gövde yokOlmadı: JSON bekleniyordu, gelen tür: text/html; charset=utf-8Olmadı: İstek başarısız: 429 TOO MANY REQUESTSOlmadı: İstek başarısız: 403 Forbidden

Sınır durumu: httpbin'in 204 yanıtında Content-Type: text/html başlığı var ama gövde yok. Tür denetimini 204'ten önce yapsaydın bu başarılı yanıtı hata sayardın; sıranın önemi bu. 429'un açıklaması büyük harfli geliyor, çünkü onu sunucu yazıyor; programın sayıya güvenmesi bu yüzden.

Kendini sına

Soru 1

Bu yanıtın başı ne söylüyor? Yeni kaydın adresi ne?

Metin
HTTP/1.1 201 CreatedContent-Type: application/jsonLocation: /maclar/43
Cevabı göster

201 Created: istek başarılı ve yeni bir kayıt oluşturuldu; büyük olasılıkla bir POST'un cevabı. Yeni kaydın adresi Location başlığında: /maclar/43. Gövde JSON.

Soru 2

401 mi, 403 mü? (a) Giriş yapmadan /maclarim adresine istek attın. (b) Giriş yaptın ama başka bir oyuncunun maçını silmeye çalıştın.

Cevabı göster

(a) 401 Unauthorized: kim olduğunu söylemedin. (b) 403 Forbidden: kim olduğun belli, ama o kayıt üzerinde iznin yok. Bazı API'ler başkasının kaydının varlığını bile belli etmemek için 404 döndürür; bu da yaygın bir tercih.

Soru 3

Bir API'nin belgesinde "anahtarınızı Authorization başlığında, Bearer ile gönderin" yazıyor. Anahtarın abc123 olsun. https://api.example.com/maclarim adresine bu isteği curl.exe ile nasıl atarsın? Başlığı unutursan hangi durum kodunu beklersin?

Cevabı göster

curl.exe https://api.example.com/maclarim -H "Authorization: Bearer abc123". -H isteğe bir başlık ekler; değeri Bearer, bir boşluk ve anahtardan oluşur. Başlığı unutursan 401 Unauthorized gelir: sunucu kim olduğunu bilmiyor. Anahtar yanlışsa da 401 gelir, ama mesaj farklıdır (GitHub'daki Bad credentials gibi). Gerçek bir anahtarı komutun içine yazmaktan kaçın; terminal geçmişinde kalır.

Soru 4

Sunucudaki kayıt { "isim": "Ahri", "hp": 100, "mana": 300 }. PUT /sampiyonlar/ahri isteğini { "hp": 120 } gövdesiyle gönderdin. Kayıt ne olur? Aynı gövdeyi PATCH ile gönderseydin?

Cevabı göster

PUT kaydı gövdeyle tümüyle değiştirir: kayıt { "hp": 120 } olur, isim ve mana gider. Pek çok API bunun yerine "eksik alan var" diye 400 döndürür. PATCH yalnızca gövdedeki alanı değiştirir: { "isim": "Ahri", "hp": 120, "mana": 300 }.

Soru 5

Hatayı bul: Windows PowerShell 5.1'de bu komut neden çalışmaz, nasıl düzeltirsin?

PowerShell
curl -X DELETE https://httpbin.org/anything/maclar/7
Cevabı göster

Bu PowerShell'de curl, Invoke-WebRequest'in takma adı; o komutun -X diye bir seçeneği yok. PowerShell şu hatayı verir: Invoke-WebRequest : A parameter cannot be found that matches parameter name 'X'. Düzeltmek için .exe ekle: curl.exe -X DELETE https://httpbin.org/anything/maclar/7.

Soru 6

Bu adreslerden hangileri REST kurallarına uymuyor, neden?

Metin
GET    /sampiyonlar?rol=destekPOST   /yeniMacEkleGET    /maclar/12/silDELETE /maclar/12GET    /Maclar.json
Cevabı göster
  • GET /sampiyonlar?rol=destek uygun: koleksiyon ve sorgu dizesinde süzme.
  • POST /yeniMacEkle uymuyor: adreste fiil var. Doğrusu POST /maclar.
  • GET /maclar/12/sil en tehlikelisi: GET hiçbir şeyi değiştirmemeli; bir bot ya da bağlantı önizlemesi bu adrese bakınca maç silinir. Doğrusu DELETE /maclar/12.
  • DELETE /maclar/12 uygun.
  • GET /Maclar.json uymuyor: büyük harf ve uzantı. Doğrusu GET /maclar.

Soru 7

httpbin'e curl.exe ile bir gövde gönderdin. Yansımada "json": null var ve gövden "form" alanının içinde duruyor. Ne unuttun?

Cevabı göster

Content-Type başlığını. -d ile gönderilen gövdeyi curl, başlık yazmazsan application/x-www-form-urlencoded olarak işaretler ve sunucu onu form sanır. Düzeltmek için -H "Content-Type: application/json" ekle.

Soru 8

HTTP sunucusu bir önceki isteği hatırlamaz. O hâlde bir siteye giriş yaptıktan sonra sayfa değiştirdiğinde sunucu seni nasıl tanır? Bilgiyi kim saklar, her istekte kim gönderir?

Cevabı göster

Oturum çereziyle. Giriş başarılı olunca sunucu bir oturum kimliği üretir, onu kendi oturum kaydına yazar ve yanıtta Set-Cookie başlığıyla tarayıcıya verir. Tarayıcı çerezi saklar ve o siteye attığı her istekte Cookie başlığıyla kendiliğinden geri gönderir. Sunucu çerezdeki kimliği kendi kaydında arar ve seni tanır. Çerezi ele geçiren biri de senin yerine geçebilir; korumasını Ders 31'de göreceksin.

Kayıt noktası

cerez.txt bir oturum anahtarı taşıyabilecek türden bir dosya; Git'e girmemeli. C:\kod\ogren\.gitignore dosyasını aç (Ders 7'de oluşturmuştun) ve en alta şu satırı ekle:

.gitignore
cerez.txt

Sonra terminalde bir üst klasöre, C:\kod\ogren'e çık:

Terminal — PowerShell
PS C:\kod\ogren\ders26> cd ..

Bir sonraki derste masanın öbür tarafına geçiyorsun: node:http ile kendi sunucunu yazacak, bu derste gönderdiğin isteklere bu kez kendin cevap vereceksin.

İşaret yalnızca bu tarayıcıda saklanır, kimseye gönderilmez.