API tasarımında 2015''ten beri süren bir tartışma: GraphQL mi, REST mi? Her ikisi de zengin production deneyimine sahip; fark felsefelerinde. Bu yazı iki yaklaşımı net kriterlerle karşılaştırır ve hangi senaryoda hangisinin daha uygun olduğunu gösterir.
Temel Fark
İlgili rehberler: REST API güvenlik · API rate limiting · KEYDAL API geliştirme hizmetleri
REST: Kaynak-odaklı (/users/42, /users/42/orders), HTTP verb''leri (GET/POST/PUT/DELETE), her endpoint sabit response shape. GraphQL: Query dili — client hangi alanları istediğini söyler, sunucu tam olarak onu döner. Tek endpoint (/graphql), POST ile query gönderilir.
# REST
GET /users/42
→ { id, name, email, phone, address, createdAt, ... }
GET /users/42/orders
→ [{ id, total, items, createdAt }, ...]
# GraphQL
POST /graphql
query {
user(id: 42) {
name
email
orders(last: 10) {
id
total
}
}
}
→ { data: { user: { name, email, orders: [...] } } }
GraphQL Avantajları
- Over-fetching yok: Mobil uygulamada sadece
nameveavatarlazım, 50 alanlı user object inmez - Under-fetching yok: Tek istekte kullanıcı + orders + items al, 3 ayrı REST çağrısına gerek yok
- Strongly-typed schema: SDL (Schema Definition Language) ile tip güvenliği
- Tooling: Apollo Studio, GraphiQL — auto-complete, docs otomatik
- Subscription: Real-time güncellemeler WebSocket üzerinden
GraphQL Dezavantajları
- Caching zor: Tek endpoint, POST — HTTP cache çalışmaz, client-side cache gerekir
- N+1 problemi: Naive resolver yazımı DB''yi bombalar — DataLoader şart
- Complexity: Schema, resolver, data source — REST''ten fazla moving parts
- Monitoring zor: Tek endpoint''te 1000 farklı sorgu — route-based metric yok
- Sorgu maliyeti kontrolsüz: Kötü niyetli deeply-nested query server''ı çökertir
REST Avantajları
- Basit: Her developer bilir, öğrenme eğrisi düşük
- HTTP semantics: Status code, method, header — yerleşik
- Caching kolay:
Cache-Control, CDN, browser cache çalışır - Tool ecosystem: curl, Postman, OpenAPI, SDK generator
- Versioning kolay:
/v1/users,/v2/users
N+1 Problemi ve DataLoader
// Naive resolver — N+1
const resolvers = {
Post: {
author: (post) => db.users.findByPk(post.authorId)
}
};
// 100 post listeleyince 100 ayrı user query → DB çöker
// DataLoader ile batch + cache
const DataLoader = require('dataloader');
const userLoader = new DataLoader(async (ids) => {
const users = await db.users.findAll({ where: { id: ids } });
return ids.map(id => users.find(u => u.id === id));
});
const resolvers = {
Post: {
author: (post) => userLoader.load(post.authorId)
}
};
// 100 post → tek DB query (WHERE id IN [...])
Schema Tasarımı (SDL)
type User {
id: ID!
email: String!
name: String
posts(limit: Int = 10, after: ID): PostConnection!
role: Role!
}
enum Role { USER ADMIN MODERATOR }
type Post {
id: ID!
title: String!
content: String!
author: User!
createdAt: DateTime!
}
type PostConnection {
edges: [PostEdge!]!
pageInfo: PageInfo!
}
type PostEdge {
node: Post!
cursor: String!
}
type Query {
me: User
user(id: ID!): User
posts(limit: Int = 10): [Post!]!
}
type Mutation {
createPost(input: CreatePostInput!): Post!
deletePost(id: ID!): Boolean!
}
input CreatePostInput {
title: String!
content: String!
}
Sorgu Maliyeti Kontrolü
// Query depth limit
const depthLimit = require('graphql-depth-limit');
const server = new ApolloServer({
typeDefs, resolvers,
validationRules: [depthLimit(5)] // max 5 seviye derinlik
});
// Query complexity
const { createComplexityLimitRule } = require('graphql-validation-complexity');
validationRules: [createComplexityLimitRule(1000)];
// Persisted queries — sadece whitelist'teki query'ler kabul
const persistedQueries = { 'abc123': 'query { me { id } }' };
Ne Zaman Hangisi?
GraphQL seçin:
- Mobil app + web app aynı backend''den farklı veri istiyor
- Çok sayıda nested resource: user → orders → items → products → reviews
- Frontend ekibi büyük: Kendi query''lerini yazsınlar, backend değişmesin
- Real-time: subscription feature
- BFF (backend-for-frontend) deseninde
REST seçin:
- Public API: 3. parti entegratorlara sunulan — REST evrensel
- Simple CRUD: Admin panel, dashboard — GraphQL overkill
- CDN caching kritik: Public içerik, yüksek trafik
- Microservices arası: Servis servise REST/gRPC daha iyi
- Ekibin deneyimi REST''te
Hibrit Yaklaşım
Çoğu modern uygulama ikisini birlikte kullanır: GraphQL client-facing API için, REST/gRPC mikroservis iç iletişimi için. BFF pattern''inde GraphQL gateway arkadaki REST servisleri çağırır.
Alternatif: tRPC
TypeScript monorepo''larda GraphQL''in getirdiği complexity''yi istemeyip REST''in esnekliğini arıyorsanız tRPC''ye bakın. Schema yok — TypeScript tipleri end-to-end type safety sağlar. Apollo''nun light rakibi.
API Tasarım Prensipleri ve Güvenli Endpoint Mimarisi
Profesyonel API tasarımı dört unsuru bir araya getirir: doğru protokol seçimi (REST CRUD için ideal, GraphQL flexible queries için, gRPC microservice-to-microservice için), kimlik doğrulama (OAuth 2.0 / OIDC, JWT access token, refresh token rotation), rate limiting (token bucket, sliding window, IP/user/API key bazlı) ve versiyonlama (URL versiyon /v1/, header versiyon, deprecation sürecleri). API endpoint güvenliği için input validation, prepared statement, CORS politikası, idempotency-key (POST için), webhook signature verification ve OpenAPI/Swagger dokümantasyonu modern standartlardır. Yüksek trafikli API'lerde Redis ile rate limit + cache, Kafka veya RabbitMQ ile asenkron iş kuyruğu, OpenTelemetry ile dağıtık izleme önerilir.
GraphQL, REST veya tRPC seçimi ve API mimarisi için iletişime geçin