Türkçe

Farklı bir küresel kitleye hizmet veren sağlam ve sürdürülebilir API'ler oluşturmak için ölçeklenebilir GraphQL şema tasarım desenlerini öğrenin. Şema birleştirme, federasyon ve modülerleştirmede ustalaşın.

GraphQL Şema Tasarımı: Küresel API'ler için Ölçeklenebilir Desenler

GraphQL, istemcilere tam olarak ihtiyaç duydukları veriyi talep etme esnekliği sunarak geleneksel REST API'lerine güçlü bir alternatif olarak ortaya çıkmıştır. Ancak, GraphQL API'niz karmaşıklık ve kapsam açısından büyüdükçe – özellikle farklı veri gereksinimleri olan küresel bir kitleye hizmet verirken – dikkatli bir şema tasarımı sürdürülebilirlik, ölçeklenebilirlik ve performans için hayati önem taşır. Bu makale, küresel bir uygulamanın taleplerini karşılayabilecek sağlam API'ler oluşturmanıza yardımcı olacak birkaç ölçeklenebilir GraphQL şema tasarım desenini incelemektedir.

Ölçeklenebilir Şema Tasarımının Önemi

İyi tasarlanmış bir GraphQL şeması, başarılı bir API'nin temelidir. İstemcilerin verilerinizle ve servislerinizle nasıl etkileşim kurabileceğini belirler. Kötü şema tasarımı, aşağıdakiler de dahil olmak üzere bir dizi soruna yol açabilir:

Küresel uygulamalar için bu sorunlar daha da artar. Farklı bölgelerin farklı veri gereksinimleri, düzenleyici kısıtlamaları ve performans beklentileri olabilir. Ölçeklenebilir bir şema tasarımı, bu zorlukları etkili bir şekilde ele almanızı sağlar.

Ölçeklenebilir Şema Tasarımının Temel İlkeleri

Belirli desenlere dalmadan önce, şema tasarımınıza rehberlik etmesi gereken bazı temel ilkeleri özetleyelim:

Ölçeklenebilir Şema Tasarım Desenleri

Sağlam GraphQL API'leri oluşturmak için kullanabileceğiniz birkaç ölçeklenebilir şema tasarım deseni aşağıda verilmiştir:

1. Şema Birleştirme (Schema Stitching)

Şema birleştirme, birden çok GraphQL API'sini tek, birleşik bir şemada birleştirmenize olanak tanır. Bu, verilerinizin farklı bölümlerinden sorumlu farklı ekipleriniz veya servisleriniz olduğunda özellikle kullanışlıdır. Bu, birkaç mini API'ye sahip olmak ve bunları bir 'ağ geçidi' (gateway) API aracılığıyla birbirine bağlamak gibidir.

Nasıl çalışır:

  1. Her ekip veya servis, kendi şemasıyla kendi GraphQL API'sini sunar.
  2. Merkezi bir ağ geçidi servisi, bu şemaları tek, birleşik bir şemada birleştirmek için şema birleştirme araçlarını (Apollo Federation veya GraphQL Mesh gibi) kullanır.
  3. İstemciler, istekleri uygun alttaki API'lere yönlendiren ağ geçidi servisiyle etkileşime girer.

Örnek:

Ürünler, kullanıcılar ve siparişler için ayrı API'lere sahip bir e-ticaret platformu hayal edin. Her API'nin kendi şeması vardır:

  
    # Ürünler API'si
    type Product {
      id: ID!
      name: String!
      price: Float!
    }

    type Query {
      product(id: ID!): Product
    }

    # Kullanıcılar API'si
    type User {
      id: ID!
      name: String!
      email: String!
    }

    type Query {
      user(id: ID!): User
    }

    # Siparişler API'si
    type Order {
      id: ID!
      userId: ID!
      productId: ID!
      quantity: Int!
    }

    type Query {
      order(id: ID!): Order
    }
  

Ağ geçidi servisi, bu şemaları birleştirerek birleşik bir şema oluşturabilir:

  
    type Product {
      id: ID!
      name: String!
      price: Float!
    }

    type User {
      id: ID!
      name: String!
      email: String!
    }

    type Order {
      id: ID!
      user: User! @relation(field: "userId")
      product: Product! @relation(field: "productId")
      quantity: Int!
    }

    type Query {
      product(id: ID!): Product
      user(id: ID!): User
      order(id: ID!): Order
    }
  

Order türünün, bu türler ayrı API'lerde tanımlanmış olmasına rağmen artık User ve Product'a referanslar içerdiğine dikkat edin. Bu, şema birleştirme direktifleri (bu örnekte @relation gibi) aracılığıyla sağlanır.

Faydaları:

Dikkat edilmesi gerekenler:

2. Şema Federasyonu (Schema Federation)

Şema federasyonu, şema birleştirmenin bazı sınırlamalarını gidermek için tasarlanmış bir evrimidir. GraphQL şemalarını birleştirmek için daha bildirimsel (declarative) ve standartlaştırılmış bir yaklaşım sunar.

Nasıl çalışır:

  1. Her servis bir GraphQL API'si sunar ve şemasını federasyon direktifleriyle (ör. @key, @extends, @external) işaretler.
  2. Merkezi bir ağ geçidi servisi (Apollo Federation kullanarak), tüm federe şemanın bir temsilini – bir süper-grafik (supergraph) – oluşturmak için bu direktifleri kullanır.
  3. Ağ geçidi servisi, istekleri uygun alttaki servislere yönlendirmek ve bağımlılıkları çözmek için süper-grafiği kullanır.

Örnek:

Aynı e-ticaret örneğini kullanarak, federe şemalar şöyle görünebilir:

  
    # Ürünler API'si
    type Product @key(fields: "id") {
      id: ID!
      name: String!
      price: Float!
    }

    type Query {
      product(id: ID!): Product
    }

    # Kullanıcılar API'si
    type User @key(fields: "id") {
      id: ID!
      name: String!
      email: String!
    }

    type Query {
      user(id: ID!): User
    }

    # Siparişler API'si
    type Order {
      id: ID!
      userId: ID!
      productId: ID!
      quantity: Int!
      user: User! @requires(fields: "userId")
      product: Product! @requires(fields: "productId")
    }

    extend type Query {
      order(id: ID!): Order
    }
  

Federasyon direktiflerinin kullanımına dikkat edin:

Faydaları:

Dikkat edilmesi gerekenler:

3. Modüler Şema Tasarımı

Modüler şema tasarımı, büyük, monolitik bir şemayı daha küçük, daha yönetilebilir modüllere ayırmayı içerir. Bu, federe şemalara başvurmadan bile API'nizin tek tek parçalarını anlamayı, değiştirmeyi ve yeniden kullanmayı kolaylaştırır.

Nasıl çalışır:

  1. Şemanızdaki mantıksal sınırları belirleyin (ör. kullanıcılar, ürünler, siparişler).
  2. Her sınır için ayrı modüller oluşturun ve o sınırla ilgili türleri, sorguları ve mutasyonları tanımlayın.
  3. Modülleri tek, birleşik bir şemada birleştirmek için içe/dışa aktarma mekanizmalarını (GraphQL sunucu uygulamanıza bağlı olarak) kullanın.

Örnek (JavaScript/Node.js kullanarak):

Her modül için ayrı dosyalar oluşturun:

  
    // kullanicilar.graphql
    type User {
      id: ID!
      name: String!
      email: String!
    }

    type Query {
      user(id: ID!): User
    }

    // urunler.graphql
    type Product {
      id: ID!
      name: String!
      price: Float!
    }

    type Query {
      product(id: ID!): Product
    }
  

Ardından, bunları ana şema dosyanızda birleştirin:

  
    // sema.js
    const { makeExecutableSchema } = require('graphql-tools');
    const { typeDefs: userTypeDefs, resolvers: userResolvers } = require('./users');
    const { typeDefs: productTypeDefs, resolvers: productResolvers } = require('./products');

    const typeDefs = [
      userTypeDefs,
      productTypeDefs,
      ""
    ];

    const resolvers = {
      Query: {
        ...userResolvers.Query,
        ...productResolvers.Query,
      }
    };

    const schema = makeExecutableSchema({
      typeDefs,
      resolvers,
    });

    module.exports = schema;
  

Faydaları:

Dikkat edilmesi gerekenler:

4. Arayüz (Interface) ve Birleşim (Union) Tipleri

Arayüz ve birleşim tipleri, birden çok somut tür tarafından uygulanabilen soyut tipler tanımlamanıza olanak tanır. Bu, polimorfik verileri – bağlama göre farklı biçimler alabilen verileri – temsil etmek için kullanışlıdır.

Nasıl çalışır:

Örnek:

  
    interface Node {
      id: ID!
    }

    type User implements Node {
      id: ID!
      name: String!
      email: String!
    }

    type Product implements Node {
      id: ID!
      name: String!
      price: Float!
    }

    union SearchResult = User | Product

    type Query {
      node(id: ID!): Node
      search(query: String!): [SearchResult!]!
    }
  

Bu örnekte, hem User hem de Product, ortak bir id alanı tanımlayan Node arayüzünü uygular. SearchResult birleşim türü, bir User veya bir Product olabilen bir arama sonucunu temsil eder. İstemciler, `search` alanını sorgulayabilir ve ardından aldıkları sonucun türünü belirlemek için `__typename` alanını kullanabilirler.

Faydaları:

Dikkat edilmesi gerekenler:

5. Bağlantı Deseni (Connection Pattern)

Bağlantı deseni, GraphQL API'lerinde sayfalama (pagination) uygulamak için standart bir yoldur. Büyük veri listelerini parçalar halinde almak için tutarlı ve verimli bir yol sağlar.

Nasıl çalışır:

Örnek:

  
    type User {
      id: ID!
      name: String!
      email: String!
    }

    type UserEdge {
      node: User!
      cursor: String!
    }

    type UserConnection {
      edges: [UserEdge!]!
      pageInfo: PageInfo!
    }

    type PageInfo {
      hasNextPage: Boolean!
      hasPreviousPage: Boolean!
      startCursor: String
      endCursor: String
    }

    type Query {
      users(first: Int, after: String, last: Int, before: String): UserConnection!
    }
  

Faydaları:

Dikkat edilmesi gerekenler:

Küresel Hususlar

Küresel bir kitle için bir GraphQL şeması tasarlarken, şu ek faktörleri göz önünde bulundurun:

Örneğin, bir ürün açıklaması alanını düşünün:


type Product {
 id: ID!
 name: String!
 description(language: String = "en"): String!
}

Bu, istemcilerin açıklamayı belirli bir dilde talep etmelerini sağlar. Dil belirtilmezse, varsayılan olarak İngilizce (`en`) kullanılır.

Sonuç

Ölçeklenebilir şema tasarımı, küresel bir uygulamanın taleplerini karşılayabilecek sağlam ve sürdürülebilir GraphQL API'leri oluşturmak için esastır. Bu makalede özetlenen ilkelere uyarak ve uygun tasarım desenlerini kullanarak, anlaşılması, değiştirilmesi ve genişletilmesi kolay, aynı zamanda mükemmel performans ve ölçeklenebilirlik sağlayan API'ler oluşturabilirsiniz. Şemanızı modülerleştirmeyi, birleştirmeyi ve soyutlamayı ve küresel kitlenizin özel ihtiyaçlarını göz önünde bulundurmayı unutmayın.

Bu desenleri benimseyerek, GraphQL'in tüm potansiyelini ortaya çıkarabilir ve uygulamalarınızı gelecek yıllar boyunca güçlendirebilecek API'ler oluşturabilirsiniz.