{"id":34454,"date":"2025-11-16T22:41:00","date_gmt":"2025-11-16T19:41:00","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/?p=34454"},"modified":"2025-11-16T22:41:00","modified_gmt":"2025-11-16T19:41:00","slug":"node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/","title":{"rendered":"Node.js&#8217;te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber"},"content":{"rendered":"<p><body><\/p>\n<h2>Node.js&#8217;te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber<\/h2>\n<p>Modern web uygulamalar\u0131, veriye eri\u015fim ve veri manip\u00fclasyonu i\u00e7in g\u00fc\u00e7l\u00fc ve esnek API&#8217;lere ihtiya\u00e7 duyar. Geleneksel RESTful API&#8217;ler bu ihtiyac\u0131 b\u00fcy\u00fck \u00f6l\u00e7\u00fcde kar\u015f\u0131larken, \u00f6zellikle karma\u015f\u0131k uygulamalarda baz\u0131 s\u0131n\u0131rlamalar\u0131 beraberinde getirebilir. Bu noktada, Facebook taraf\u0131ndan geli\u015ftirilen ve a\u00e7\u0131k kaynak hale getirilen GraphQL, API tasar\u0131m\u0131na yepyeni bir bak\u0131\u015f a\u00e7\u0131s\u0131 sunarak geli\u015ftiricilerin imdad\u0131na yeti\u015fmi\u015ftir. Node.js ise, JavaScript tabanl\u0131, y\u00fcksek performansl\u0131 ve \u00f6l\u00e7eklenebilir sunucu taraf\u0131 uygulamalar geli\u015ftirmek i\u00e7in ideal bir ortamd\u0131r. Bu makalede, Node.js kullanarak nas\u0131l bir GraphQL API sunucusu kuraca\u011f\u0131m\u0131z\u0131, temelden ileri seviyeye kadar t\u00fcm ad\u0131mlar\u0131yla ele alaca\u011f\u0131z. GraphQL&#8217;in temel prensiplerinden ba\u015flayarak, bir sunucu kurma, \u015fema tan\u0131mlama, \u00e7\u00f6z\u00fcmleyicileri yazma, veri kaynaklar\u0131yla entegrasyon, kimlik do\u011frulama, abonelikler ve en iyi uygulamalara kadar geni\u015f bir yelpazeyi kapsayaca\u011f\u0131z.<\/p>\n<h2>GraphQL Temelleri<\/h2>\n<h3>GraphQL Nedir?<\/h3>\n<p>GraphQL, API&#8217;ler i\u00e7in bir sorgu dili ve bu sorgular\u0131 \u00e7al\u0131\u015ft\u0131rmak i\u00e7in bir \u00e7al\u0131\u015fma zaman\u0131 ortam\u0131d\u0131r. Geleneksel REST API&#8217;lerinden farkl\u0131 olarak, istemcilerin tam olarak neye ihtiya\u00e7 duyduklar\u0131n\u0131 belirtmelerine olanak tan\u0131r. Bu, istemcinin tek bir istekte birden fazla kaynakla ilgili veri alabilece\u011fi anlam\u0131na gelir ve &#8220;over-fetching&#8221; (gere\u011finden fazla veri alma) veya &#8220;under-fetching&#8221; (gere\u011finden az veri al\u0131p birden fazla istek yapma) sorunlar\u0131n\u0131 ortadan kald\u0131r\u0131r. GraphQL, API&#8217;nizin t\u00fcm yeteneklerini a\u00e7\u0131klayan g\u00fc\u00e7l\u00fc bir tip sistemine sahiptir. Bu tip sistemi, istemci taraf\u0131nda veri do\u011frulama ve otomatik tamamlama gibi avantajlar sunar.<\/p>\n<h3>REST ile Kar\u015f\u0131la\u015ft\u0131rma<\/h3>\n<p>REST ve GraphQL aras\u0131ndaki temel farklar\u0131 anlamak, GraphQL&#8217;in neden tercih edildi\u011fini daha iyi kavramam\u0131z\u0131 sa\u011flar:<\/p>\n<ul>\n<li><strong>Veri \u00c7ekme Modeli:<\/strong> REST&#8217;te genellikle her kaynak i\u00e7in ayr\u0131 bir endpoint bulunur (\u00f6rn. <code>\/users<\/code>, <code>\/posts<\/code>). Bir kullan\u0131c\u0131n\u0131n g\u00f6nderilerini almak i\u00e7in iki ayr\u0131 istek gerekebilir. GraphQL&#8217;de ise istemci, tek bir sorgu ile ihtiyac\u0131 olan t\u00fcm veriyi (kullan\u0131c\u0131 ve g\u00f6nderileri) tek bir endpoint&#8217;ten \u00e7ekebilir.<\/li>\n<li><strong>Esneklik:<\/strong> REST API&#8217;leri genellikle sabit veri yap\u0131lar\u0131 d\u00f6nd\u00fcr\u00fcr. \u0130stemcinin farkl\u0131 alanlara ihtiyac\u0131 oldu\u011funda API&#8217;nin de\u011fi\u015ftirilmesi gerekebilir. GraphQL&#8217;de istemci, sorgusunda hangi alanlar\u0131 istedi\u011fini a\u00e7\u0131k\u00e7a belirtir, bu da istemciye b\u00fcy\u00fck bir esneklik sa\u011flar.<\/li>\n<li><strong>Endpoint Say\u0131s\u0131:<\/strong> REST API&#8217;lerinde \u00e7ok say\u0131da endpoint bulunabilir (<code>GET \/users<\/code>, <code>GET \/users\/{id}<\/code>, <code>POST \/users<\/code> vb.). GraphQL&#8217;de ise genellikle tek bir endpoint (\u00f6rn. <code>\/graphql<\/code>) \u00fczerinden t\u00fcm i\u015flemler y\u00fcr\u00fct\u00fcl\u00fcr.<\/li>\n<li><strong>Versiyonlama:<\/strong> REST API&#8217;lerinde versiyonlama (\u00f6rn. <code>\/v1\/users<\/code>, <code>\/v2\/users<\/code>) yayg\u0131nken, GraphQL&#8217;in esnek yap\u0131s\u0131 sayesinde \u015fema evrimi daha kolay y\u00f6netilir ve genellikle versiyonlamaya gerek kalmaz.<\/li>\n<\/ul>\n<h3>Temel Kavramlar<\/h3>\n<p>GraphQL ile \u00e7al\u0131\u015f\u0131rken kar\u015f\u0131la\u015faca\u011f\u0131m\u0131z temel kavramlar \u015funlard\u0131r:<\/p>\n<ul>\n<li><strong>Schema (\u015eema):<\/strong> API&#8217;nizin t\u00fcm veri yap\u0131s\u0131n\u0131 ve mevcut operasyonlar\u0131 (sorgular, mutasyonlar, abonelikler) tan\u0131mlayan bir dildir. GraphQL \u015eema Tan\u0131mlama Dili (Schema Definition Language &#8211; SDL) kullan\u0131larak yaz\u0131l\u0131r.<\/li>\n<li><strong>Types (T\u00fcrler):<\/strong> \u015eeman\u0131n yap\u0131 ta\u015flar\u0131d\u0131r. Veri nesnelerinin (\u00f6rn. <code>User<\/code>, <code>Product<\/code>) ve bunlar\u0131n alanlar\u0131n\u0131n t\u00fcrlerini (String, Int, Boolean vb.) belirtir. \u00d6zel t\u00fcrler (Enum, Input, Interface, Union) de tan\u0131mlanabilir.<\/li>\n<li><strong>Queries (Sorgular):<\/strong> API&#8217;den veri okumak i\u00e7in kullan\u0131l\u0131r. REST&#8217;teki GET isteklerine benzer.<\/li>\n<li><strong>Mutations (De\u011fi\u015fiklikler):<\/strong> API&#8217;deki veriyi de\u011fi\u015ftirmek (olu\u015fturmak, g\u00fcncellemek, silmek) i\u00e7in kullan\u0131l\u0131r. REST&#8217;teki POST, PUT, DELETE isteklerine benzer.<\/li>\n<li><strong>Resolvers (\u00c7\u00f6z\u00fcmleyiciler):<\/strong> \u015eemadaki her alan i\u00e7in, o alan\u0131n verisini nas\u0131l alaca\u011f\u0131n\u0131 veya i\u015fleyece\u011fini belirten fonksiyonlard\u0131r. Bir sorgu veya mutasyon geldi\u011finde, ilgili resolver \u00e7al\u0131\u015f\u0131r ve veriyi d\u00f6nd\u00fcr\u00fcr.<\/li>\n<li><strong>Subscriptions (Abonelikler):<\/strong> Ger\u00e7ek zamanl\u0131 veri ak\u0131\u015f\u0131 sa\u011flamak i\u00e7in kullan\u0131l\u0131r. Bir olay (\u00f6rn. yeni bir mesaj) meydana geldi\u011finde istemcilere otomatik olarak bildirim g\u00f6nderir.<\/li>\n<li><strong>Introspection (\u0130\u00e7 G\u00f6zlem):<\/strong> Bir GraphQL sunucusunun kendi \u015femas\u0131n\u0131 sorgulama yetene\u011fidir. Bu sayede geli\u015ftirme ara\u00e7lar\u0131 (GraphQL Playground, GraphiQL) otomatik tamamlama ve dok\u00fcmantasyon sa\u011flayabilir.<\/li>\n<\/ul>\n<h2>Node.js Ortam\u0131n\u0131 Haz\u0131rlama<\/h2>\n<h3>\u00d6n Gereksinimler<\/h3>\n<p>Node.js ile GraphQL API sunucusu kurmak i\u00e7in a\u015fa\u011f\u0131daki \u00f6n gereksinimlere ihtiyac\u0131m\u0131z var:<\/p>\n<ul>\n<li><strong>Node.js:<\/strong> Sisteminizde kurulu olmal\u0131d\u0131r. <a href=\"https:\/\/nodejs.org\/\" target=\"_blank\">nodejs.org<\/a> adresinden indirebilirsiniz.<\/li>\n<li><strong>npm veya Yarn:<\/strong> Node.js ile birlikte gelen paket y\u00f6neticisi npm (Node Package Manager) veya alternatif olarak Yarn kurulu olmal\u0131d\u0131r.<\/li>\n<\/ul>\n<h3>Proje Ba\u015flatma<\/h3>\n<p>Yeni bir Node.js projesi olu\u015fturarak ba\u015flayal\u0131m. Terminalinizi a\u00e7\u0131n ve a\u015fa\u011f\u0131daki komutlar\u0131 \u00e7al\u0131\u015ft\u0131r\u0131n:<\/p>\n<pre><code class=\"language-bash\">\nmkdir graphql-api-server\ncd graphql-api-server\nnpm init -y\n<\/code><\/pre>\n<p>Bu komutlar, projeniz i\u00e7in bir klas\u00f6r olu\u015fturur, i\u00e7ine girer ve <code>package.json<\/code> dosyas\u0131n\u0131 varsay\u0131lan ayarlarla olu\u015fturur.<\/p>\n<h2>Temel Bir GraphQL Sunucusu Kurulumu<\/h2>\n<h3>Ba\u011f\u0131ml\u0131l\u0131klar\u0131 Y\u00fckleme<\/h3>\n<p>GraphQL sunucumuzu kurmak i\u00e7in birka\u00e7 temel ba\u011f\u0131ml\u0131l\u0131\u011fa ihtiyac\u0131m\u0131z var. Bu makalede, pop\u00fcler ve g\u00fc\u00e7l\u00fc bir ara\u00e7 olan Apollo Server&#8217;\u0131 kullanaca\u011f\u0131z. Apollo Server, GraphQL sunucusu olu\u015fturmay\u0131 ve y\u00f6netmeyi b\u00fcy\u00fck \u00f6l\u00e7\u00fcde basitle\u015ftirir. Ayr\u0131ca, Express.js ile entegrasyonu i\u00e7in <code>apollo-server-express<\/code> paketini kullanaca\u011f\u0131z.<\/p>\n<pre><code class=\"language-bash\">\nnpm install apollo-server-express graphql express\n<\/code><\/pre>\n<ul>\n<li><code>apollo-server-express<\/code>: Apollo Server&#8217;\u0131 Express.js uygulamas\u0131yla birlikte kullanmam\u0131z\u0131 sa\u011flar.<\/li>\n<li><code>graphql<\/code>: GraphQL&#8217;in temel \u00e7al\u0131\u015fma zaman\u0131 ve \u015fema tan\u0131mlama yeteneklerini sa\u011flar.<\/li>\n<li><code>express<\/code>: Temel web sunucusu ve middleware altyap\u0131s\u0131n\u0131 sa\u011flar.<\/li>\n<\/ul>\n<h3>Apollo Server Kullan\u0131m\u0131<\/h3>\n<p>Apollo Server, bir GraphQL sunucusu olu\u015fturmak i\u00e7in gerekli t\u00fcm ara\u00e7lar\u0131 sa\u011flar. \u015eema tan\u0131mlar\u0131n\u0131z\u0131 ve \u00e7\u00f6z\u00fcmleyicilerinizi alarak bir GraphQL endpoint&#8217;i olu\u015fturur ve sorgular\u0131 i\u015fler. Ayr\u0131ca, geli\u015ftirme s\u0131ras\u0131nda \u00e7ok faydal\u0131 olan GraphQL Playground gibi ara\u00e7lar\u0131 da otomatik olarak entegre eder.<\/p>\n<h3>\u015eema Tan\u0131mlama (Type Definitions)<\/h3>\n<p>GraphQL API&#8217;mizin kalbi \u015femad\u0131r. \u015eema, API&#8217;nizin destekledi\u011fi t\u00fcm veri t\u00fcrlerini ve operasyonlar\u0131 (sorgular ve mutasyonlar) tan\u0131mlar. <code>src\/schema.js<\/code> ad\u0131nda bir dosya olu\u015ftural\u0131m ve a\u015fa\u011f\u0131daki \u015femay\u0131 ekleyelim:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ src\/schema.js\nconst { gql } = require('apollo-server-express');\n\n\/\/ GraphQL \u015eema Tan\u0131mlama Dili (SDL) kullan\u0131larak \u015fema olu\u015fturulur.\nconst typeDefs = gql<code>\n  # 'Book' ad\u0131nda bir nesne t\u00fcr\u00fc tan\u0131ml\u0131yoruz.\n  # Her kitab\u0131n bir ID'si, ba\u015fl\u0131\u011f\u0131 ve yazar\u0131 olacak.\n  type Book {\n    id: ID! # ID benzersiz bir tan\u0131mlay\u0131c\u0131d\u0131r ve '!' bo\u015f olamayaca\u011f\u0131n\u0131 belirtir.\n    title: String!\n    author: String!\n    year: Int\n  }\n\n  # 'Query' t\u00fcr\u00fc, istemcilerin sunucudan veri \u00e7ekmek i\u00e7in kullanabilece\u011fi sorgular\u0131 tan\u0131mlar.\n  type Query {\n    # T\u00fcm kitaplar\u0131 d\u00f6nd\u00fcren bir sorgu. Dizi d\u00f6nd\u00fcrd\u00fc\u011f\u00fc i\u00e7in '[Book]' kullan\u0131l\u0131r.\n    books: [Book!]! \n    # Belirli bir ID'ye sahip kitab\u0131 d\u00f6nd\u00fcren bir sorgu.\n    # 'id: ID!' arg\u00fcman\u0131 al\u0131r ve bir 'Book' veya null d\u00f6nd\u00fcrebilir.\n    book(id: ID!): Book\n  }\n\n  # 'Mutation' t\u00fcr\u00fc, istemcilerin sunucudaki veriyi de\u011fi\u015ftirmek i\u00e7in kullanabilece\u011fi operasyonlar\u0131 tan\u0131mlar.\n  type Mutation {\n    # Yeni bir kitap ekleyen mutasyon. Gerekli arg\u00fcmanlar 'title' ve 'author'd\u0131r.\n    # Eklenen kitab\u0131 d\u00f6nd\u00fcr\u00fcr.\n    addBook(title: String!, author: String!, year: Int): Book!\n    # Varolan bir kitab\u0131 g\u00fcncelleyen mutasyon. 'id' zorunlu, di\u011ferleri iste\u011fe ba\u011fl\u0131d\u0131r.\n    updateBook(id: ID!, title: String, author: String, year: Int): Book!\n    # Bir kitab\u0131 silen mutasyon. Silinen kitab\u0131n ID'sini d\u00f6nd\u00fcr\u00fcr.\n    deleteBook(id: ID!): ID!\n  }\n<\/code>;\n\nmodule.exports = typeDefs;\n<\/code><\/pre>\n<p>Yukar\u0131daki \u015femada:<\/p>\n<ul>\n<li><code>Book<\/code>: Kitap nesnesinin yap\u0131s\u0131n\u0131 tan\u0131mlayan bir t\u00fcrd\u00fcr.<\/li>\n<li><code>Query<\/code>: API&#8217;mizden veri almak i\u00e7in kullanabilece\u011fimiz sorgular\u0131 i\u00e7erir (<code>books<\/code> ve <code>book<\/code>).<\/li>\n<li><code>Mutation<\/code>: API&#8217;mizdeki veriyi de\u011fi\u015ftirmek i\u00e7in kullanabilece\u011fimiz operasyonlar\u0131 i\u00e7erir (<code>addBook<\/code>, <code>updateBook<\/code>, <code>deleteBook<\/code>).<\/li>\n<li><code>ID!<\/code>, <code>String!<\/code> gibi ifadeler, alan\u0131n bo\u015f (null) olamayaca\u011f\u0131n\u0131 belirtir.<\/li>\n<li><code>[Book!]!<\/code> gibi ifadeler, bir <code>Book<\/code> nesneleri dizisi d\u00f6nd\u00fcr\u00fclece\u011fini ve bu dizinin kendisinin bo\u015f olamayaca\u011f\u0131n\u0131 ve i\u00e7indeki her bir eleman\u0131n da bo\u015f olamayaca\u011f\u0131n\u0131 belirtir.<\/li>\n<\/ul>\n<h3>\u00c7\u00f6z\u00fcmleyicileri (Resolvers) Yazma<\/h3>\n<p>\u015eemay\u0131 tan\u0131mlad\u0131ktan sonra, bu \u015femadaki alanlar\u0131n verilerini nas\u0131l alaca\u011f\u0131m\u0131z\u0131 veya i\u015fleyece\u011fimizi belirten \u00e7\u00f6z\u00fcmleyici (resolver) fonksiyonlar\u0131n\u0131 yazmam\u0131z gerekir. <code>src\/resolvers.js<\/code> ad\u0131nda bir dosya olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ src\/resolvers.js\n\n\/\/ Ge\u00e7ici bir veri deposu olarak kullanaca\u011f\u0131m\u0131z bir dizi olu\u015ftural\u0131m.\n\/\/ Ger\u00e7ek uygulamalarda buras\u0131 bir veritaban\u0131 veya ba\u015fka bir veri kayna\u011f\u0131 olacakt\u0131r.\nconst books = [\n  { id: '1', title: 'Lord of the Rings', author: 'J.R.R. Tolkien', year: 1954 },\n  { id: '2', title: 'The Hobbit', author: 'J.R.R. Tolkien', year: 1937 },\n  { id: '3', title: '1984', author: 'George Orwell', year: 1949 },\n];\n\nlet nextBookId = books.length + 1; \/\/ Yeni kitaplar i\u00e7in ID olu\u015fturucu\n\nconst resolvers = {\n  Query: {\n    \/\/ 'books' sorgusu i\u00e7in \u00e7\u00f6z\u00fcmleyici: T\u00fcm kitaplar\u0131 d\u00f6nd\u00fcr\u00fcr.\n    books: () => books,\n    \/\/ 'book' sorgusu i\u00e7in \u00e7\u00f6z\u00fcmleyici: Belirli bir ID'ye sahip kitab\u0131 d\u00f6nd\u00fcr\u00fcr.\n    \/\/ 'args' parametresi sorguda ge\u00e7irilen arg\u00fcmanlar\u0131 (bu durumda 'id') i\u00e7erir.\n    book: (parent, args) => books.find(book => book.id === args.id),\n  },\n  Mutation: {\n    \/\/ 'addBook' mutasyonu i\u00e7in \u00e7\u00f6z\u00fcmleyici: Yeni bir kitap ekler.\n    addBook: (parent, args) => {\n      const newBook = {\n        id: String(nextBookId++), \/\/ Yeni bir ID atar\n        title: args.title,\n        author: args.author,\n        year: args.year || null, \/\/ Y\u0131l iste\u011fe ba\u011fl\u0131 oldu\u011fu i\u00e7in null olabilir\n      };\n      books.push(newBook);\n      return newBook;\n    },\n    \/\/ 'updateBook' mutasyonu i\u00e7in \u00e7\u00f6z\u00fcmleyici: Varolan bir kitab\u0131 g\u00fcnceller.\n    updateBook: (parent, args) => {\n      const bookIndex = books.findIndex(book => book.id === args.id);\n      if (bookIndex === -1) {\n        throw new Error(<code>Kitap bulunamad\u0131: ${args.id}<\/code>);\n      }\n      const updatedBook = {\n        ...books[bookIndex],\n        ...args, \/\/ Arg\u00fcmanlardaki t\u00fcm g\u00fcncel alanlar\u0131 mevcut kitaba uygula\n      };\n      books[bookIndex] = updatedBook;\n      return updatedBook;\n    },\n    \/\/ 'deleteBook' mutasyonu i\u00e7in \u00e7\u00f6z\u00fcmleyici: Bir kitab\u0131 siler.\n    deleteBook: (parent, args) => {\n      const bookIndex = books.findIndex(book => book.id === args.id);\n      if (bookIndex === -1) {\n        throw new Error(<code>Kitap bulunamad\u0131: ${args.id}<\/code>);\n      }\n      books.splice(bookIndex, 1); \/\/ Diziden kitab\u0131 kald\u0131r\n      return args.id; \/\/ Silinen kitab\u0131n ID'sini d\u00f6nd\u00fcr\n    },\n  },\n};\n\nmodule.exports = resolvers;\n<\/code><\/pre>\n<p>Her resolver fonksiyonu d\u00f6rt arg\u00fcman alabilir: <code>(parent, args, context, info)<\/code>:<\/p>\n<ul>\n<li><code>parent<\/code> (veya <code>root<\/code>): \u00d6nceki resolver&#8217;\u0131n d\u00f6nd\u00fcrd\u00fc\u011f\u00fc sonu\u00e7tur. Genellikle \u00fcst t\u00fcr\u00fcn verisini i\u00e7erir.<\/li>\n<li><code>args<\/code>: Sorguya veya mutasyona ge\u00e7irilen arg\u00fcmanlard\u0131r (\u00f6rn. <code>book(id: \"1\")<\/code> sorgusundaki <code>id<\/code>).<\/li>\n<li><code>context<\/code>: T\u00fcm resolver&#8217;lar aras\u0131nda payla\u015f\u0131lan bir nesnedir. Veritaban\u0131 ba\u011flant\u0131lar\u0131, kimlik do\u011frulama bilgileri gibi ortak kaynaklar\u0131 ta\u015f\u0131mak i\u00e7in kullan\u0131l\u0131r.<\/li>\n<li><code>info<\/code>: Sorgunun y\u00fcr\u00fctme durumu hakk\u0131nda daha fazla bilgi i\u00e7eren geli\u015fmi\u015f bir nesnedir.<\/li>\n<\/ul>\n<h3>Sunucuyu Ba\u015flatma<\/h3>\n<p>\u015eema ve \u00e7\u00f6z\u00fcmleyicileri tan\u0131mlad\u0131ktan sonra, Apollo Server&#8217;\u0131 kullanarak sunucumuzu ba\u015flatabiliriz. <code>index.js<\/code> ad\u0131nda ana bir dosya olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ index.js\nconst express = require('express');\nconst { ApolloServer } = require('apollo-server-express');\nconst typeDefs = require('.\/src\/schema');\nconst resolvers = require('.\/src\/resolvers');\n\nasync function startApolloServer() {\n  const app = express(); \/\/ Express uygulamas\u0131n\u0131 ba\u015flat\n\n  \/\/ Apollo Server \u00f6rne\u011fini olu\u015ftur\n  const server = new ApolloServer({\n    typeDefs,  \/\/ \u015eema tan\u0131mlar\u0131n\u0131 Apollo Server'a ilet\n    resolvers, \/\/ \u00c7\u00f6z\u00fcmleyicileri Apollo Server'a ilet\n    \/\/ Geli\u015ftirme ortam\u0131nda GraphQL Playground'u etkinle\u015ftir\n    \/\/ production ortam\u0131nda kapat\u0131lmas\u0131 g\u00fcvenlik a\u00e7\u0131s\u0131ndan \u00f6nerilir\n    introspection: true, \n    playground: true, \n  });\n\n  \/\/ Apollo Server'\u0131 ba\u015flat\n  await server.start();\n\n  \/\/ Apollo Server'\u0131 Express uygulamas\u0131na middleware olarak uygula\n  server.applyMiddleware({ app, path: '\/graphql' });\n\n  const PORT = process.env.PORT || 4000;\n\n  \/\/ Express sunucusunu dinlemeye ba\u015fla\n  app.listen(PORT, () => {\n    console.log(<code>GraphQL API sunucusu \u00e7al\u0131\u015f\u0131yor: http:\/\/localhost:${PORT}\/graphql<\/code>);\n    console.log(<code>GraphQL Playground'a eri\u015fmek i\u00e7in: http:\/\/localhost:${PORT}\/graphql<\/code>);\n  });\n}\n\nstartApolloServer();\n<\/code><\/pre>\n<p>\u015eimdi terminalde <code>node index.js<\/code> komutunu \u00e7al\u0131\u015ft\u0131rarak sunucuyu ba\u015flatabilirsiniz. Sunucu ba\u015far\u0131yla \u00e7al\u0131\u015ft\u0131\u011f\u0131nda, <code>http:\/\/localhost:4000\/graphql<\/code> adresine giderek GraphQL Playground aray\u00fcz\u00fcn\u00fc g\u00f6receksiniz. Bu aray\u00fcz, API&#8217;nizi test etmek, sorgu yazmak ve \u015fema dok\u00fcmantasyonunu g\u00f6r\u00fcnt\u00fclemek i\u00e7in harika bir ara\u00e7t\u0131r.<\/p>\n<h3>Test Etme<\/h3>\n<p>GraphQL Playground&#8217;da a\u015fa\u011f\u0131daki sorgular\u0131 ve mutasyonlar\u0131 deneyebilirsiniz:<\/p>\n<p><strong>T\u00fcm kitaplar\u0131 sorgulama:<\/strong><\/p>\n<pre><code class=\"language-graphql\">\nquery {\n  books {\n    id\n    title\n    author\n    year\n  }\n}\n<\/code><\/pre>\n<p><strong>Belirli bir kitab\u0131 ID ile sorgulama:<\/strong><\/p>\n<pre><code class=\"language-graphql\">\nquery {\n  book(id: \"1\") {\n    title\n    author\n  }\n}\n<\/code><\/pre>\n<p><strong>Yeni bir kitap ekleme (Mutasyon):<\/strong><\/p>\n<pre><code class=\"language-graphql\">\nmutation {\n  addBook(title: \"The Great Gatsby\", author: \"F. Scott Fitzgerald\", year: 1925) {\n    id\n    title\n    author\n    year\n  }\n}\n<\/code><\/pre>\n<p><strong>Bir kitab\u0131 g\u00fcncelleme (Mutasyon):<\/strong><\/p>\n<pre><code class=\"language-graphql\">\nmutation {\n  updateBook(id: \"4\", title: \"The Great Gatsby (Updated)\", year: 1926) {\n    id\n    title\n    author\n    year\n  }\n}\n<\/code><\/pre>\n<p><strong>Bir kitab\u0131 silme (Mutasyon):<\/strong><\/p>\n<pre><code class=\"language-graphql\">\nmutation {\n  deleteBook(id: \"4\")\n}\n<\/code><\/pre>\n<h2>Veri Kaynaklar\u0131n\u0131 Entegre Etme<\/h2>\n<h3>Data Sources Kavram\u0131<\/h3>\n<p>\u015eu ana kadar ge\u00e7ici bir dizi kulland\u0131k. Ger\u00e7ek d\u00fcnya uygulamalar\u0131nda veriler genellikle veritabanlar\u0131ndan (SQL, NoSQL), REST API&#8217;lerinden veya di\u011fer mikroservislerden gelir. Apollo Server, bu t\u00fcr veri kaynaklar\u0131n\u0131 y\u00f6netmek i\u00e7in <code>Data Sources<\/code> ad\u0131 verilen bir soyutlama katman\u0131 sunar. Data sources, veri alma mant\u0131\u011f\u0131n\u0131 \u00e7\u00f6z\u00fcmleyicilerden ay\u0131rarak kodunuzu daha temiz, test edilebilir ve yeniden kullan\u0131labilir hale getirir. Ayr\u0131ca, otomatik \u00f6nbellekleme (caching) gibi \u00f6zellikler de sunabilirler.<\/p>\n<h3>Apollo Data Sources<\/h3>\n<p>Apollo Server, <code>apollo-datasource<\/code> ve <code>apollo-datasource-rest<\/code> gibi paketlerle \u00e7e\u015fitli veri kaynaklar\u0131n\u0131 entegre etmek i\u00e7in kolay bir yol sunar. \u00d6rne\u011fin, bir REST API&#8217;den veri \u00e7ekecekseniz <code>RESTDataSource<\/code> s\u0131n\u0131f\u0131n\u0131 kullanabilirsiniz. Bir veritaban\u0131 ile \u00e7al\u0131\u015f\u0131rken, genellikle \u00f6zel bir <code>DataSource<\/code> s\u0131n\u0131f\u0131 olu\u015fturur veya do\u011frudan veritaban\u0131 istemcisini <code>context<\/code> objesi arac\u0131l\u0131\u011f\u0131yla resolver&#8217;lara iletiriz.<\/p>\n<h3>Veritaban\u0131 Entegrasyonu (\u00d6rnek: MongoDB ve Mongoose)<\/h3>\n<p>Bir MongoDB veritaban\u0131 ile entegrasyonu g\u00f6stermek i\u00e7in Mongoose ORM&#8217;yi kullanal\u0131m. \u0130lk olarak, Mongoose&#8217;u y\u00fckleyin:<\/p>\n<pre><code class=\"language-bash\">\nnpm install mongoose dotenv\n<\/code><\/pre>\n<p><code>.env<\/code> dosyan\u0131z\u0131 olu\u015fturun ve MongoDB ba\u011flant\u0131 URI&#8217;nizi ekleyin:<\/p>\n<pre><code class=\"language-dotenv\">\nMONGO_URI=\"mongodb:\/\/localhost:27017\/graphql-books-db\"\n<\/code><\/pre>\n<p><code>src\/models\/Book.js<\/code> ad\u0131nda bir dosya olu\u015fturun:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ src\/models\/Book.js\nconst mongoose = require('mongoose');\n\nconst bookSchema = new mongoose.Schema({\n  title: {\n    type: String,\n    required: true,\n  },\n  author: {\n    type: String,\n    required: true,\n  },\n  year: {\n    type: Number,\n  },\n});\n\nmodule.exports = mongoose.model('Book', bookSchema);\n<\/code><\/pre>\n<p>\u015eimdi <code>src\/datasources\/BooksAPI.js<\/code> ad\u0131nda bir veri kayna\u011f\u0131 olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ src\/datasources\/BooksAPI.js\nconst { DataSource } = require('apollo-datasource');\nconst Book = require('..\/models\/Book'); \/\/ Mongoose modelimizi dahil et\n\nclass BooksAPI extends DataSource {\n  constructor() {\n    super();\n  }\n\n  \/<em><\/em>\n   * Bu fonksiyon, Apollo Server'\u0131n ba\u015flang\u0131\u00e7ta veri kayna\u011f\u0131n\u0131 ba\u015flatmak i\u00e7in \u00e7a\u011f\u0131r\u0131l\u0131r.\n   * Genellikle context'i burada al\u0131r\u0131z.\n   *\/\n  initialize(config) {\n    this.context = config.context;\n  }\n\n  async getAllBooks() {\n    return Book.find(); \/\/ T\u00fcm kitaplar\u0131 veritaban\u0131ndan \u00e7ek\n  }\n\n  async getBookById(id) {\n    return Book.findById(id); \/\/ Belirli bir ID'ye sahip kitab\u0131 \u00e7ek\n  }\n\n  async createBook(bookInput) {\n    const newBook = new Book(bookInput);\n    await newBook.save();\n    return newBook;\n  }\n\n  async updateBook(id, bookInput) {\n    return Book.findByIdAndUpdate(id, bookInput, { new: true }); \/\/ G\u00fcncellenmi\u015f belgeyi d\u00f6nd\u00fcr\n  }\n\n  async deleteBook(id) {\n    await Book.findByIdAndDelete(id);\n    return id;\n  }\n}\n\nmodule.exports = BooksAPI;\n<\/code><\/pre>\n<p>Resolver&#8217;lar\u0131m\u0131z\u0131 bu veri kayna\u011f\u0131n\u0131 kullanacak \u015fekilde g\u00fcncelleyelim (<code>src\/resolvers.js<\/code>):<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ src\/resolvers.js (G\u00fcncellenmi\u015f)\nconst resolvers = {\n  Query: {\n    books: (parent, args, { dataSources }) => dataSources.booksAPI.getAllBooks(),\n    book: (parent, { id }, { dataSources }) => dataSources.booksAPI.getBookById(id),\n  },\n  Mutation: {\n    addBook: (parent, args, { dataSources }) => dataSources.booksAPI.createBook(args),\n    updateBook: (parent, { id, ...rest }, { dataSources }) => dataSources.booksAPI.updateBook(id, rest),\n    deleteBook: (parent, { id }, { dataSources }) => dataSources.booksAPI.deleteBook(id),\n  },\n};\n\nmodule.exports = resolvers;\n<\/code><\/pre>\n<p>Son olarak, <code>index.js<\/code> dosyas\u0131n\u0131 g\u00fcncelleyerek veritaban\u0131 ba\u011flant\u0131s\u0131n\u0131 ve veri kaynaklar\u0131n\u0131 Apollo Server&#8217;a ekleyelim:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ index.js (G\u00fcncellenmi\u015f)\nrequire('dotenv').config(); \/\/ .env dosyas\u0131n\u0131 y\u00fckle\nconst express = require('express');\nconst { ApolloServer } = require('apollo-server-express');\nconst mongoose = require('mongoose'); \/\/ Mongoose'u dahil et\nconst typeDefs = require('.\/src\/schema');\nconst resolvers = require('.\/src\/resolvers');\nconst BooksAPI = require('.\/src\/datasources\/BooksAPI'); \/\/ Veri kayna\u011f\u0131m\u0131z\u0131 dahil et\n\nasync function startApolloServer() {\n  const app = express();\n\n  \/\/ MongoDB ba\u011flant\u0131s\u0131\n  try {\n    await mongoose.connect(process.env.MONGO_URI, {\n      useNewUrlParser: true,\n      useUnifiedTopology: true,\n    });\n    console.log('MongoDB ba\u011flant\u0131s\u0131 ba\u015far\u0131l\u0131.');\n  } catch (error) {\n    console.error('MongoDB ba\u011flant\u0131 hatas\u0131:', error);\n    process.exit(1); \/\/ Hata durumunda uygulamay\u0131 sonland\u0131r\n  }\n\n  const server = new ApolloServer({\n    typeDefs,\n    resolvers,\n    \/\/ dataSources fonksiyonu, her istek i\u00e7in yeni bir veri kayna\u011f\u0131 \u00f6rne\u011fi olu\u015fturur.\n    dataSources: () => ({\n      booksAPI: new BooksAPI(),\n    }),\n    \/\/ Context fonksiyonu, her istekle birlikte resolver'lara iletilecek bir nesne olu\u015fturur.\n    \/\/ Burada kimlik do\u011frulama bilgileri veya di\u011fer payla\u015f\u0131lan kaynaklar eklenebilir.\n    context: ({ req }) => {\n      \/\/ \u00d6rnek: HTTP ba\u015fl\u0131klar\u0131ndan token alma\n      const token = req.headers.authorization || '';\n      return { token };\n    },\n    introspection: true,\n    playground: true,\n  });\n\n  await server.start();\n  server.applyMiddleware({ app, path: '\/graphql' });\n\n  const PORT = process.env.PORT || 4000;\n\n  app.listen(PORT, () => {\n    console.log(<code>GraphQL API sunucusu \u00e7al\u0131\u015f\u0131yor: http:\/\/localhost:${PORT}\/graphql<\/code>);\n    console.log(<code>GraphQL Playground'a eri\u015fmek i\u00e7in: http:\/\/localhost:${PORT}\/graphql<\/code>);\n  });\n}\n\nstartApolloServer();\n<\/code><\/pre>\n<p>Bu de\u011fi\u015fikliklerle art\u0131k API&#8217;niz verileri MongoDB&#8217;den al\u0131p kaydedecektir.<\/p>\n<h2>Geli\u015fmi\u015f Konular<\/h2>\n<h3>Subscription&#8217;lar (Abonelikler)<\/h3>\n<p>Subscription&#8217;lar, GraphQL API&#8217;nizin istemcilere ger\u00e7ek zamanl\u0131 olarak veri ak\u0131\u015f\u0131 sa\u011flamas\u0131na olanak tan\u0131r. Bir olay (\u00f6rn. yeni bir kitap eklendi\u011finde) meydana geldi\u011finde, sunucu bu olaya abone olan t\u00fcm istemcilere bir g\u00fcncelleme g\u00f6nderir. Subscription&#8217;lar genellikle WebSockets \u00fczerinden \u00e7al\u0131\u015f\u0131r.<\/p>\n<p>Apollo Server, subscription&#8217;lar\u0131 desteklemek i\u00e7in <code>graphql-subscriptions<\/code> paketiyle entegre edilebilir bir <code>PubSub<\/code> (Publish\/Subscribe) mekanizmas\u0131 sunar.<\/p>\n<p><strong>Kurulum:<\/strong><\/p>\n<pre><code class=\"language-bash\">\nnpm install graphql-subscriptions ws\n<\/code><\/pre>\n<p><strong>\u015eema G\u00fcncelleme (src\/schema.js):<\/strong><\/p>\n<pre><code class=\"language-javascript\">\n\/\/ ...\nconst typeDefs = gql<code>\n  # ... Book, Query, Mutation t\u00fcrleri ...\n\n  # 'Subscription' t\u00fcr\u00fc, ger\u00e7ek zamanl\u0131 olaylar\u0131 tan\u0131mlar.\n  type Subscription {\n    newBook: Book! # Yeni bir kitap eklendi\u011finde tetiklenir.\n  }\n<\/code>;\n\/\/ ...\n<\/code><\/pre>\n<p><strong>Resolver G\u00fcncelleme (src\/resolvers.js):<\/strong><\/p>\n<pre><code class=\"language-javascript\">\n\/\/ ...\nconst { PubSub } = require('graphql-subscriptions');\nconst pubsub = new PubSub(); \/\/ Bir PubSub \u00f6rne\u011fi olu\u015ftur\n\nconst BOOK_ADDED = 'BOOK_ADDED'; \/\/ Olay tipi i\u00e7in bir sabit tan\u0131mla\n\nconst resolvers = {\n  Query: { \/<em> ... <\/em>\/ },\n  Mutation: {\n    addBook: async (parent, args, { dataSources }) => {\n      const newBook = await dataSources.booksAPI.createBook(args);\n      pubsub.publish(BOOK_ADDED, { newBook: newBook }); \/\/ Yeni kitab\u0131 yay\u0131nla\n      return newBook;\n    },\n    \/\/ ... di\u011fer mutasyonlar ...\n  },\n  Subscription: {\n    newBook: {\n      subscribe: () => pubsub.asyncIterator([BOOK_ADDED]), \/\/ Abone olunan olaylar\u0131 dinle\n    },\n  },\n};\n\/\/ ...\n<\/code><\/pre>\n<p><strong>Sunucu G\u00fcncelleme (index.js):<\/strong><\/p>\n<pre><code class=\"language-javascript\">\n\/\/ ...\nconst { createServer } = require('http'); \/\/ HTTP sunucusu i\u00e7in\nconst { execute, subscribe } = require('graphql'); \/\/ Subscription'lar i\u00e7in\nconst { SubscriptionServer } = require('subscriptions-transport-ws'); \/\/ WebSocket sunucusu i\u00e7in\n\nasync function startApolloServer() {\n  \/\/ ... MongoDB ba\u011flant\u0131s\u0131 ...\n\n  const app = express();\n  const httpServer = createServer(app); \/\/ HTTP sunucusunu Express uygulamas\u0131yla olu\u015ftur\n\n  const server = new ApolloServer({\n    typeDefs,\n    resolvers,\n    dataSources: () => ({\n      booksAPI: new BooksAPI(),\n    }),\n    context: ({ req, connection }) => {\n      \/\/ WebSocket ba\u011flant\u0131lar\u0131 i\u00e7in context y\u00f6netimi\n      if (connection) {\n        return connection.context;\n      }\n      const token = req.headers.authorization || '';\n      return { token };\n    },\n    introspection: true,\n    playground: true,\n  });\n\n  await server.start();\n  server.applyMiddleware({ app, path: '\/graphql' });\n\n  \/\/ Subscription sunucusunu ba\u015flat\n  SubscriptionServer.create(\n    {\n      schema: server.schema, \/\/ Apollo Server'\u0131n \u015femas\u0131n\u0131 kullan\n      execute,\n      subscribe,\n      onConnect: (connectionParams, websocket, context) => {\n        console.log('Client connected for subscriptions');\n        \/\/ \u0130ste\u011fe ba\u011fl\u0131: Burada kimlik do\u011frulama yap\u0131labilir\n        return { currentUser: 'someUser' }; \/\/ Context'e eklenecek veri\n      },\n      onDisconnect: (websocket, context) => {\n        console.log('Client disconnected from subscriptions');\n      },\n    },\n    {\n      server: httpServer, \/\/ HTTP sunucusunu kullan\n      path: '\/graphql', \/\/ Ayn\u0131 path'i kullanabilir\n    }\n  );\n\n  const PORT = process.env.PORT || 4000;\n\n  \/\/ HTTP sunucusunu dinlemeye ba\u015fla\n  httpServer.listen(PORT, () => {\n    console.log(<code>GraphQL API sunucusu \u00e7al\u0131\u015f\u0131yor: http:\/\/localhost:${PORT}\/graphql<\/code>);\n    console.log(<code>GraphQL Playground'a eri\u015fmek i\u00e7in: http:\/\/localhost:${PORT}\/graphql<\/code>);\n    console.log(<code>Subscription endpoint: ws:\/\/localhost:${PORT}\/graphql<\/code>);\n  });\n}\n\nstartApolloServer();\n<\/code><\/pre>\n<p>\u015eimdi GraphQL Playground&#8217;da &#8220;newBook&#8221; subscription&#8217;\u0131na abone olabilir ve yeni bir kitap ekledi\u011finizde an\u0131nda bildirim alabilirsiniz.<\/p>\n<h3>Ba\u011flam (Context) Kullan\u0131m\u0131<\/h3>\n<p><code>context<\/code> nesnesi, her GraphQL i\u015flemi i\u00e7in olu\u015fturulan ve t\u00fcm resolver&#8217;lar aras\u0131nda payla\u015f\u0131lan bir nesnedir. Veritaban\u0131 ba\u011flant\u0131lar\u0131, kimlik do\u011frulama bilgileri, kullan\u0131c\u0131 oturumu veya payla\u015f\u0131lan servisler gibi her iste\u011fe \u00f6zg\u00fc verileri ta\u015f\u0131mak i\u00e7in idealdir. <code>ApolloServer<\/code> yap\u0131land\u0131rmas\u0131nda bir <code>context<\/code> fonksiyonu tan\u0131mlayarak bu nesneyi olu\u015fturabilirsiniz:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ index.js i\u00e7indeki context tan\u0131m\u0131\ncontext: ({ req }) => {\n  \/\/ HTTP ba\u015fl\u0131klar\u0131ndan token'\u0131 al\n  const token = req.headers.authorization || '';\n  \/\/ Token'\u0131 do\u011frula ve kullan\u0131c\u0131 bilgilerini context'e ekle\n  \/\/ const user = await authService.getUserFromToken(token);\n  return { token \/<em>, user <\/em>\/ };\n},\n<\/code><\/pre>\n<p>Resolver&#8217;lar\u0131n\u0131zda bu bilgilere \u00fc\u00e7\u00fcnc\u00fc arg\u00fcman olarak eri\u015febilirsiniz:<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ src\/resolvers.js\nconst resolvers = {\n  Query: {\n    books: (parent, args, context) => {\n      \/\/ console.log(context.token); \/\/ Token'a eri\u015fim\n      \/\/ if (!context.user) throw new AuthenticationError('Giri\u015f yap\u0131lmal\u0131');\n      return context.dataSources.booksAPI.getAllBooks();\n    },\n  },\n  \/\/ ...\n};\n<\/code><\/pre>\n<h3>Kimlik Do\u011frulama ve Yetkilendirme (Authentication &#038; Authorization)<\/h3>\n<p>G\u00fcvenli bir API i\u00e7in kimlik do\u011frulama (kullan\u0131c\u0131n\u0131n kim oldu\u011funu belirleme) ve yetkilendirme (kullan\u0131c\u0131n\u0131n neye eri\u015febilece\u011fini belirleme) \u00e7ok \u00f6nemlidir.<\/p>\n<ul>\n<li><strong>Kimlik Do\u011frulama:<\/strong> Genellikle <code>context<\/code> fonksiyonu i\u00e7inde bir JWT (JSON Web Token) veya oturum tabanl\u0131 bir mekanizma kullan\u0131larak yap\u0131l\u0131r. HTTP ba\u015fl\u0131klar\u0131ndan token al\u0131n\u0131r, do\u011frulan\u0131r ve kullan\u0131c\u0131 bilgileri <code>context<\/code> nesnesine eklenir.<\/li>\n<li><strong>Yetkilendirme:<\/strong>\n<ul>\n<li><strong>Resolver Seviyesinde:<\/strong> Her resolver&#8217;\u0131n ba\u015f\u0131nda kullan\u0131c\u0131n\u0131n yetkisi olup olmad\u0131\u011f\u0131n\u0131 kontrol edebilirsiniz.<\/li>\n<li><strong>Custom Direktifler:<\/strong> GraphQL SDL&#8217;de \u00f6zel direktifler (\u00f6rn. <code>@auth<\/code>, <code>@hasRole(role: \"ADMIN\")<\/code>) tan\u0131mlayarak yetkilendirme mant\u0131\u011f\u0131n\u0131 \u015femaya ta\u015f\u0131yabilirsiniz. Apollo Server, custom direktifleri uygulamak i\u00e7in bir API sunar.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3>Hata Y\u00f6netimi (Error Handling)<\/h3>\n<p>GraphQL, hatalar\u0131 belirli bir formatta d\u00f6nd\u00fcr\u00fcr. Apollo Server, hatalar\u0131 yakalamak ve \u00f6zelle\u015ftirmek i\u00e7in <code>formatError<\/code> se\u00e7ene\u011fi sunar. Kendi \u00f6zel hata s\u0131n\u0131flar\u0131n\u0131z\u0131 (\u00f6rn. <code>AuthenticationError<\/code>, <code>ForbiddenError<\/code>) olu\u015fturabilir ve bunlar\u0131 <code>formatError<\/code> i\u00e7inde i\u015fleyerek istemciye daha anlaml\u0131 hata mesajlar\u0131 g\u00f6nderebilirsiniz.<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ ApolloServer yap\u0131land\u0131rmas\u0131nda\nconst server = new ApolloServer({\n  \/\/ ...\n  formatError: (error) => {\n    \/\/ Hata mesaj\u0131n\u0131 ve detaylar\u0131n\u0131 \u00f6zelle\u015ftir\n    if (error.extensions.code === 'BAD_USER_INPUT') {\n      return new Error('Ge\u00e7ersiz giri\u015f verisi.');\n    }\n    \/\/ Di\u011fer hatalar\u0131 oldu\u011fu gibi d\u00f6nd\u00fcr\n    return error;\n  },\n  \/\/ ...\n});\n<\/code><\/pre>\n<h3>Performans Optimizasyonu<\/h3>\n<ul>\n<li><strong>N+1 Problemi ve DataLoader:<\/strong> Bir sorguda birincil nesneleri (\u00f6rn. kitaplar) ve ard\u0131ndan her birincil nesnenin ili\u015fkili nesnelerini (\u00f6rn. her kitab\u0131n yazar\u0131) \u00e7ekti\u011finizde, her ili\u015fkili nesne i\u00e7in ayr\u0131 bir veritaban\u0131 sorgusu tetiklenir. Bu, &#8220;N+1 problemi&#8221; olarak bilinir. DataLoader, bu t\u00fcr sorgular\u0131 birle\u015ftirerek (batching) ve \u00f6nbelle\u011fe alarak N+1 problemini \u00e7\u00f6zer ve veritaban\u0131 y\u00fck\u00fcn\u00fc \u00f6nemli \u00f6l\u00e7\u00fcde azalt\u0131r.<\/li>\n<li><strong>Caching:<\/strong> Apollo Server, veri kaynaklar\u0131 seviyesinde veya manuel olarak resolver&#8217;larda \u00f6nbellekleme uygulaman\u0131za olanak tan\u0131r.<\/li>\n<li><strong>Persisted Queries:<\/strong> \u0130stemciler taraf\u0131ndan s\u0131k\u00e7a kullan\u0131lan sorgular\u0131 sunucu taraf\u0131nda \u00f6nceden kaydederek, a\u011f trafi\u011fini azaltabilir ve sorgu do\u011frulama maliyetini d\u00fc\u015f\u00fcrebilirsiniz.<\/li>\n<\/ul>\n<h2>Proje Yap\u0131s\u0131 ve En \u0130yi Uygulamalar<\/h2>\n<h3>Mod\u00fcler \u015eema Tasar\u0131m\u0131<\/h3>\n<p>B\u00fcy\u00fck GraphQL API&#8217;lerinde tek bir \u015fema dosyas\u0131 y\u00f6netmek zorla\u015fabilir. \u015eemay\u0131 mant\u0131ksal mod\u00fcllere (\u00f6rn. <code>users.graphql<\/code>, <code>products.graphql<\/code>) ay\u0131rmak ve bunlar\u0131 birle\u015ftirmek (schema stitching veya daha modern yakla\u015f\u0131mlar olan Apollo Federation) iyi bir uygulamad\u0131r.<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ src\/index.js veya schema.js i\u00e7inde\nconst { mergeTypeDefs, mergeResolvers } = require('@graphql-tools\/merge');\nconst { loadFilesSync } = require('@graphql-tools\/load-files');\nconst path = require('path');\n\nconst typesArray = loadFilesSync(path.join(__dirname, '.\/schemas'), { extensions: ['graphql'] });\nconst resolversArray = loadFilesSync(path.join(__dirname, '.\/resolvers'), { extensions: ['js'] });\n\nconst typeDefs = mergeTypeDefs(typesArray);\nconst resolvers = mergeResolvers(resolversArray);\n\nmodule.exports = { typeDefs, resolvers };\n<\/code><\/pre>\n<p>Bu yap\u0131land\u0131rma ile <code>src\/schemas<\/code> ve <code>src\/resolvers<\/code> klas\u00f6rlerindeki t\u00fcm <code>.graphql<\/code> ve <code>.js<\/code> dosyalar\u0131n\u0131 otomatik olarak birle\u015ftirebilirsiniz.<\/p>\n<h3>Klas\u00f6r Yap\u0131s\u0131<\/h3>\n<p>Temiz ve d\u00fczenli bir klas\u00f6r yap\u0131s\u0131, projenizin \u00f6l\u00e7eklenebilirli\u011fini art\u0131r\u0131r:<\/p>\n<pre><code>\ngraphql-api-server\/\n\u251c\u2500\u2500 node_modules\/\n\u251c\u2500\u2500 src\/\n\u2502   \u251c\u2500\u2500 schemas\/        # .graphql uzant\u0131l\u0131 \u015fema tan\u0131mlar\u0131 (\u00f6rn. book.graphql, user.graphql)\n\u2502   \u251c\u2500\u2500 resolvers\/      # Resolver fonksiyonlar\u0131 (\u00f6rn. bookResolver.js, userResolver.js)\n\u2502   \u251c\u2500\u2500 datasources\/    # Veri kaynaklar\u0131 (\u00f6rn. BooksAPI.js, UsersAPI.js)\n\u2502   \u251c\u2500\u2500 models\/         # Veritaban\u0131 modelleri (\u00f6rn. Book.js, User.js)\n\u2502   \u251c\u2500\u2500 utils\/          # Yard\u0131mc\u0131 fonksiyonlar, kimlik do\u011frulama vb.\n\u2502   \u2514\u2500\u2500 index.js        # Ana uygulama dosyas\u0131\n\u251c\u2500\u2500 .env\n\u251c\u2500\u2500 package.json\n\u2514\u2500\u2500 README.md\n<\/code><\/pre>\n<h3>G\u00fcvenlik \u0130pu\u00e7lar\u0131<\/h3>\n<ul>\n<li><strong>Derinlik ve Karma\u015f\u0131kl\u0131k Limitleri:<\/strong> K\u00f6t\u00fc niyetli kullan\u0131c\u0131lar, \u00e7ok derin veya karma\u015f\u0131k sorgular g\u00f6ndererek sunucunuzu yorabilir. Bu t\u00fcr sorgular\u0131 engellemek i\u00e7in Apollo Server&#8217;da sorgu derinli\u011fi ve karma\u015f\u0131kl\u0131k limitleri uygulay\u0131n.<\/li>\n<li><strong>Veri Do\u011frulama:<\/strong> Input t\u00fcrlerini ve resolver&#8217;lar\u0131 kullanarak gelen verileri her zaman do\u011frulay\u0131n.<\/li>\n<li><strong>CSRF Korumas\u0131:<\/strong> Mutasyonlar i\u00e7in CSRF (Cross-Site Request Forgery) korumas\u0131 uygulay\u0131n.<\/li>\n<li><strong>Hata Mesajlar\u0131n\u0131 Gizleme:<\/strong> \u00dcretim ortam\u0131nda ayr\u0131nt\u0131l\u0131 hata mesajlar\u0131n\u0131 istemcilere g\u00f6ndermekten ka\u00e7\u0131n\u0131n. Bu, sald\u0131rganlara sisteminiz hakk\u0131nda bilgi verebilir.<\/li>\n<li><strong>Rate Limiting:<\/strong> API&#8217;nize gelen istekleri s\u0131n\u0131rlayarak DDoS sald\u0131r\u0131lar\u0131n\u0131 \u00f6nleyin.<\/li>\n<\/ul>\n<h3>Test Etme<\/h3>\n<p>GraphQL API&#8217;nizi test etmek, uygulaman\u0131z\u0131n kalitesini ve g\u00fcvenilirli\u011fini sa\u011flar. Unit testler (resolver&#8217;lar i\u00e7in), entegrasyon testleri (Apollo Server instance&#8217;\u0131 ile) ve u\u00e7tan uca testler (ger\u00e7ek bir istemci gibi davranarak) yazmak \u00f6nemlidir. Jest ve Supertest gibi k\u00fct\u00fcphaneler bu s\u00fcre\u00e7te yard\u0131mc\u0131 olabilir.<\/p>\n<h2>Sonu\u00e7<\/h2>\n<p>Bu makalede, Node.js ve Apollo Server kullanarak kapsaml\u0131 bir GraphQL API sunucusu kurulumunu ele ald\u0131k. GraphQL&#8217;in temel kavramlar\u0131ndan ba\u015flayarak, \u015fema tan\u0131mlama, \u00e7\u00f6z\u00fcmleyicileri yazma, veritaban\u0131 entegrasyonu, abonelikler, kimlik do\u011frulama, hata y\u00f6netimi ve performans optimizasyonu gibi geli\u015fmi\u015f konulara de\u011findik. Ayr\u0131ca, mod\u00fcler bir proje yap\u0131s\u0131 ve en iyi g\u00fcvenlik uygulamalar\u0131 hakk\u0131nda da bilgi verdik.<\/p>\n<p>GraphQL, modern uygulama geli\u015ftiricilerine, veriye eri\u015fim konusunda benzersiz bir esneklik ve verimlilik sunar. Node.js&#8217;in h\u0131zl\u0131 geli\u015ftirme yetenekleri ve zengin paket ekosistemiyle birle\u015fti\u011finde, g\u00fc\u00e7l\u00fc ve \u00f6l\u00e7eklenebilir API&#8217;ler olu\u015fturmak i\u00e7in m\u00fckemmel bir kombinasyon olu\u015fturur. Bu rehber, kendi GraphQL API&#8217;nizi olu\u015fturmaya ba\u015flaman\u0131z i\u00e7in sa\u011flam bir temel sa\u011flamal\u0131d\u0131r. Daha fazla \u00f6\u011frenmek ve uygulaman\u0131z\u0131 geli\u015ftirmek i\u00e7in Apollo Client, GraphQL Federation ve daha geli\u015fmi\u015f performans optimizasyon tekniklerini ara\u015ft\u0131rmaya devam etmeniz \u00f6nerilir. GraphQL&#8217;in gelece\u011fi parlak ve Node.js ile birlikte, web geli\u015ftirme d\u00fcnyas\u0131nda \u00f6nemli bir rol oynamaya devam edecektir.<\/p>\n<p><\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Node.js&#8217;te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber\nModern web uygulamalar\u0131, veriye eri\u015fim ve veri manip\u00fclasyonu i\u00e7in g\u00fc\u00e7l\u00fc ve esne","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[136],"tags":[],"class_list":{"0":"post-34454","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-node-js","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Node.js&#039;te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Node.js&#039;te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber\" \/>\n<meta property=\"og:description\" content=\"Node.js&#039;te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber Modern web uygulamalar\u0131, veriye eri\u015fim ve veri manip\u00fclasyonu i\u00e7in g\u00fc\u00e7l\u00fc ve esne\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-11-16T19:41:00+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"21 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Node.js&#8217;te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber\",\"datePublished\":\"2025-11-16T19:41:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/\"},\"wordCount\":2396,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"Node.js\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/\",\"name\":\"Node.js'te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-11-16T19:41:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Node.js&#8217;te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Node.js'te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/","og_locale":"tr_TR","og_type":"article","og_title":"Node.js'te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber","og_description":"Node.js'te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber Modern web uygulamalar\u0131, veriye eri\u015fim ve veri manip\u00fclasyonu i\u00e7in g\u00fc\u00e7l\u00fc ve esne","og_url":"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-11-16T19:41:00+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"21 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Node.js&#8217;te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber","datePublished":"2025-11-16T19:41:00+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/"},"wordCount":2396,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["Node.js"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/","url":"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/","name":"Node.js'te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-11-16T19:41:00+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/node-jste-graphql-api-sunucusu-kurulumu-kapsamli-bir-rehber\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Node.js&#8217;te GraphQL API Sunucusu Kurulumu: Kapsaml\u0131 Bir Rehber"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/34454","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=34454"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/34454\/revisions"}],"predecessor-version":[{"id":34455,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/34454\/revisions\/34455"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=34454"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=34454"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=34454"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}