API Development Rehberi
Backend iletisim katmani için kapsamli rehber: REST, GraphQL, gRPC, WebSocket, kimlik doğrulama, dokumantasyon ve en iyi uygulamalar.
TIP
- ✅ Her backend proje -- API zorunlu
- ⚠️ Basit CRUD için REST yeterli
Önerilen: REST varsayılan + GraphQL karmasik veri + WebSocket real-time
1) REST API Temelleri
REST (Representational State Transfer), HTTP protokolu uzerine kurulu kaynak odakli bir mimaridir. Gunumuzde en yaygin API yaklasimidir.
1.1) URL Yapisi
Iyi tasarlanmis URL'ler API kullanilabilirligini dogrudan etkiler.
Temel kurallar:
- Küçük harf kullan
- Cogul isimler kullan (
users,products,orders) - Fiil degil isim kullan (kaynak odakli)
- Hiyerarsiyi yansit
- Dosya uzantisi kullanma
# Dogru
GET /api/v1/users
GET /api/v1/users/123
GET /api/v1/users/123/orders
GET /api/v1/users/123/orders/456
POST /api/v1/users
PUT /api/v1/users/123
DELETE /api/v1/users/123
# Yanlis
GET /api/v1/getUsers # fiil kullanma
GET /api/v1/user/123 # tekil kullanma
POST /api/v1/users/create # fiil ekleme
GET /api/v1/Users # buyuk harf kullanma1.2) HTTP Methods
| Method | Amac | Idempotent | Request Body | Örnek |
|---|---|---|---|---|
| GET | Kaynak oku | Evet | Hayir | GET /users/1 |
| POST | Kaynak oluştur | Hayir | Evet | POST /users |
| PUT | Tamamen güncelle | Evet | Evet | PUT /users/1 |
| PATCH | Kismi güncelle | Hayir | Evet | PATCH /users/1 |
| DELETE | Kaynak sil | Evet | Hayir | DELETE /users/1 |
| HEAD | Sadece header | Evet | Hayir | HEAD /users/1 |
| OPTIONS | Izin verilen methodlar | Evet | Hayir | OPTIONS /users |
1.3) HTTP Status Codes
| Kod | Anlam | Kullanım |
|---|---|---|
| 200 | OK | Basarili GET, PUT, PATCH |
| 201 | Created | Basarili POST |
| 204 | No Content | Basarili DELETE |
| 301 | Moved Permanently | Kalici yonlendirme |
| 304 | Not Modified | Cache gecerli |
| 400 | Bad Request | Gecersiz istek verisi |
| 401 | Unauthorized | Kimlik doğrulama gerekli |
| 403 | Forbidden | Yetki yetersiz |
| 404 | Not Found | Kaynak bulunamadi |
| 405 | Method Not Allowed | Desteklenmeyen HTTP method |
| 409 | Conflict | Kaynak catismasi |
| 410 | Gone | Kaynak kalici olarak silindi |
| 415 | Unsupported Media Type | Desteklenmeyen içerik tipi |
| 422 | Unprocessable Entity | Validasyon hatasi |
| 429 | Too Many Requests | Rate limit asildi |
| 500 | Internal Server Error | Sunucu hatasi |
| 502 | Bad Gateway | Upstream sunucu hatasi |
| 503 | Service Unavailable | Sunucu gecici olarak kulanilamaz |
| 504 | Gateway Timeout | Upstream sunucu zaman asimi |
1.4) Response Format
Tutarli bir response yapisi kullanmak istemci tarafini kolaylastirir.
// Basarili tekil yanit
{
"success": true,
"data": {
"id": 1,
"name": "Fahri",
"email": "fahri@example.com"
}
}
// Basarili liste yaniti
{
"success": true,
"data": [
{ "id": 1, "name": "Fahri" },
{ "id": 2, "name": "Ali" }
],
"meta": {
"page": 1,
"per_page": 20,
"total": 150,
"total_pages": 8
}
}
// Hata yaniti
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Gecersiz email adresi",
"details": [
{ "field": "email", "message": "Gecerli bir email giriniz" }
]
}
}1.5) Pagination
| Yöntem | Avantaj | Dezavantaj | Kullanım Alani |
|---|---|---|---|
| Offset-based | Basit, herhangi sayfaya atla | Büyük offset'lerde yavas, veri kaymasi | Admin panelleri, küçük veri |
| Cursor-based | Performansli, tutarli sonuclar | Rastgele sayfaya atlanamaz | Feed, sonsuz scroll |
| Keyset-based | Cok performansli | Karmasik siralama zorlu | Büyük veri setleri |
# Offset-based
GET /api/v1/users?page=2&per_page=20
# Cursor-based
GET /api/v1/users?cursor=eyJpZCI6MTAwfQ&limit=20
# Keyset-based
GET /api/v1/users?after_id=100&limit=20Node.js Offset Ornegi:
app.get('/api/v1/users', async (req, res) => {
const page = parseInt(req.query.page) || 1;
const perPage = Math.min(parseInt(req.query.per_page) || 20, 100);
const offset = (page - 1) * perPage;
const [users, total] = await Promise.all([
db.query('SELECT * FROM users LIMIT ? OFFSET ?', [perPage, offset]),
db.query('SELECT COUNT(*) as count FROM users')
]);
res.json({
success: true,
data: users,
meta: { page, per_page: perPage, total: total[0].count, total_pages: Math.ceil(total[0].count / perPage) }
});
});1.6) Filtering ve Sorting
# Filtreleme
GET /api/v1/users?status=active&role=admin
GET /api/v1/products?price_min=100&price_max=500&category=electronics
# Siralama
GET /api/v1/users?sort=created_at&order=desc
GET /api/v1/products?sort=-price,name # - isareti desc
# Alan secimi (sparse fieldsets)
GET /api/v1/users?fields=id,name,email
# Arama
GET /api/v1/users?search=fahri1.7) Versiyonlama
| Yöntem | Örnek | Avantaj | Dezavantaj |
|---|---|---|---|
| URL path | /api/v1/users | Acik, basit | URL kirlilik |
| Query string | /api/users?version=1 | Kolay gecis | Gozden kacabilir |
| Header | Accept: application/vnd.api.v1+json | Temiz URL | Debug zor |
| Content-Type | Content-Type: application/vnd.api.v1+json | Standart | Karmasik |
URL path yontemi en yaygin ve önerilen yaklasimdir.
2) GraphQL
GraphQL, Facebook tarafindan gelistirilen bir sorgu dilidir. Istemci tam olarak hangi verileri istedigini belirtir.
2.1) Schema Tanimlama
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
createdAt: String!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
}
type Query {
user(id: ID!): User
users(page: Int, limit: Int): [User!]!
post(id: ID!): Post
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User!
deleteUser(id: ID!): Boolean!
}
input CreateUserInput {
name: String!
email: String!
password: String!
}
input UpdateUserInput {
name: String
email: String
}2.2) Query ve Mutation
# Query -- veri cekme
query {
user(id: "1") {
name
email
posts {
title
content
}
}
}
# Mutation -- veri degistirme
mutation {
createUser(input: {
name: "Fahri"
email: "fahri@example.com"
password: "guvenli123"
}) {
id
name
}
}
# Degiskenli query
query GetUser($id: ID!) {
user(id: $id) {
name
email
}
}2.3) N+1 Problemi ve DataLoader
GraphQL'in en büyük performans tuzagi N+1 sorgusudur. Bunu DataLoader ile cozersiniz.
const DataLoader = require('dataloader');
const userLoader = new DataLoader(async (userIds) => {
const users = await db.query(
'SELECT * FROM users WHERE id IN (?)', [userIds]
);
return userIds.map(id => users.find(u => u.id === id));
});
const resolvers = {
Post: {
author: (post) => userLoader.load(post.authorId)
}
};2.4) REST vs GraphQL
| Özellik | REST | GraphQL |
|---|---|---|
| Veri cekme | Sabit endpoint'ler | Istemci belirler |
| Over-fetching | Sik yasanir | Yok |
| Under-fetching | Birden fazla istek gerekir | Tek istekte cozulur |
| Cache | HTTP cache kolay | Ozel cache gerekir |
| Dosya yükleme | Kolay | Ek kütüphane gerekir |
| Öğrenme egrisi | Düşük | Orta-yüksek |
| Hata yönetimi | HTTP status codes | 200 + errors dizisi |
| Real-time | Yok (SSE/WS ayri) | Subscription destegi |
| Dokumantasyon | Swagger/OpenAPI | Introspection + Playground |
| Versiyonlama | URL/header ile | Schema evolution |
3) gRPC
gRPC, Google tarafindan gelistirilen yüksek performansli RPC framework'udur. Protocol Buffers (protobuf) kullanir, HTTP/2 uzerinde çalışır.
// user.proto
syntax = "proto3";
package user;
service UserService {
rpc GetUser (GetUserRequest) returns (UserResponse);
rpc ListUsers (ListUsersRequest) returns (stream UserResponse);
rpc CreateUser (CreateUserRequest) returns (UserResponse);
}
message GetUserRequest {
string id = 1;
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
message UserResponse {
string id = 1;
string name = 2;
string email = 3;
}
message ListUsersRequest {
int32 page = 1;
int32 limit = 2;
}Ne zaman gRPC kullanilir:
- Microservice'ler arasi iletisim (düşük latency)
- Büyük veri aktarimi (streaming)
- Polyglot ortamlar (farkli dillerdeki servisler arasi)
- Mobil istemciler (düşük bant genisligi)
Ne zaman kullanilmaz:
- Browser istemciler (dogrudan destek sınırlı, gRPC-Web gerekir)
- Basit CRUD API'ler
- Hızlı prototipleme
4) WebSocket
WebSocket, istemci ve sunucu arasinda kalici, cift yonlu iletisim sağlar. HTTP'den farkli olarak bağlantı bir kez kurulur ve acik kalir.
4.1) Socket.io ile WebSocket
// Sunucu
const { Server } = require('socket.io');
const io = new Server(3001, {
cors: { origin: '*' }
});
io.on('connection', (socket) => {
console.log('Kullanici baglandi:', socket.id);
// Odaya katilma
socket.on('join-room', (roomId) => {
socket.join(roomId);
socket.to(roomId).emit('user-joined', { userId: socket.id });
});
// Mesaj gonderme
socket.on('send-message', (data) => {
io.to(data.roomId).emit('new-message', {
from: socket.id,
message: data.message,
timestamp: Date.now()
});
});
// Yazma bildirimi
socket.on('typing', (data) => {
socket.to(data.roomId).emit('user-typing', { userId: socket.id });
});
socket.on('disconnect', () => {
console.log('Kullanici ayrildi:', socket.id);
});
});
// Istemci
import { io } from 'socket.io-client';
const socket = io('http://localhost:3001');
socket.on('connect', () => {
socket.emit('join-room', 'room-1');
});
socket.on('new-message', (data) => {
console.log('Yeni mesaj:', data.message);
});
socket.emit('send-message', {
roomId: 'room-1',
message: 'Merhaba!'
});4.2) Ne Zaman WebSocket Kullanilir
| Senaryo | WebSocket | REST + Polling | SSE |
|---|---|---|---|
| Chat uygulamasi | Evet | Hayir | Kismi |
| Canli bildirimler | Evet | Mumkun | Evet |
| Canli dashboard | Evet | Mumkun | Evet |
| Oyun | Evet | Hayir | Hayir |
| Dosya yükleme durumu | Hayir | Evet | Evet |
| Form gonderme | Hayir | Evet | Hayir |
5) Authentication
5.1) API Key
En basit kimlik doğrulama yontemidir. Genellikle server-to-server iletisimde kullanilir.
// Middleware
function apiKeyAuth(req, res, next) {
const apiKey = req.headers['x-api-key'];
if (!apiKey || apiKey !== process.env.API_KEY) {
return res.status(401).json({ error: 'Gecersiz API anahtari' });
}
next();
}
app.use('/api', apiKeyAuth);# Kullanim
curl -H "X-API-Key: abc123secret" https://api.example.com/data5.2) JWT (JSON Web Token)
JWT, stateless kimlik doğrulama için standarttir. Uclu yapiya sahiptir: Header.Payload.Signature.
const jwt = require('jsonwebtoken');
// Token olusturma
function generateTokens(user) {
const accessToken = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '15m' }
);
const refreshToken = jwt.sign(
{ userId: user.id },
process.env.JWT_REFRESH_SECRET,
{ expiresIn: '7d' }
);
return { accessToken, refreshToken };
}
// Token dogrulama middleware
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (!token) return res.status(401).json({ error: 'Token gerekli' });
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) return res.status(403).json({ error: 'Gecersiz token' });
req.user = decoded;
next();
});
}
// Login endpoint
app.post('/api/auth/login', async (req, res) => {
const { email, password } = req.body;
const user = await db.findUserByEmail(email);
if (!user || !await bcrypt.compare(password, user.password)) {
return res.status(401).json({ error: 'Gecersiz kimlik bilgileri' });
}
const tokens = generateTokens(user);
res.json({ success: true, data: tokens });
});
// Refresh endpoint
app.post('/api/auth/refresh', async (req, res) => {
const { refreshToken } = req.body;
try {
const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);
const user = await db.findUserById(decoded.userId);
const tokens = generateTokens(user);
res.json({ success: true, data: tokens });
} catch (err) {
res.status(403).json({ error: 'Gecersiz refresh token' });
}
});5.3) OAuth 2.0
OAuth 2.0, ucuncu parti uygulamalara sınırlı erisim vermek için kullanilan bir yetkilendirme framework'udur.
+--------+ +---------------+
| |-- (1) Authorization Request -->| Resource |
| | | Owner |
| |<-- (2) Authorization Grant ----| |
| | +---------------+
| Client |
| |-- (3) Authorization Grant ---->+---------------+
| | | Authorization |
| |<-- (4) Access Token -----------| Server |
| | +---------------+
| |
| |-- (5) Access Token ---------->+---------------+
| | | Resource |
| |<-- (6) Protected Resource ----| Server |
+--------+ +---------------+// Google OAuth ornegi (Passport.js)
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback'
}, async (accessToken, refreshToken, profile, done) => {
let user = await db.findUserByGoogleId(profile.id);
if (!user) {
user = await db.createUser({
googleId: profile.id,
name: profile.displayName,
email: profile.emails[0].value
});
}
done(null, user);
}));
app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
app.get('/auth/google/callback', passport.authenticate('google'), (req, res) => {
const tokens = generateTokens(req.user);
res.redirect(`/dashboard?token=${tokens.accessToken}`);
});6) Rate Limiting
Rate limiting, API'yi asiri kullanimdan ve kotuye kullanimdan korur.
Algoritma Karsilastirmasi
| Algoritma | Nasil Calisir | Avantaj | Dezavantaj |
|---|---|---|---|
| Fixed Window | Sabit zaman diliminde sayac tutar | Basit | Pencere sinirinda patlama |
| Sliding Window | Kayan pencere ile ortalama hesaplar | Daha adil | Daha fazla bellek |
| Token Bucket | Sabit hizda token eklenir, istekte harcanir | Burst'e izin verir | Karmasik |
| Leaky Bucket | Sabit hizda istek islenir, fazlasi kuyruga | Duz trafik | Gecikme olusabilir |
// express-rate-limit ile basit uygulama
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 dakika
max: 100, // pencere basina 100 istek
standardHeaders: true,
legacyHeaders: false,
message: {
success: false,
error: { code: 'RATE_LIMIT', message: 'Cok fazla istek, lutfen bekleyin' }
}
});
// Genel limiter
app.use('/api', limiter);
// Endpoint bazli limiter
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5,
message: { error: 'Cok fazla giris denemesi' }
});
app.use('/api/auth/login', authLimiter);7) API Documentation
7.1) OpenAPI / Swagger
OpenAPI (eski adiyla Swagger), REST API'ler için standart dokumantasyon formatdir.
# openapi.yaml
openapi: 3.0.3
info:
title: User API
version: 1.0.0
description: Kullanici yonetimi API'si
servers:
- url: https://api.example.com/v1
paths:
/users:
get:
summary: Kullanicilari listele
tags: [Users]
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: per_page
in: query
schema:
type: integer
default: 20
responses:
'200':
description: Basarili
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
data:
type: array
items:
$ref: '#/components/schemas/User'
post:
summary: Yeni kullanici olustur
tags: [Users]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUser'
responses:
'201':
description: Olusturuldu
'400':
description: Gecersiz veri
components:
schemas:
User:
type: object
properties:
id:
type: integer
name:
type: string
email:
type: string
format: email
CreateUser:
type: object
required: [name, email, password]
properties:
name:
type: string
email:
type: string
password:
type: string
minLength: 8
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT// Express ile Swagger UI
const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
const spec = YAML.load('./openapi.yaml');
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(spec));7.2) Postman Collection
Postman collection'lari JSON formatinda disari aktarilabilir ve ekiple paylasilabilir. newman CLI araci ile CI/CD pipeline'ina entegre edilebilir.
# Newman ile Postman collection calistirma
npm install -g newman
newman run collection.json -e environment.json --reporters cli,html8) API Testing
8.1) curl ile Test
# GET
curl -s http://localhost:3000/api/users | jq
# POST
curl -X POST http://localhost:3000/api/users \
-H "Content-Type: application/json" \
-d '{"name": "Fahri", "email": "fahri@example.com"}'
# PUT
curl -X PUT http://localhost:3000/api/users/1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGc..." \
-d '{"name": "Fahri Aydin"}'
# DELETE
curl -X DELETE http://localhost:3000/api/users/1 \
-H "Authorization: Bearer eyJhbGc..."
# Detayli cikti
curl -v http://localhost:3000/api/users
# Sadece header
curl -I http://localhost:3000/api/users8.2) Supertest ile Entegrasyon Testi
const request = require('supertest');
const app = require('../app');
describe('User API', () => {
let token;
let userId;
beforeAll(async () => {
const res = await request(app)
.post('/api/auth/login')
.send({ email: 'test@test.com', password: 'test123' });
token = res.body.data.accessToken;
});
test('GET /api/users -- kullanicilari listeler', async () => {
const res = await request(app)
.get('/api/users')
.set('Authorization', `Bearer ${token}`)
.expect(200);
expect(res.body.success).toBe(true);
expect(Array.isArray(res.body.data)).toBe(true);
});
test('POST /api/users -- yeni kullanici olusturur', async () => {
const res = await request(app)
.post('/api/users')
.set('Authorization', `Bearer ${token}`)
.send({ name: 'Test User', email: 'new@test.com', password: 'pass1234' })
.expect(201);
expect(res.body.data).toHaveProperty('id');
userId = res.body.data.id;
});
test('GET /api/users/:id -- tek kullanici getirir', async () => {
const res = await request(app)
.get(`/api/users/${userId}`)
.set('Authorization', `Bearer ${token}`)
.expect(200);
expect(res.body.data.name).toBe('Test User');
});
test('PUT /api/users/:id -- kullaniciyi gunceller', async () => {
const res = await request(app)
.put(`/api/users/${userId}`)
.set('Authorization', `Bearer ${token}`)
.send({ name: 'Updated User' })
.expect(200);
expect(res.body.data.name).toBe('Updated User');
});
test('DELETE /api/users/:id -- kullaniciyi siler', async () => {
await request(app)
.delete(`/api/users/${userId}`)
.set('Authorization', `Bearer ${token}`)
.expect(204);
});
test('POST /api/users -- validasyon hatasi', async () => {
const res = await request(app)
.post('/api/users')
.set('Authorization', `Bearer ${token}`)
.send({ name: '' })
.expect(400);
expect(res.body.success).toBe(false);
});
});9) CORS (Cross-Origin Resource Sharing)
CORS, tarayicilarin farkli origin'lerden API istegi yapmasini kontrol eder.
const cors = require('cors');
// Herkese acik (gelistirme ortami)
app.use(cors());
// Production ayarlari
app.use(cors({
origin: ['https://app.example.com', 'https://admin.example.com'],
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
maxAge: 86400 // preflight cache suresi (saniye)
}));Tarayici, basit olmayan istekler için once bir OPTIONS preflight istegi gonderir. Sunucu uygun CORS header'larini donmezse istek engellenir.
10) Webhook
Webhook, bir olay gerceklestiginde sunucunun baska bir sunucuya HTTP istegi gondermesidir. Polling yerine push modeli kullanir.
// Webhook gonderme
async function sendWebhook(url, event, data) {
const payload = JSON.stringify({ event, data, timestamp: Date.now() });
const signature = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(payload)
.digest('hex');
await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Webhook-Signature': signature
},
body: payload
});
}
// Ornek: Siparis olusturulunca webhook tetikle
app.post('/api/orders', async (req, res) => {
const order = await db.createOrder(req.body);
await sendWebhook(
'https://partner.example.com/webhooks/orders',
'order.created',
order
);
res.status(201).json({ success: true, data: order });
});
// Webhook alma ve dogrulama
app.post('/webhooks/incoming', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const expectedSig = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
if (signature !== expectedSig) {
return res.status(401).json({ error: 'Gecersiz imza' });
}
// Olaya gore islem yap
const { event, data } = req.body;
switch (event) {
case 'payment.completed':
handlePaymentCompleted(data);
break;
case 'order.shipped':
handleOrderShipped(data);
break;
}
res.status(200).json({ received: true });
});11) Error Handling
Merkezi hata yönetimi, tutarli hata yanitlari sağlar.
// Ozel hata sinifi
class AppError extends Error {
constructor(statusCode, code, message) {
super(message);
this.statusCode = statusCode;
this.code = code;
}
}
class NotFoundError extends AppError {
constructor(resource = 'Kaynak') {
super(404, 'NOT_FOUND', `${resource} bulunamadi`);
}
}
class ValidationError extends AppError {
constructor(details) {
super(400, 'VALIDATION_ERROR', 'Validasyon hatasi');
this.details = details;
}
}
// Merkezi hata middleware'i
app.use((err, req, res, next) => {
console.error(`[${new Date().toISOString()}] ${err.stack}`);
if (err instanceof AppError) {
return res.status(err.statusCode).json({
success: false,
error: {
code: err.code,
message: err.message,
...(err.details && { details: err.details })
}
});
}
// Beklenmeyen hatalar
res.status(500).json({
success: false,
error: {
code: 'INTERNAL_ERROR',
message: process.env.NODE_ENV === 'production'
? 'Sunucu hatasi'
: err.message
}
});
});
// Kullanim
app.get('/api/users/:id', async (req, res, next) => {
try {
const user = await db.findUserById(req.params.id);
if (!user) throw new NotFoundError('Kullanici');
res.json({ success: true, data: user });
} catch (err) {
next(err);
}
});12) Pratik İpuçları
Tasarim:
- RESTful URL yapisini tutarli kullan
- Her endpoint tek bir is yapsin
- Response formatini standartlastir
- Pagination'i ilk gunden ekle
- Versiyonlamayi ihmal etme
Güvenlik:
- HTTPS zorunlu kullan
- Rate limiting mutlaka ekle
- Input validasyonu yap (joi, zod, class-validator)
- SQL injection ve XSS korumalari sagla
- Hassas verileri log'lama
- CORS'u production'da daralt
Performans:
- Gereksiz veri dondurme (sparse fieldsets)
- Uygun yerlerde cache kullan (Redis, HTTP cache)
- Büyük payload'lari sikiştir (gzip, brotli)
- Connection pooling kullan
- N+1 sorgularindan kacin
Dokumantasyon:
- OpenAPI/Swagger ile canli dokumantasyon tut
- Her endpoint için örnek request/response ekle
- Hata kodlarini belgele
- Postman collection paylas
Ilgili Rehberler
Backend
- Backend Genel Bakış
- Yazilim Mimarisi
- Laravel Rehberi
- ASP.NET Core Guide
- Node.js Rehberi
- Python Rehberi
- AI & LLM