Skip to content

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 kullanma

1.2) HTTP Methods

MethodAmacIdempotentRequest BodyÖrnek
GETKaynak okuEvetHayirGET /users/1
POSTKaynak oluşturHayirEvetPOST /users
PUTTamamen güncelleEvetEvetPUT /users/1
PATCHKismi güncelleHayirEvetPATCH /users/1
DELETEKaynak silEvetHayirDELETE /users/1
HEADSadece headerEvetHayirHEAD /users/1
OPTIONSIzin verilen methodlarEvetHayirOPTIONS /users

1.3) HTTP Status Codes

KodAnlamKullanım
200OKBasarili GET, PUT, PATCH
201CreatedBasarili POST
204No ContentBasarili DELETE
301Moved PermanentlyKalici yonlendirme
304Not ModifiedCache gecerli
400Bad RequestGecersiz istek verisi
401UnauthorizedKimlik doğrulama gerekli
403ForbiddenYetki yetersiz
404Not FoundKaynak bulunamadi
405Method Not AllowedDesteklenmeyen HTTP method
409ConflictKaynak catismasi
410GoneKaynak kalici olarak silindi
415Unsupported Media TypeDesteklenmeyen içerik tipi
422Unprocessable EntityValidasyon hatasi
429Too Many RequestsRate limit asildi
500Internal Server ErrorSunucu hatasi
502Bad GatewayUpstream sunucu hatasi
503Service UnavailableSunucu gecici olarak kulanilamaz
504Gateway TimeoutUpstream sunucu zaman asimi

1.4) Response Format

Tutarli bir response yapisi kullanmak istemci tarafini kolaylastirir.

json
// 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öntemAvantajDezavantajKullanım Alani
Offset-basedBasit, herhangi sayfaya atlaBüyük offset'lerde yavas, veri kaymasiAdmin panelleri, küçük veri
Cursor-basedPerformansli, tutarli sonuclarRastgele sayfaya atlanamazFeed, sonsuz scroll
Keyset-basedCok performansliKarmasik siralama zorluBü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=20

Node.js Offset Ornegi:

js
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=fahri

1.7) Versiyonlama

YöntemÖrnekAvantajDezavantaj
URL path/api/v1/usersAcik, basitURL kirlilik
Query string/api/users?version=1Kolay gecisGozden kacabilir
HeaderAccept: application/vnd.api.v1+jsonTemiz URLDebug zor
Content-TypeContent-Type: application/vnd.api.v1+jsonStandartKarmasik

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

graphql
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

graphql
# 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.

js
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

ÖzellikRESTGraphQL
Veri cekmeSabit endpoint'lerIstemci belirler
Over-fetchingSik yasanirYok
Under-fetchingBirden fazla istek gerekirTek istekte cozulur
CacheHTTP cache kolayOzel cache gerekir
Dosya yüklemeKolayEk kütüphane gerekir
Öğrenme egrisiDüşükOrta-yüksek
Hata yönetimiHTTP status codes200 + errors dizisi
Real-timeYok (SSE/WS ayri)Subscription destegi
DokumantasyonSwagger/OpenAPIIntrospection + Playground
VersiyonlamaURL/header ileSchema evolution

3) gRPC

gRPC, Google tarafindan gelistirilen yüksek performansli RPC framework'udur. Protocol Buffers (protobuf) kullanir, HTTP/2 uzerinde çalışır.

protobuf
// 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

js
// 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

SenaryoWebSocketREST + PollingSSE
Chat uygulamasiEvetHayirKismi
Canli bildirimlerEvetMumkunEvet
Canli dashboardEvetMumkunEvet
OyunEvetHayirHayir
Dosya yükleme durumuHayirEvetEvet
Form gondermeHayirEvetHayir

5) Authentication

5.1) API Key

En basit kimlik doğrulama yontemidir. Genellikle server-to-server iletisimde kullanilir.

js
// 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/data

5.2) JWT (JSON Web Token)

JWT, stateless kimlik doğrulama için standarttir. Uclu yapiya sahiptir: Header.Payload.Signature.

js
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     |
+--------+                               +---------------+
js
// 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

AlgoritmaNasil CalisirAvantajDezavantaj
Fixed WindowSabit zaman diliminde sayac tutarBasitPencere sinirinda patlama
Sliding WindowKayan pencere ile ortalama hesaplarDaha adilDaha fazla bellek
Token BucketSabit hizda token eklenir, istekte harcanirBurst'e izin verirKarmasik
Leaky BucketSabit hizda istek islenir, fazlasi kuyrugaDuz trafikGecikme olusabilir
js
// 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.

yaml
# 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
js
// 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.

bash
# Newman ile Postman collection calistirma
npm install -g newman
newman run collection.json -e environment.json --reporters cli,html

8) API Testing

8.1) curl ile Test

bash
# 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/users

8.2) Supertest ile Entegrasyon Testi

js
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.

js
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.

js
// 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.

js
// 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

Diger Kategoriler

Developer Guides & Technical References