@yildizpay/http-adapter 3.0.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +253 -9
  2. package/README.tr.md +288 -44
  3. package/dist/builders/request.builder.d.ts +3 -0
  4. package/dist/builders/request.builder.js +6 -1
  5. package/dist/builders/request.builder.js.map +1 -1
  6. package/dist/contracts/http-client.contract.d.ts +0 -9
  7. package/dist/contracts/http-client.contract.js +0 -17
  8. package/dist/contracts/http-client.contract.js.map +1 -1
  9. package/dist/contracts/http-interceptor.contract.d.ts +6 -2
  10. package/dist/contracts/response-validator.contract.d.ts +4 -0
  11. package/dist/contracts/response-validator.contract.js +3 -0
  12. package/dist/contracts/response-validator.contract.js.map +1 -0
  13. package/dist/core/default-http-client.js +7 -6
  14. package/dist/core/default-http-client.js.map +1 -1
  15. package/dist/core/error.converter.d.ts +5 -0
  16. package/dist/core/error.converter.js +31 -0
  17. package/dist/core/error.converter.js.map +1 -0
  18. package/dist/core/http.adapter.js +28 -4
  19. package/dist/core/http.adapter.js.map +1 -1
  20. package/dist/exceptions/base-adapter.exception.d.ts +7 -0
  21. package/dist/exceptions/base-adapter.exception.js +34 -0
  22. package/dist/exceptions/base-adapter.exception.js.map +1 -0
  23. package/dist/exceptions/circuit-breaker-open.exception.d.ts +2 -2
  24. package/dist/exceptions/circuit-breaker-open.exception.js +3 -3
  25. package/dist/exceptions/circuit-breaker-open.exception.js.map +1 -1
  26. package/dist/exceptions/exception.guards.d.ts +17 -0
  27. package/dist/exceptions/exception.guards.js +53 -0
  28. package/dist/exceptions/exception.guards.js.map +1 -0
  29. package/dist/exceptions/http-exception.factory.d.ts +5 -0
  30. package/dist/exceptions/http-exception.factory.js +59 -0
  31. package/dist/exceptions/http-exception.factory.js.map +1 -0
  32. package/dist/exceptions/http-status.exceptions.d.ts +134 -0
  33. package/dist/exceptions/http-status.exceptions.js +382 -0
  34. package/dist/exceptions/http-status.exceptions.js.map +1 -0
  35. package/dist/exceptions/network-exception.factory.d.ts +6 -0
  36. package/dist/exceptions/network-exception.factory.js +35 -0
  37. package/dist/exceptions/network-exception.factory.js.map +1 -0
  38. package/dist/exceptions/network.exceptions.d.ts +25 -0
  39. package/dist/exceptions/network.exceptions.js +69 -0
  40. package/dist/exceptions/network.exceptions.js.map +1 -0
  41. package/dist/exceptions/unknown.exception.d.ts +7 -0
  42. package/dist/exceptions/unknown.exception.js +20 -0
  43. package/dist/exceptions/unknown.exception.js.map +1 -0
  44. package/dist/exceptions/validation.exception.d.ts +9 -0
  45. package/dist/exceptions/validation.exception.js +25 -0
  46. package/dist/exceptions/validation.exception.js.map +1 -0
  47. package/dist/index.d.ts +11 -1
  48. package/dist/index.js +11 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/models/request-context.d.ts +5 -0
  51. package/dist/models/request-context.js +3 -0
  52. package/dist/models/request-context.js.map +1 -0
  53. package/dist/models/request.d.ts +3 -1
  54. package/dist/models/request.js +2 -1
  55. package/dist/models/request.js.map +1 -1
  56. package/dist/models/response.d.ts +8 -5
  57. package/dist/models/response.js +9 -5
  58. package/dist/models/response.js.map +1 -1
  59. package/dist/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +17 -3
  61. package/dist/exceptions/http.exception.d.ts +0 -5
  62. package/dist/exceptions/http.exception.js +0 -12
  63. package/dist/exceptions/http.exception.js.map +0 -1
package/README.tr.md CHANGED
@@ -6,16 +6,18 @@
6
6
  ![NPM Version](https://img.shields.io/npm/v/@yildizpay/http-adapter)
7
7
  ![License](https://img.shields.io/npm/l/@yildizpay/http-adapter)
8
8
 
9
- Node.js tabanlı kurumsal seviye (enterprise-grade) uygulamalar için tasarlanmış profesyonel, dayanıklı (robust) ve yüksek oranda yapılandırılabilir bir HTTP istemci (client) adaptörü. Akıcı (fluent) bir API, yerleşik ağ direnci (resilience) desenleri ve güçlü bir önleyici (interceptor) sistemi sunar. Dış bağımlılık bulundurmayan (zero-dependency) paketin çekirdeği **Node.js Native Fetch API** kullanır ancak tercih edilen farklı özel HTTP istemcilerine de (Custom Clients) kolayca genişletilebilir.
9
+ Node.js tabanlı kurumsal uygulamalar için tasarlanmış profesyonel ve yüksek oranda yapılandırılabilir bir HTTP client adaptörü. Fluent API, built-in resilience pattern'ları, güçlü bir interceptor sistemi ve kapsamlı bir exception hiyerarşisi sunar. Zero-dependency olan paketin çekirdeği **Node.js Native Fetch API** kullanır; ancak istenen farklı custom HTTP client'lara da kolayca genişletilebilir.
10
10
 
11
11
  ## Temel Özellikler
12
12
 
13
- - **Akıcı İstek Oluşturucu (Fluent Request Builder):** Sezgisel ve zincirlenebilir (chainable) bir API ile karmaşık HTTP isteklerini kolayca oluşturun.
14
- - **Önleyici Mimarisi (Interceptor Architecture):** Loglama, kimlik doğrulama, hata yönetimi ve veri dönüşümü gibi ara yazılım (middleware) işlemlerini zahmetsizce entegre edin.
15
- - ** Direnci ve Güvenilirlik (Resilience & Reliability):** Sunucular arası entegrasyonlarda geçici arızaları zarif bir şekilde yönetmek ve zincirleme (cascading) hataları önlemek için üstel geri çekilme (Exponential Backoff vs.) gibi yeniden deneme (retry) politikaları ve yerleşik bir **Devre Kesici (Circuit Breaker)** içerir.
16
- - **Tip Güvenliği (Type Safety):** Jenerikleri (generics) kullanan tam tiplendirilmiş (fully typed) istek ve yanıtlar ile uygulamanız genelinde tip güvenliği sağlar.
17
- - **Test Edilebilirlik:** Bağımlılık enjeksiyonu (dependency injection) düşünülerek tasarlandığından, birim testleri (unit mock) yazmak oldukça kolaydır.
18
- - **Değişmez (Immutable) Tasarım:** Eşzamanlı (concurrent) ortamlarda yan etkileri (side effects) önlemek için çekirdek (core) bileşenler değiştirilemez (immutable) yapıda tasarlanmıştır.
13
+ - **Fluent Request Builder:** Sezgisel ve zincirlenebilir bir API ile karmaşık HTTP isteklerini kolayca oluşturun.
14
+ - **Structured Exception Hierarchy:** Her HTTP durum kodu ve hatası, zengin metadata, `isRetryable()` sinyali ve `toJSON()` desteğiyle ayrı bir exception sınıfına dönüştürülür.
15
+ - **Response Validation:** Herhangi bir request'e bir veya daha fazla `ResponseValidator` ekleyerek schema kısıtlamalarını veya business rule'ları response kodunuza ulaşmadan otomatik olarak denetleyebilirsiniz.
16
+ - **Interceptor Mimarisi:** Loglama, kimlik doğrulama, hata yönetimi ve veri dönüşümü gibi middleware işlemlerini zahmetsizce entegre edin.
17
+ - **Resilience & Reliability:** S2S entegrasyonlarında geçici hataları zarif bir şekilde yönetmek için Exponential Backoff gibi retry policy'ler ve built-in **Circuit Breaker** içerir.
18
+ - **Type Safety:** Generic'ler kullanılarak tam olarak tiplendirilmiş request ve response'lar ile uygulama genelinde tip güvenliği sağlanır.
19
+ - **Test Edilebilirlik:** Dependency injection düşünülerek tasarlandığından mock yazmak oldukça kolaydır.
20
+ - **Immutable Tasarım:** Concurrent ortamlarda side effect'leri önlemek için core bileşenler immutable olarak tasarlanmıştır.
19
21
 
20
22
  ## Kurulum
21
23
 
@@ -29,9 +31,9 @@ pnpm add @yildizpay/http-adapter
29
31
 
30
32
  ## Kullanım
31
33
 
32
- ### 1. Temel İstek Oluşturma
34
+ ### 1. Request Oluşturma
33
35
 
34
- İstekleri temiz ve öz bir şekilde oluşturmak için `RequestBuilder` sınıfını kullanın.
36
+ `RequestBuilder` ile istekleri temiz ve öz bir şekilde oluşturun.
35
37
 
36
38
  ```typescript
37
39
  import { RequestBuilder, HttpMethod } from '@yildizpay/http-adapter';
@@ -44,31 +46,31 @@ const request = new RequestBuilder('https://api.example.com')
44
46
  .build();
45
47
  ```
46
48
 
47
- ### 2. Adaptörü Başlatma
49
+ ### 2. Adapter'ı Başlatma
48
50
 
49
- İsteğe bağlı önleyiciler (interceptors), yeniden deneme (retry) politikaları ve devre kesici (circuit breaker) ile `HttpAdapter` nesnesini oluşturun.
51
+ İsteğe bağlı interceptor'lar, retry policy ve circuit breaker ile `HttpAdapter` oluşturun.
50
52
 
51
53
  ```typescript
52
54
  import { HttpAdapter, RetryPolicies, CircuitBreaker } from '@yildizpay/http-adapter';
53
55
 
54
56
  const circuitBreaker = new CircuitBreaker({
55
57
  failureThreshold: 5,
56
- resetTimeoutMs: 60000,
58
+ resetTimeoutMs: 60000,
57
59
  });
58
60
 
59
61
  const adapter = HttpAdapter.create(
60
62
  [
61
- /* interceptors (önleyiciler) */
63
+ /* interceptors */
62
64
  ],
63
- RetryPolicies.exponential(3), // Üstel (exponential) geri çekilme ile 3 defaya kadar yeniden dene
64
- undefined, // İsteğe bağlı özel HTTP istemcisi (opsiyonel)
65
- circuitBreaker // İsteğe bağlı Devre Kesici (opsiyonel)
65
+ RetryPolicies.exponential(3), // Exponential backoff ile 3 defaya kadar retry
66
+ undefined, // Opsiyonel custom HTTP client
67
+ circuitBreaker, // Opsiyonel Circuit Breaker
66
68
  );
67
69
  ```
68
70
 
69
- ### 3. İstek Gönderme
71
+ ### 3. Request Gönderme
70
72
 
71
- İsteği yürütün ve kesin bir şekilde tiplendirilmiş (strongly-typed) yanıtı (response) alın.
73
+ Request'i çalıştırın ve strongly-typed response alın.
72
74
 
73
75
  ```typescript
74
76
  interface UserResponse {
@@ -80,45 +82,281 @@ try {
80
82
  const response = await adapter.send<UserResponse>(request);
81
83
  console.log('Kullanıcı oluşturuldu:', response.data);
82
84
  } catch (error) {
83
- console.error('İstek başarısız oldu:', error);
85
+ console.error('Request başarısız oldu:', error);
84
86
  }
85
87
  ```
86
88
 
87
- ## Direnç ve Yeniden Denemeler (Resilience & Retries)
89
+ ## Hata Yönetimi (Error Handling)
88
90
 
89
- kararsızlığı kaçınılmazdır. Bu adaptör, sağlam yeniden deneme stratejileri tanımlamanıza olanak tanır.
91
+ `@yildizpay/http-adapter`, her türlü ham hatayı — HTTP hataları, OS düzeyindeki ağ hataları veya tamamen beklenmedik exception'lar — yapılandırılmış ve tiplendirilmiş bir exception sınıfına dönüştürür. Bu sayede `catch` bloklarında ham durum kodlarını ya da hata kodlarını elle incelemenize gerek kalmaz.
90
92
 
91
- ### Üstel Geri Çekilme (Exponential Backoff)
93
+ ### Exception Hiyerarşisi
92
94
 
93
- Yerleşik `ExponentialBackoffPolicy`, denemeler arasında giderek daha uzun süreler (ör. 200ms, 400ms, 800ms) bekler ve "gürleyen sürü" (thundering herd) sorunlarını önlemek için gecikmelere rastgele bir sapma (jitter) ekler.
95
+ ```
96
+ BaseAdapterException
97
+ ├── HttpException (herhangi bir HTTP response hatası)
98
+ │ ├── BadRequestException (400)
99
+ │ ├── UnauthorizedException (401)
100
+ │ ├── ForbiddenException (403)
101
+ │ ├── NotFoundException (404)
102
+ │ ├── ConflictException (409)
103
+ │ ├── UnprocessableEntityException (422)
104
+ │ ├── TooManyRequestsException (429) ← isRetryable() = true
105
+ │ ├── InternalServerErrorException (500)
106
+ │ ├── BadGatewayException (502) ← isRetryable() = true
107
+ │ ├── ServiceUnavailableException (503) ← isRetryable() = true
108
+ │ ├── GatewayTimeoutException (504) ← isRetryable() = true
109
+ │ └── ... (tüm 4xx / 5xx kodları)
110
+ ├── NetworkException (OS düzeyindeki bağlantı hataları)
111
+ │ ├── ConnectionRefusedException (ECONNREFUSED) ← isRetryable() = true
112
+ │ ├── TimeoutException (ETIMEDOUT / ECONNABORTED / AbortError) ← isRetryable() = true
113
+ │ ├── SocketResetException (ECONNRESET) ← isRetryable() = true
114
+ │ ├── DnsResolutionException (ENOTFOUND / EAI_AGAIN)
115
+ │ └── HostUnreachableException (EHOSTUNREACH / ENETUNREACH)
116
+ ├── UnknownException (sınıflandırılamayan her türlü hata)
117
+ └── CircuitBreakerOpenException (circuit açık, request gönderilmedi)
118
+ ```
119
+
120
+ ### Exception Türüne Göre Yakalama
121
+
122
+ ```typescript
123
+ import {
124
+ NotFoundException,
125
+ TooManyRequestsException,
126
+ TimeoutException,
127
+ ConnectionRefusedException,
128
+ CircuitBreakerOpenException,
129
+ UnknownException,
130
+ } from '@yildizpay/http-adapter';
131
+
132
+ try {
133
+ const response = await adapter.send<PaymentResponse>(request);
134
+ } catch (error) {
135
+ if (error instanceof NotFoundException) {
136
+ // HTTP 404 — kaynak bulunamadı
137
+ console.error('Kaynak bulunamadı:', error.response.data);
138
+ } else if (error instanceof TooManyRequestsException) {
139
+ // HTTP 429 — retry'dan önce bekle
140
+ const retryAfterMs = error.getRetryAfterMs();
141
+ console.warn(`Rate limit aşıldı. ${retryAfterMs}ms sonra tekrar dene`);
142
+ } else if (error instanceof TimeoutException) {
143
+ // ETIMEDOUT / AbortError — downstream servis yavaş
144
+ console.error('Request timeout:', error.code);
145
+ } else if (error instanceof ConnectionRefusedException) {
146
+ // ECONNREFUSED — downstream servis kapalı
147
+ console.error('Servis kapalı:', error.requestContext?.url);
148
+ } else if (error instanceof CircuitBreakerOpenException) {
149
+ // Circuit açık — sunucuya istek gönderilmeden fail fast
150
+ console.error('Circuit breaker açık. Request gönderilmedi.');
151
+ } else if (error instanceof UnknownException) {
152
+ // Beklenmedik bir hata — logla ve araştır
153
+ console.error('Bilinmeyen hata:', error.toJSON());
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### Type Guard'lar
159
+
160
+ `instanceof` kullanmadan type narrowing tercih ediyorsanız — fonksiyonel pipeline'larda veya modül sınırlarını geçerken kullanışlıdır — her exception sınıfının karşılık gelen bir type guard'ı mevcuttur:
161
+
162
+ ```typescript
163
+ import {
164
+ isHttpException,
165
+ isTimeoutException,
166
+ isConnectionRefusedException,
167
+ isCircuitBreakerOpenException,
168
+ } from '@yildizpay/http-adapter';
169
+
170
+ function handleError(error: unknown): void {
171
+ if (isTimeoutException(error)) {
172
+ // TypeScript artık biliyor: error, TimeoutException türünde
173
+ scheduleRetry(error.requestContext?.url);
174
+ } else if (isHttpException(error)) {
175
+ // TypeScript artık biliyor: error, HttpException türünde
176
+ reportToMonitoring(error.response.status, error.response.data);
177
+ }
178
+ }
179
+ ```
180
+
181
+ ### `isRetryable()` Sinyali
182
+
183
+ Her exception, hatanın geçici olup olmadığını ve retry'a değer olup olmadığını belirten bir `isRetryable(): boolean` metodu sunar. Custom retry decorator'lar yazarken ya da uygulama katmanında hatayı tekrar denemek isteyip istemediğinize karar verirken kullanışlıdır.
184
+
185
+ ```typescript
186
+ } catch (error) {
187
+ if (error instanceof BaseAdapterException && error.isRetryable()) {
188
+ return retryOperation();
189
+ }
190
+ throw error;
191
+ }
192
+ ```
193
+
194
+ Retry edilebilir exception'lar: `TooManyRequestsException (429)`, `BadGatewayException (502)`, `ServiceUnavailableException (503)`, `GatewayTimeoutException (504)`, `TimeoutException`, `SocketResetException`, `ConnectionRefusedException`.
195
+
196
+ ### `toJSON()` ile Structured Logging
197
+
198
+ Tüm exception'lar `toJSON()` metodunu override eder; bu sayede Pino, Winston gibi structured logger'larla tam uyumludur. `JSON.stringify(error)` çağrısı boş `{}` yerine eksiksiz bir log objesi üretir.
199
+
200
+ ```typescript
201
+ } catch (error) {
202
+ if (error instanceof BaseAdapterException) {
203
+ logger.error(error.toJSON());
204
+ // {
205
+ // name: 'NotFoundException',
206
+ // message: 'Not Found',
207
+ // code: 'ERR_NOT_FOUND',
208
+ // stack: '...',
209
+ // response: {
210
+ // status: 404,
211
+ // data: { detail: 'Ödeme kaydı bulunamadı' },
212
+ // request: { method: 'GET', url: 'https://api.example.com/payments/123', correlationId: 'corr-abc' }
213
+ // }
214
+ // }
215
+ }
216
+ }
217
+ ```
218
+
219
+ ### `RequestContext` — Güvenli Request Metadata
220
+
221
+ Her exception, kaynak request'ten alınan `RequestContext` objesini (`method`, `url`, `correlationId`) otomatik olarak taşır. Auth token'larının veya kişisel verilerin (PII) loglara sızmasını önlemek amacıyla header ve body bilgileri bu objeden kasıtlı olarak çıkarılmıştır.
222
+
223
+ ```typescript
224
+ } catch (error) {
225
+ if (error instanceof NetworkException) {
226
+ logger.warn({
227
+ event: 'network_failure',
228
+ exception: error.name,
229
+ request: error.requestContext, // { method, url, correlationId }
230
+ });
231
+ }
232
+ }
233
+ ```
234
+
235
+ ### Response Validator'lar
236
+
237
+ Request'e validator ekleyerek schema kısıtlamalarını veya business rule'ları response kodunuza ulaşmadan otomatik olarak denetleyebilirsiniz. Validator'lar HTTP çağrısı başarılı olduktan sonra, response-side interceptor'lardan önce sırayla çalışır. İlk hata veren validator chain'i durdurur.
238
+
239
+ ```typescript
240
+ import { ResponseValidator, ValidationException, Response } from '@yildizpay/http-adapter';
241
+
242
+ class PaymentStatusValidator implements ResponseValidator<IyzicoResponse> {
243
+ validate(response: Response<IyzicoResponse>): void {
244
+ if (response.data.status !== 'success') {
245
+ throw new ValidationException(
246
+ `Payment failed: ${response.data.errorMessage}`,
247
+ response,
248
+ );
249
+ }
250
+ }
251
+ }
252
+
253
+ // Zod, Joi gibi herhangi bir validation kütüphanesiyle çalışır
254
+ class PaymentSchemaValidator implements ResponseValidator<unknown> {
255
+ validate(response: Response<unknown>): void {
256
+ IyzicoResponseSchema.parse(response.data); // Zod uyuşmazlıkta exception fırlatır
257
+ }
258
+ }
259
+
260
+ const request = new RequestBuilder('https://api.iyzipay.com')
261
+ .setEndpoint('/payment/auth')
262
+ .setMethod(HttpMethod.POST)
263
+ .setBody(dto)
264
+ .validateWith(new PaymentSchemaValidator(), new PaymentStatusValidator())
265
+ .build();
266
+ ```
267
+
268
+ Validation hatasını yakalamak:
269
+
270
+ ```typescript
271
+ import { isValidationException } from '@yildizpay/http-adapter';
272
+
273
+ } catch (error) {
274
+ if (isValidationException(error)) {
275
+ console.error('Validation başarısız:', error.message);
276
+ console.error('Ham response:', error.response.data);
277
+ }
278
+ }
279
+ ```
280
+
281
+ Validator içinde fırlatılan `BaseAdapterException` olmayan hatalar (örn. `ZodError`) otomatik olarak `ValidationException`'a sarılır; orijinal hata `cause`'ta tutulur. Typed erişim için generic parametre kullanılabilir:
282
+
283
+ ```typescript
284
+ } catch (error) {
285
+ if (isValidationException<ZodError>(error) && error.cause) {
286
+ console.error('Schema hataları:', error.cause.issues);
287
+ }
288
+ }
289
+ ```
290
+
291
+ Validator kayıtlıyken tam interceptor lifecycle'ı:
292
+
293
+ ```
294
+ onRequest → HTTP call → onResponse → validators → onResponseValidated → caller
295
+ ↓ (hata durumunda)
296
+ onError
297
+ ```
298
+
299
+ `onResponse` her zaman çalışır. `onResponseValidated` yalnızca tüm validator'lar geçtiğinde çalışır — business açısından geçerli bir response gerektiren cache veya side effect işlemleri için idealdir.
300
+
301
+ ### Error Interceptor
302
+
303
+ Exception'lar business logic'e ulaşmadan önce interceptor seviyesinde yakalanabilir ve dönüştürülebilir.
304
+
305
+ ```typescript
306
+ import {
307
+ HttpErrorInterceptor,
308
+ Request,
309
+ BaseAdapterException,
310
+ UnauthorizedException,
311
+ } from '@yildizpay/http-adapter';
312
+
313
+ export class GlobalErrorInterceptor implements HttpErrorInterceptor {
314
+ async onError(error: BaseAdapterException, request: Request): Promise<never> {
315
+ if (error instanceof UnauthorizedException) {
316
+ await this.tokenService.refresh();
317
+ }
318
+ // Caller'ın handle edebilmesi için hatayı yeniden fırlat
319
+ throw error;
320
+ }
321
+ }
322
+ ```
323
+
324
+ ## Resilience & Retry
325
+
326
+ Ağ kararsızlığı kaçınılmazdır. Bu adaptör, sağlam retry stratejileri tanımlamanıza olanak tanır.
327
+
328
+ ### Exponential Backoff
329
+
330
+ Built-in `ExponentialBackoffPolicy`, denemeler arasında giderek artan süreler (ör. 200ms, 400ms, 800ms) bekler ve "thundering herd" sorununu önlemek için gecikmelere rastgele jitter ekler.
94
331
 
95
332
  ```typescript
96
333
  import { RetryPolicies } from '@yildizpay/http-adapter';
97
334
 
98
- // 429, 500, 502, 503, 504 durum kodlarında ve ağ hatalarında yeniden dener
335
+ // 429, 502, 503, 504 ve ağ hatalarında retry yapar
99
336
  const retryPolicy = RetryPolicies.exponential(5);
100
337
  ```
101
338
 
102
- ### Devre Kesici (Circuit Breaker)
339
+ ### Circuit Breaker
103
340
 
104
- Sisteminizi tamamen çökmüş olan bir sunucuyu beklemekten korumak için `CircuitBreaker` (Devre Kesici) yönteminden yararlanabilirsiniz. Konfigürasyonla belirlenmiş miktarda ardışık hata alındığında devre açılır ve yanıt vermeyen sunucuya gereksiz istek göndermeksizin anında `CircuitBreakerOpenException` fırlatarak cevap verir.
341
+ Tamamen çökmüş bir downstream servisi beklemeye karşı sisteminizi korumak için `CircuitBreaker` kullanabilirsiniz. Belirli sayıda ardışık hata alındığında circuit açılır ve yanıt vermeyen servise gereksiz istek göndermeksizin anında `CircuitBreakerOpenException` fırlatır.
105
342
 
106
343
  ```typescript
107
344
  import { CircuitBreaker } from '@yildizpay/http-adapter';
108
345
 
109
346
  const breaker = new CircuitBreaker({
110
- failureThreshold: 5, // 5 hatadan sonra devreyi
111
- resetTimeoutMs: 30000, // 30 saniye sonra 'yarı-açık' (half-open) test isteği dene
112
- successThreshold: 1, // Yarı-açık durumda 1 başarılı istek sonrası devreyi kapat
347
+ failureThreshold: 5, // 5 hatadan sonra circuit'i
348
+ resetTimeoutMs: 30000, // 30 saniye sonra half-open test isteği gönder
349
+ successThreshold: 1, // 1 başarılı half-open request sonrası circuit'i kapat
113
350
  });
114
351
  ```
115
352
 
116
- ## Önleyiciler (Interceptors)
353
+ ## Interceptors
354
+
355
+ **Interface Segregation Principle (ISP)** sayesinde gereksiz metodları implement etmek zorunda kalmazsınız. Yalnızca ihtiyaç duyduğunuz lifecycle event'e göre `HttpRequestInterceptor`, `HttpResponseInterceptor` veya `HttpErrorInterceptor` interface'ini implement edebilirsiniz.
117
356
 
118
- **Arayüz Ayrımı Prensibi (ISP)** sayesinde gereksiz tüm metodları uygulamak zorunda kalmazsınız. Tam olarak araya girmek istediğiniz yaşam döngüsüne göre `HttpRequestInterceptor`, `HttpResponseInterceptor` veya `HttpErrorInterceptor` arayüzlerini uygulayabilirsiniz.
357
+ ### 1. Request Interceptor (Örn: Auth Token)
119
358
 
120
- ### 1. İstek Önleyici (Örn: Kimlik Doğrulama)
121
- İstekler yola çıkmadan önce `Authorization` (Yetkilendirme) gibi başlıkları otomatik ekleyebilirsiniz.
359
+ Request'ler gönderilmeden önce `Authorization` gibi header'ları otomatik ekleyebilirsiniz.
122
360
 
123
361
  ```typescript
124
362
  import { HttpRequestInterceptor, Request } from '@yildizpay/http-adapter';
@@ -131,8 +369,9 @@ export class AuthInterceptor implements HttpRequestInterceptor {
131
369
  }
132
370
  ```
133
371
 
134
- ### 2. Yanıt Önleyici (Örn: Veri İzleme ve Dönüşüm)
135
- Projeye giren tüm başarılı verileri merkezi olarak şekillendirebilir veya loglayabilirsiniz.
372
+ ### 2. Response Interceptor (Örn: Veri Dönüşümü)
373
+
374
+ Gelen tüm response'ları merkezi olarak şekillendirebilir veya loglayabilirsiniz.
136
375
 
137
376
  ```typescript
138
377
  import { HttpResponseInterceptor, Response } from '@yildizpay/http-adapter';
@@ -140,25 +379,30 @@ import { HttpResponseInterceptor, Response } from '@yildizpay/http-adapter';
140
379
  export class TransformResponseInterceptor implements HttpResponseInterceptor {
141
380
  async onResponse(response: Response): Promise<Response> {
142
381
  if (response.status === 201) {
143
- console.log('Kaynak başarıyla oluşturuldu!');
382
+ console.log('Kaynak başarıyla oluşturuldu!');
144
383
  }
145
384
  return response;
146
385
  }
147
386
  }
148
387
  ```
149
388
 
150
- ### 3. Hata Önleyici (Örn: Evrensel Hata Yönetimi)
151
- Sunucudan gelen hatalı HTTP kodlarını (4xx, 5xx) veya ağ kopmalarını tek bir yerden yakalayıp yönetebilirsiniz.
389
+ ### 3. Error Interceptor (Örn: Global Hata Yönetimi)
390
+
391
+ Sunucudan gelen hatalı HTTP kodlarını (4xx, 5xx) veya ağ hatalarını tek bir yerden yakalayıp yönetebilirsiniz.
152
392
 
153
393
  ```typescript
154
- import { HttpErrorInterceptor, Request, HttpClientException } from '@yildizpay/http-adapter';
394
+ import {
395
+ HttpErrorInterceptor,
396
+ Request,
397
+ BaseAdapterException,
398
+ UnauthorizedException,
399
+ } from '@yildizpay/http-adapter';
155
400
 
156
401
  export class GlobalErrorInterceptor implements HttpErrorInterceptor {
157
- async onError(error: unknown, request: Request): Promise<unknown> {
158
- if (error instanceof HttpClientException && error.response?.status === 401) {
159
- console.error(`${request.endpoint} noktasına yetkisiz erişim! Login sayfasına yönlendiriliyor...`);
402
+ async onError(error: BaseAdapterException, request: Request): Promise<never> {
403
+ if (error instanceof UnauthorizedException) {
404
+ console.error(`${error.requestContext?.url} endpoint'ine yetkisiz erişim!`);
160
405
  }
161
- // Hatayı fırlatmaya devam edebilir veya varsayılan bir veri (fallback) dönebilirsiniz
162
406
  throw error;
163
407
  }
164
408
  }
@@ -166,7 +410,7 @@ export class GlobalErrorInterceptor implements HttpErrorInterceptor {
166
410
 
167
411
  ## Katkıda Bulunma
168
412
 
169
- Katkılarınızı her zaman bekliyoruz! Lütfen bir "Pull Request" göndermekten çekinmeyin.
413
+ Katkılarınızı her zaman bekliyoruz! Lütfen bir Pull Request göndermekten çekinmeyin.
170
414
 
171
415
  ## Lisans
172
416
 
@@ -2,6 +2,7 @@ import { HttpMethod } from '../common/enums/http-method.enum';
2
2
  import { HttpBody } from '../common/types/http.types';
3
3
  import { Request } from '../models/request';
4
4
  import { RequestOptions } from '../models/request-options';
5
+ import { ResponseValidator } from '../contracts/response-validator.contract';
5
6
  export declare class RequestBuilder {
6
7
  private readonly baseUrl;
7
8
  private endpoint;
@@ -10,6 +11,7 @@ export declare class RequestBuilder {
10
11
  private body;
11
12
  private queryParams;
12
13
  private options;
14
+ private readonly validators;
13
15
  constructor(baseUrl: string);
14
16
  setEndpoint(endpoint: string): this;
15
17
  setMethod(method: HttpMethod): this;
@@ -33,5 +35,6 @@ export declare class RequestBuilder {
33
35
  resetQueryParams(): this;
34
36
  setTimeout(timeout: number): this;
35
37
  setOptions(options: RequestOptions): this;
38
+ validateWith(...validators: ResponseValidator[]): this;
36
39
  build(): Request;
37
40
  }
@@ -13,6 +13,7 @@ class RequestBuilder {
13
13
  };
14
14
  this.body = {};
15
15
  this.queryParams = {};
16
+ this.validators = [];
16
17
  this.baseUrl = baseUrl;
17
18
  this.options = new request_options_1.RequestOptions();
18
19
  }
@@ -104,8 +105,12 @@ class RequestBuilder {
104
105
  this.options = options;
105
106
  return this;
106
107
  }
108
+ validateWith(...validators) {
109
+ this.validators.push(...validators);
110
+ return this;
111
+ }
107
112
  build() {
108
- return new request_1.Request(this.baseUrl, this.endpoint, this.method, this.headers, this.queryParams, this.body ? { ...this.body } : undefined, this.options);
113
+ return new request_1.Request(this.baseUrl, this.endpoint, this.method, this.headers, this.queryParams, this.body ? { ...this.body } : undefined, this.options, this.validators);
109
114
  }
110
115
  }
111
116
  exports.RequestBuilder = RequestBuilder;
@@ -1 +1 @@
1
- {"version":3,"file":"request.builder.js","sourceRoot":"","sources":["../../src/builders/request.builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request.builder.js","sourceRoot":"","sources":["../../src/builders/request.builder.ts"],"names":[],"mappings":"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"}
@@ -15,12 +15,3 @@ export interface HttpClientResponse<T = unknown> {
15
15
  export interface HttpClientContract {
16
16
  request<T = unknown>(config: HttpClientRequestConfig): Promise<HttpClientResponse<T>>;
17
17
  }
18
- export declare class HttpClientException<T = unknown> extends Error {
19
- readonly response?: {
20
- status: number;
21
- data: T;
22
- headers: Record<string, string>;
23
- };
24
- readonly code?: string;
25
- constructor(message: string, status?: number, data?: T, headers?: Record<string, string>, code?: string);
26
- }
@@ -1,20 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HttpClientException = void 0;
4
- class HttpClientException extends Error {
5
- constructor(message, status, data, headers, code) {
6
- super(message);
7
- this.name = 'HttpClientException';
8
- Object.setPrototypeOf(this, HttpClientException.prototype);
9
- if (status !== undefined) {
10
- this.response = {
11
- status,
12
- data: data,
13
- headers: headers ?? {},
14
- };
15
- }
16
- this.code = code;
17
- }
18
- }
19
- exports.HttpClientException = HttpClientException;
20
3
  //# sourceMappingURL=http-client.contract.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"http-client.contract.js","sourceRoot":"","sources":["../../src/contracts/http-client.contract.ts"],"names":[],"mappings":";;;AAkCA,MAAa,mBAAiC,SAAQ,KAAK;IAQzD,YACE,OAAe,EACf,MAAe,EACf,IAAQ,EACR,OAAgC,EAChC,IAAa;QAEb,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAE3D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC,QAAQ,GAAG;gBACd,MAAM;gBACN,IAAI,EAAE,IAAS;gBACf,OAAO,EAAE,OAAO,IAAI,EAAE;aACvB,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AA5BD,kDA4BC"}
1
+ {"version":3,"file":"http-client.contract.js","sourceRoot":"","sources":["../../src/contracts/http-client.contract.ts"],"names":[],"mappings":""}
@@ -1,3 +1,4 @@
1
+ import { BaseAdapterException } from '../exceptions/base-adapter.exception';
1
2
  import { Request } from '../models/request';
2
3
  import { Response } from '../models/response';
3
4
  export interface HttpRequestInterceptor {
@@ -6,7 +7,10 @@ export interface HttpRequestInterceptor {
6
7
  export interface HttpResponseInterceptor {
7
8
  onResponse(response: Response): Promise<Response>;
8
9
  }
10
+ export interface HttpValidatedResponseInterceptor {
11
+ onResponseValidated(response: Response): Promise<Response>;
12
+ }
9
13
  export interface HttpErrorInterceptor {
10
- onError(error: unknown, request: Request): Promise<unknown>;
14
+ onError(error: BaseAdapterException, request: Request): Promise<BaseAdapterException>;
11
15
  }
12
- export type HttpInterceptor = Partial<HttpRequestInterceptor> & Partial<HttpResponseInterceptor> & Partial<HttpErrorInterceptor>;
16
+ export type HttpInterceptor = Partial<HttpRequestInterceptor> & Partial<HttpResponseInterceptor> & Partial<HttpValidatedResponseInterceptor> & Partial<HttpErrorInterceptor>;
@@ -0,0 +1,4 @@
1
+ import { Response } from '../models/response';
2
+ export interface ResponseValidator<T = unknown> {
3
+ validate(response: Response<T>): Promise<void> | void;
4
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=response-validator.contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-validator.contract.js","sourceRoot":"","sources":["../../src/contracts/response-validator.contract.ts"],"names":[],"mappings":""}
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.defaultHttpClient = exports.FetchHttpClient = void 0;
4
- const http_client_contract_1 = require("../contracts/http-client.contract");
4
+ const network_exception_factory_1 = require("../exceptions/network-exception.factory");
5
+ const http_exception_factory_1 = require("../exceptions/http-exception.factory");
6
+ const base_adapter_exception_1 = require("../exceptions/base-adapter.exception");
5
7
  class FetchHttpClient {
6
8
  async request(config) {
7
9
  const controller = new AbortController();
@@ -32,7 +34,7 @@ class FetchHttpClient {
32
34
  responseHeaders[key] = value;
33
35
  });
34
36
  if (!response.ok) {
35
- throw new http_client_contract_1.HttpClientException(`Request failed with status ${response.status}`, response.status, responseData, responseHeaders);
37
+ throw http_exception_factory_1.HttpExceptionFactory.createFromResponse(response.status, responseData, responseHeaders, `Request failed with status ${response.status}`);
36
38
  }
37
39
  return {
38
40
  data: responseData,
@@ -41,10 +43,9 @@ class FetchHttpClient {
41
43
  };
42
44
  }
43
45
  catch (error) {
44
- if (error instanceof Error && error.name === 'AbortError') {
45
- throw new http_client_contract_1.HttpClientException('Request Timeout', undefined, undefined, undefined, 'ECONNABORTED');
46
- }
47
- throw error;
46
+ if (error instanceof base_adapter_exception_1.BaseAdapterException)
47
+ throw error;
48
+ throw network_exception_factory_1.NetworkExceptionFactory.createFromNativeError(error);
48
49
  }
49
50
  finally {
50
51
  if (timeoutId) {
@@ -1 +1 @@
1
- {"version":3,"file":"default-http-client.js","sourceRoot":"","sources":["../../src/core/default-http-client.ts"],"names":[],"mappings":";;;AAAA,4EAK2C;AAQ3C,MAAa,eAAe;IACnB,KAAK,CAAC,OAAO,CAClB,MAA+B;QAE/B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,IAAI,SAAqC,CAAC;QAE1C,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;YACzC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACnE,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE;gBACvC,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,GAAG,MAAM,CAAC,OAAO;iBAClB;gBACD,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;gBAC3D,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YAEH,IAAI,YAAY,GAAY,IAAI,CAAC;YACjC,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAEzD,IAAI,WAAW,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC9C,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACzD,CAAC;iBAAM,CAAC;gBACN,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACzD,CAAC;YAED,MAAM,eAAe,GAA2B,EAAE,CAAC;YACnD,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;gBACtC,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAC/B,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,0CAAmB,CAC3B,8BAA8B,QAAQ,CAAC,MAAM,EAAE,EAC/C,QAAQ,CAAC,MAAM,EACf,YAAiB,EACjB,eAAe,CAChB,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,YAAiB;gBACvB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,OAAO,EAAE,eAAe;aACzB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC1D,MAAM,IAAI,0CAAmB,CAC3B,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,SAAS,EACT,cAAc,CACf,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,IAAI,SAAS,EAAE,CAAC;gBACd,YAAY,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAnED,0CAmEC;AAEY,QAAA,iBAAiB,GAAG,IAAI,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"default-http-client.js","sourceRoot":"","sources":["../../src/core/default-http-client.ts"],"names":[],"mappings":";;;AAKA,uFAAkF;AAClF,iFAA4E;AAC5E,iFAA4E;AAQ5E,MAAa,eAAe;IACnB,KAAK,CAAC,OAAO,CAClB,MAA+B;QAE/B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,IAAI,SAAqC,CAAC;QAE1C,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;YACzC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACnE,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE;gBACvC,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,GAAG,MAAM,CAAC,OAAO;iBAClB;gBACD,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;gBAC3D,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YAEH,IAAI,YAAY,GAAY,IAAI,CAAC;YACjC,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAEzD,IAAI,WAAW,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC9C,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACzD,CAAC;iBAAM,CAAC;gBACN,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACzD,CAAC;YAED,MAAM,eAAe,GAA2B,EAAE,CAAC;YACnD,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;gBACtC,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAC/B,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,6CAAoB,CAAC,kBAAkB,CAC3C,QAAQ,CAAC,MAAM,EACf,YAAiB,EACjB,eAAe,EACf,8BAA8B,QAAQ,CAAC,MAAM,EAAE,CAChD,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,YAAiB;gBACvB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,OAAO,EAAE,eAAe;aACzB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,YAAY,6CAAoB;gBAAE,MAAM,KAAK,CAAC;YACvD,MAAM,mDAAuB,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAC7D,CAAC;gBAAS,CAAC;YACT,IAAI,SAAS,EAAE,CAAC;gBACd,YAAY,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA3DD,0CA2DC;AAEY,QAAA,iBAAiB,GAAG,IAAI,eAAe,EAAE,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { BaseAdapterException } from '../exceptions/base-adapter.exception';
2
+ import { RequestContext } from '../models/request-context';
3
+ export declare class ErrorConverter {
4
+ static toAdapterException(error: unknown, requestContext?: RequestContext): BaseAdapterException;
5
+ }