# SFCC Hook Kullanımı: hooks.json Örnekleriyle Pratik Rehber

URL: https://www.ozanaltinbas.com/tr/makale/sfcc-hooks
Author: Ozan Altinbas (Ozan Altınbaş), SFCC Technical Architect
Published: 2026-11-12
Category: Geliştirme | Tags: SFCC, Hook, Cartridge, SFRA, SCAPI

---

Hook'lar, B2C Commerce'in kodunuzu kendisine ait olmayan noktalarda çalıştırma yoludur: bir Shopper API isteğinin içinde, sepet hesaplaması sırasında, her storefront isteğinin başında ya da kendi storefront'unuzun tanımladığı bir extension point'te. Production hatalarının önemli bir kısmı da burada yaşar; çünkü hangi implementasyonun hangi sırayla çalıştığı ve bir dönüş değerinin ne yaptığı hook ailesine göre değişir, çoğu eğitim içeriği ise bunları tek bir kural gibi anlatır.

Bu rehber; hook kaydını, çalışma sırasını, `dw.system.HookMgr` kullanımını, SCAPI ve OCAPI hook'larını, sistem hook'larını, hata yönetimini, performansı ve testi ele alıyor. Cartridge'ların nasıl çalıştığını bildiğinizi varsayar; bilmiyorsanız [SFCC cartridge geliştirme rehberiyle](https://www.ozanaltinbas.com/tr/makale/sfcc-cartridge-development) başlayın, platformun geneli için de [SFCC rehberine](https://www.ozanaltinbas.com/tr/sfcc) bakın.

---

## B2C Commerce'te hook nedir

Hook, bir fonksiyon export eden CommonJS modülüne eşlenmiş, adı olan bir **genişletme noktasıdır (extension point)**. Platform ya da kendi kodunuz extension point'i adıyla çağırır; B2C Commerce kayıtlı modülleri bulur ve çalıştırır. [HookMgr referansı](https://developer.salesforce.com/docs/commerce/b2c-commerce/references/b2c-script-api/dw.system.HookMgr.html) bunu "iş mantığında, işlevselliği özelleştirmek için script kaydedebileceğiniz bir extension point" olarak tanımlar.

Üç aile vardır ve aralarındaki farklar ileride önem kazanır:

| Aile | İsim kalıbı | Kim çağırır | Örnek |
|---|---|---|---|
| Shopper API hook'ları (SCAPI ve OCAPI) | `dw.ocapi.shop.<resource>.<hook><METHOD>` | Platform, bir API isteği sırasında | `dw.ocapi.shop.basket.beforePATCH` |
| Sistem hook'ları | `dw.order.*`, `dw.system.request.*` | Platform ya da `HookMgr` üzerinden kendi kodunuz | `dw.order.calculate` |
| Custom hook'lar | Kendi namespace'iniz, örneğin `app.*` | `HookMgr.callHook` üzerinden kendi kodunuz | `app.payment.processor.default` (SFRA) |

Hook'lar SFRA route genişletmesi değildir: `server.append` bir route'u, hook ise bir iş operasyonunu nerede çalışırsa çalışsın genişletir. [SFRA hooks dokümantasyonu](https://developer.salesforce.com/docs/commerce/sfra/guide/b2c-sfra-hooks.html), custom bir hook'un hem OCAPI'den hem storefront kodundan çağrılabileceğini belirtir; bu da hook'ları bir SFRA storefront'u ile headless bir kanalın paylaştığı mantığın doğal yeri yapar.

---

## Hook'ları bir cartridge'a kaydetmek

Kayıt üç parçadan oluşur; burada tek bir custom cartridge içinde gösteriliyor:

```text
app_custom_hooks/
  package.json
  cartridge/
    scripts/
      hooks.json
      hooks/
        loyalty.js
        product.js
        address.js
```

### Adım 1: package.json dosyasını hooks.json dosyasına yönlendirin

Cartridge'ın en üst dizinindeki `package.json`, hook dosyasını `hooks` anahtarıyla belirtir. Yol, `package.json` dosyasının bulunduğu dizine göredir:

```json
{
  "hooks": "./cartridge/scripts/hooks.json"
}
```

### Adım 2: hooks.json içinde extension point'leri script'lere eşleyin

`hooks` dizisindeki her kaydın bir `name` (extension point) ve bir `script` (`hooks.json` dosyasına göre göreli bir yol ya da geçerli herhangi bir modül tanımlayıcısı) alanı vardır:

```json
{
  "hooks": [
    { "name": "app.loyalty.orderPlaced", "script": "./hooks/loyalty.js" },
    { "name": "dw.ocapi.shop.product.modifyGETResponse", "script": "./hooks/product.js" },
    { "name": "dw.ocapi.shop.basket.shipment.shipping_address.beforePUT", "script": "./hooks/address.js" }
  ]
}
```

### Adım 3: fonksiyonu export edin

Platform hook'larında export edilen isim, paket niteliği olmadan hook adıdır: `dw.ocapi.shop.basket.shipment.shipping_address.beforePUT`, `beforePUT` olarak export edilir. Custom bir hook'ta fonksiyon adını çağıran taraf `callHook` metoduna verir; ikisini senkron tutun:

```javascript
'use strict';

// cartridge/scripts/hooks/loyalty.js
var Logger = require('dw/system/Logger').getLogger('loyalty', 'hooks');

// app.loyalty.orderPlaced implementasyonu; dönüş değeri çağırana gider
exports.orderPlaced = function (order) {
    var points = Math.floor(order.totalGrossPrice.value);
    Logger.info('Order {0} earns {1} loyalty points', order.orderNo, points);
    return { points: points };
};
```

### Cartridge'ın bulunması gereken yer

Kodu yüklemek yetmez. [CalculateHooks referansı](https://developer.salesforce.com/docs/commerce/b2c-commerce/references/b2c-script-api/dw.order.hooks.CalculateHooks.html), hook script'inin bir site cartridge'ı içinde bulunması gerektiğini söyler; yani cartridge, isteği karşılayan sitenin cartridge path listesinde olmalıdır; tüm sitelerin paylaştığı organizasyon düzeyindeki kaynaklar için Salesforce, Business Manager sitesinin kullanılmasını söyler. Bir sitede çalışıp diğerinde çalışmayan bir hook genellikle bir cartridge path farkıdır.

---

## Çalışma sırası ve dönüş değerleri

Kurallar hook ailesine göre değişir; bunları karıştırmak yaygın bir hatadır.

### Custom hook'lar: her kayıt çalışır

SFRA hooks dokümantasyonuna göre B2C Commerce, bir extension point için **cartridge path üzerindeki tüm cartridge'larda** kayıtlı bütün hook'ları cartridge path sırasıyla çalıştırır. Tek bir `hooks.json` içinde bir extension point için birden fazla modül kaydedebilirsiniz, ama çağrılma sıralarını kontrol edemezsiniz. Tüm modüller ne döndürürse döndürsün çalışır ve çağırana **yalnızca son hook'un dönüş değeri** ulaşır.

Bunun üç sonucu var:

1. **Yeniden kaydetmek override etmez.** Daha sağdaki bir cartridge `app.validate.basket` kaydını yapıyorsa ve sizinki de yapıyorsa, ikisi de çalışır. Controller, template ve script'lerde durum tersidir: en soldaki eşleşme kazanır.
2. **Cartridge path'i yeniden sıralamak çalışma sırasını da değiştirir** ve çağıranın hangi implementasyonun dönüş değerini aldığını değiştirebilir.
3. **Sonuçları dönüş değeri üzerinden toplamayın.** Her implementasyonun içine yazdığı bir nesneyi argüman olarak geçin ve `callHook` döndükten sonra onu okuyun.

### Shopper API hook'ları: dönüş değeri zinciri bitirir

`dw.ocapi.shop.*` hook'ları için [Commerce API hooks rehberi](https://developer.salesforce.com/docs/commerce/commerce-api/guide/extensibility_via_hooks.html) tersi kuralı koyar: değer döndüren bir hook, o extension point için **sistem implementasyonunu ve sonraki tüm kayıtlı hook'ları atlar**. Metot referansı bunu "a non-null Status ends the hook execution" (null olmayan bir Status hook yürütmesini bitirir) diye ifade eder.

Varsayılan implementasyonlar gerçek iş yapar. `dw.ocapi.shop.basket.items.afterPOST` ve `dw.ocapi.shop.basket.coupon.afterPOST` gibi sepet `after*` hook'larının varsayılan mantığı örtük olarak `dw.order.calculate` hook'unu çağırır. `items.afterPOST` hook'unuzdan `new Status(Status.OK)` döndürürseniz ürün sepete eklenir ama sepet yeniden hesaplanmaz. Salesforce, işlemi durdurmak istemediğiniz sürece hiçbir şey döndürmemenizi önerir.

| Fonksiyonunuzun dönüşü | Custom hook (`app.*`) | Shopper API hook'u (`dw.ocapi.shop.*`) |
|---|---|---|
| Hiçbir şey (`undefined`) | Sonraki kayıt çalışır; çağıran son değeri alır | Sistem implementasyonu ve sonraki kayıtlar yine çalışır |
| `Status.OK` | Sonraki kayıt yine çalışır | Yürütme biter; yeniden hesaplama gibi varsayılan mantık atlanır |
| `Status.ERROR` | Sonraki kayıt yine çalışır; kararı çağıran verir | İşlem durur, transaction geri alınır, HTTP 400 |
| Exception fırlatır | `callHook` exception'ı çağırana fırlatır | Transaction geri alınır, HTTP 500 |

`dw.order.calculate` gibi sistem hook'ları, kaydınızın override ettiği bir platform varsayılan implementasyonuyla gelir. Her birini tek bir cartridge'da kaydedin; böylece cevaplanacak bir sıralama sorusu kalmaz.

### hasHook göründüğünden daha geniştir

`HookMgr.hasHook(extensionPoint)`, bir hook kayıtlıysa **ya da bir sistem varsayılan implementasyonu varsa** `true` döner; bu yüzden hiçbir cartridge kaydetmese bile `dw.order.calculate` için `true` döner. Belirli bir fonksiyonun export edilip edilmediğine değil, extension point'in kendisine bakar. Opsiyonel bir custom hook'u güvenle çağırmak için kullanın; cartridge'ınızın doğru bağlandığının kanıtı olarak değil.

---

## dw.system.HookMgr ile hook çağırmak

`callHook(extensionPoint, functionName, ...args)` hook'un sonucunu döndürür; ne kayıtlı bir hook ne de varsayılan bir implementasyon varsa `undefined` döner. Hook exception fırlatırsa `callHook` da fırlatır. Loyalty hook'u için savunmacı bir çağrı noktası:

```javascript
'use strict';

var HookMgr = require('dw/system/HookMgr');
var Logger = require('dw/system/Logger').getLogger('loyalty', 'hooks');

var LOYALTY_HOOK = 'app.loyalty.orderPlaced';

// Loyalty checkout'u asla bozmamalı; hatalar loglanır, yeniden fırlatılmaz
function notifyOrderPlaced(order) {
    if (!HookMgr.hasHook(LOYALTY_HOOK)) {
        return null; // bu sitede hiçbir cartridge implemente etmiyor
    }
    try {
        return HookMgr.callHook(LOYALTY_HOOK, 'orderPlaced', order) || null;
    } catch (e) {
        Logger.error('{0} failed for order {1}: {2}', LOYALTY_HOOK, order.orderNo, e.message);
        return null;
    }
}

module.exports = { notifyOrderPlaced: notifyOrderPlaced };
```

Exception'ları yalnızca özellik opsiyonelse yakalayın; aksi halde yayılmalarına izin verin ki transaction geri alınsın. Sistem hook'ları da aynı şekilde çağrılır: `HookMgr.callHook('dw.order.calculate', 'calculate', basket)`.

---

## SCAPI ve OCAPI hook'ları

SCAPI ve OCAPI istekleri için aynı hook'lar çağrılır. Extension point adları tarihsel `dw.ocapi.shop.*` önekini korur ve Salesforce dokümantasyonu artık OCAPI'nin kendisini deprecated olarak etiketliyor; yeni projeler için bunun ne anlama geldiğini [SCAPI ve OCAPI karşılaştırmasında](https://www.ozanaltinbas.com/tr/makale/scapi-vs-ocapi) bulabilirsiniz. Tek bir implementasyon iki API'ye de hizmet edebilir; davranışın ayrışması gereken yerde `request.isSCAPI()` ile dallanın.

### Ön koşullar ve kapsam

API hook'larını instance bazında, Business Manager'da **Administration > Global Preferences > Feature Switches** altında API hook execution seçeneğini açarak etkinleştirin; bunun için Account Manager'da *Business Manager Administrator* rolü gerekir. Shopper API'lerinin çoğu hook'ları destekler; Shopper Login (SLAS), Experience, Payments, Custom Objects ve Consents desteklemez.

### Before, after ve modifyResponse

| Hook tipi | Ne zaman çalışır | Tipik kullanım |
|---|---|---|
| `before<METHOD>` | Platform isteği işlemeden önce | Doğrulama, erişim kontrolleri |
| `after<METHOD>` | İşlemden sonra, yazma transaction'ı içinde | Veri değiştirme; hatası yazmayı geri alması gereken harici çağrılar |
| `modify<METHOD>Response` | Yanıt dönmeden önce | İstemci için `c_` property'leri eklemek |

GET istekleri `before` ve `modifyResponse` hook'larını destekler; POST, PATCH, PUT ve DELETE bunlara `after` ekler. Basket payment methods üzerindeki `afterGET` gibi istisnalar vardır ve bazı adlar `_v2` ya da `_v3` son eki taşır; bu yüzden adları ve imzaları tahmin etmek yerine [Hook Method Details](https://developer.salesforce.com/docs/commerce/b2c-commerce/guide/hook-method-details.html) sayfasından alın:

| Extension point | Endpoint (OCAPI yolu) | Argümanlar |
|---|---|---|
| `dw.ocapi.shop.basket.beforePATCH` | `PATCH /baskets/{basket_id}` | `basket, basketInput` |
| `dw.ocapi.shop.basket.shipment.shipping_address.beforePUT` | `PUT /baskets/{basket_id}/shipments/{shipment_id}/shipping_address` | `basket, shipment, shippingAddress` |
| `dw.ocapi.shop.order.afterPOST` | `POST /orders` | `order` |
| `dw.ocapi.shop.product.modifyGETResponse` | `GET /products/{id}` | `scriptProduct, doc` |

### Doğrulama hook'u

Beklenen hatalar için, makine tarafından okunabilir detaylarla `Status.ERROR` döndürün:

```javascript
'use strict';

// cartridge/scripts/hooks/address.js
var Status = require('dw/system/Status');
var addressRules = require('*/cartridge/scripts/helpers/addressRules'); // kendi modülünüz

// dw.ocapi.shop.basket.shipment.shipping_address.beforePUT
exports.beforePUT = function (basket, shipment, shippingAddress) {
    if (!addressRules.isDeliverable(shippingAddress)) {
        var status = new Status(Status.ERROR, 'ADDRESS_UNDELIVERABLE');
        status.addDetail('field', 'shippingAddress');
        return status; // HTTP 400, transaction geri alınır
    }
    // Geçerli: hiçbir şey döndürmeyin, varsayılan implementasyon yine çalışsın
};
```

SCAPI'de istemci, extension point'i adlandıran ve detaylarınızı `statusDetails` içinde taşıyan, `application/problem+json` tipinde bir HTTP 400 yanıtı alır.

### Bir modifyResponse hook'u

```javascript
'use strict';

// cartridge/scripts/hooks/product.js
// dw.ocapi.shop.product.modifyGETResponse: SCAPI ve OCAPI ürün GET isteklerinde çalışır
exports.modifyGETResponse = function (scriptProduct, doc) {
    // Yanıta yalnızca c_ önekli custom property'ler eklenebilir
    doc.c_hasBrand = !!scriptProduct.brand;
    doc.c_isMaster = scriptProduct.master;
    // Dönüş değeri yok: null olmayan bir Status hook yürütmesini bitirirdi
};
```

Bir endpoint için önbellekleme açıksa hook'un sonucu yanıtla birlikte önbelleğe alınır ve kayıt süresi dolana kadar ne sunucu mantığı ne de hook'unuz yeniden çalışır. Dolayısıyla tek bir müşteriye ya da o anki zamana bağlı her şey istek başına yeniden hesaplanmaz; bu etkileşimi [SFCC önbellekleme rehberi](https://www.ozanaltinbas.com/tr/makale/sfcc-caching) ele alıyor. Koşullu davranış için custom header değil, `c_` önekli query parametreleri (`request.httpParameterMap`) kullanın: header'lar cache key'in parçası değildir ve yalnızca tanılama amaçlıdır.

### Hook'lar arasında veri taşımak

Sepete payment instrument eklemek tek bir istekte `dw.ocapi.shop.basket.payment_instrument.beforePOST`, `afterPOST` ve `modifyPOSTResponse` hook'larını çağırır. Aralarında değer taşımak için istek boyunca yaşayan `request.custom` nesnesini kullanın. Salesforce'un örneği ödeme sağlayıcısını `afterPOST` içinde çağırır, böylece bir hata yazma işlemini geri alır; sağlayıcının referansını `request.custom` içine yazar ve `modifyPOSTResponse` içinde yanıtın bir `c_` property'sine kopyalar.

---

## Karşınıza çıkacak sistem hook'ları

### Hesaplama: dw.order.calculate

`dw.order.calculate`, sepet ve sipariş (yeniden) hesaplamasının tek noktasıdır; `dw.order.calculateShipping` ve `dw.order.calculateTax` ise CalculateHooks referansının `HookMgr` üzerinden çağrılmasını önerdiği alt adımlardır. Platform varsayılanı, deprecated API kullanım loglarına kayıt düşen deprecated `dw.ocapi.shop.basket.calculate` hook'una geri düşer. Resmi dokümantasyondakiler dahil eski örnekler hâlâ bu adı kaydediyor; siz `dw.order.calculate` kullanın.

- **SCAPI söz konusuysa transaction yok.** Salesforce, controller döneminden kalma kodda yaygın olan calculate hook'u içindeki transaction'ların SCAPI'yi bozduğu konusunda uyarır. Hook controller'lara da hizmet ediyorsa `request.isSCAPI()` ile dallanın.
- **Hızlı ve yerel tutun.** Otuz sepet ve sipariş hook'unun varsayılan mantığı onu çağırır; buradaki bir uzak çağrı neredeyse her sepet etkileşiminde tekrarlanır.

### Ödeme: dw.order.payment.*

[PaymentHooks referansı](https://developer.salesforce.com/docs/commerce/b2c-commerce/references/b2c-script-api/dw.order.hooks.PaymentHooks.html) aynı önek altında `dw.order.payment.authorize`, `authorizeCreditCard`, `capture`, `refund`, `reauthorize`, `validateAuthorization` ve `releaseAuthorization` extension point'lerini tanımlar. `authorize(order, paymentDetails)` ve `authorizeCreditCard(order, paymentDetails, cvn)` başarılı bir provizyon için `Status.OK`, başarısız bir provizyon için `Status.ERROR` döndürür.

### İstek yaşam döngüsü: onRequest ve onSession

`dw.system.request.onRequest` bir storefront isteği alındığında, `dw.system.request.onSession` yeni bir storefront oturumu başladığında çalışır. `onRequest` her storefront isteğinin yolundadır: uzak çağrı yok, ağır sorgu yok.

---

## SFRA custom hook'ları: ödeme işlemcileri ve sepet doğrulama

SFRA, takılıp çıkarılabilir checkout mantığı için custom hook'lar kullanır. Dokümantasyonu `app.payment.processor.default`, `app.payment.processor.basic_credit` ve `app.validate.basket` kaydeden bir `hooks.json` ile `HookMgr.callHook('app.payment.processor.default', 'Handle', ...)` çağrısını gösterir: her ödeme işlemcisi (payment processor) için bir extension point, her biri `scripts/hooks/payment/processor/` altında.

Bir ödeme entegrasyonu için:

- **Yeni bir processor extension point'i kaydedin**; mevcut birini yeniden kaydetmeyin. `app.payment.processor.basic_credit` kaydını tekrar yapmak ikinci bir implementasyon ekler; temeldekinin yerini almaz.
- **Base cartridge'ın sözleşmesini aynalayın.** Hook adının nasıl türetildiğini ve checkout'un hangi fonksiyonları hangi argümanlarla çağırdığını görmek için kullandığınız `app_storefront_base` sürümündeki processor script'lerini ve checkout helper'larını okuyun.

---

## dw.system.Status ile hata yönetimi

Bir [`dw.system.Status`](https://developer.salesforce.com/docs/commerce/b2c-commerce/references/b2c-script-api/dw.system.Status.html) nesnesi `new Status(Status.OK)` ya da `new Status(Status.ERROR, code, message)` ile oluşturulur, `addDetail(key, value)` ile genişletilir ve `status.error` ile `status.code` üzerinden okunur. Mesaja göre değil, koda göre dallanın: referans, bir status'u tanımlamak için `getCode()` metodunu ayırır.

Shopper API hook'larında `Status.ERROR` HTTP 400 ve rollback, yakalanmamış bir exception ise HTTP 500 ("Hook Execution Error") ve rollback üretir. Beklediğiniz her durum için ilkini döndürün ki istemci ayrıştırılabilir bir hata alsın.

**Circuit breaker.** Her extension point'in kendi [hook circuit breaker'ı](https://developer.salesforce.com/docs/commerce/b2c-commerce/references/b2c-commerce-ocapi/hookcircuitbreaker.html) vardır. En son 100 çağrının 50'den fazlası başarısız olursa açılır ve o extension point'e yapılan her çağrı 60 saniye boyunca HTTP 503 döner. Ardından half-open durumuna geçer; sonraki 10 çağrının 5'ten fazlası başarısız olursa yeniden açılır. Sık kullanılan bir yolda exception fırlatan bir hook, bir endpoint'i tüm müşteriler için devre dışı bırakabilir.

**Hatayı bulmak.** Log Center'da `category: ( com.demandware.wapi.servlet.ShopRestServlet ) AND stackTrace: ( HookInvocationException )` LCQL sorgusunu çalıştırın ya da başarısız SCAPI isteğinin correlation ID'sinden başlayın. Circuit breaker olayları için `HookCircuitBreaker` arayın ve stack trace'in `Caused by` bölümünü okuyun.

---

## Performans ve transaction tuzakları

- **Zaman bütçesi.** [Timeouts and Limits](https://developer.salesforce.com/docs/commerce/b2c-commerce/guide/timeouts-limits.html) sayfasına göre Shopper API hook yürütmesi varsayılan olarak hook başına 10 saniyedir (aşılırsa HTTP 500), Shopper API istekleri ise varsayılan 10 saniyelik gateway timeout'una tabidir (HTTP 504). İkisi de özelleştirilebilir, ama yavaş bir üçüncü taraf yine de müşterinin bütçesini harcar.
- **after hook'larında uzak çağrılar.** Bir hata veritabanı yazmasını geri alır, ama uzak sistemdeki yan etkiyi geri almaz. Bu çağrıları idempotent yapın ya da mutabakat için yeterli durumu saklayın.
- **Önce sık çalışan yollar.** `onRequest`, `dw.order.calculate` ve ürün ya da arama `modifyGETResponse` hook'ları checkout hook'larından çok daha sık çalışır. Önce onları profilleyin.

---

## Hook'ları test etmek ve hata ayıklamak

Hook script'leri CommonJS modülleridir, dolayısıyla platform dışında unit test yazabilirsiniz. [SFRA test dokümantasyonu](https://developer.salesforce.com/docs/commerce/b2c-commerce/guide/b2c-testing-sfra.html) unit testler için mocha, chai, sinon ve proxyquire'ı listeler. `dw/system/Status` ve helper modüllerinizi stub'larla değiştirmek için proxyquire kullanın ve her Shopper API hook'u için geçerli yolun `undefined` döndürdüğünü doğrulayan bir test ekleyin: bu test, code review'da en kolay bozulan kuralı kodlar. Sandbox'ta:

- Kodu debug etmeden önce feature switch'i ve sitenin cartridge path ayarını kontrol edin.
- Bir adı kaydetmeden önce path üzerindeki her `hooks.json` dosyasında arayın; tekrarlanan kayıtlara izin verilir ve hepsi çalışır.
- `Logger.getLogger('loyalty', 'hooks')` gibi ayrı bir logger'ı sabit bir önek setiyle kullanın: günlük custom log dosyası üst sınırına ulaşıldığında `getLogger` exception fırlatır.
- Hem SCAPI hem OCAPI istemciniz varsa ikisini de test edin; `request.isSCAPI()` dalları kolayca test dışı kalır.

---

## SFCC hook kontrol listesi

| Kontrol | Neden önemli |
|---|---|
| `package.json` dosyasında `hooks` anahtarı var; `script` yolları `hooks.json` dosyasına göre | Aksi halde hiçbir şey kaydolmaz ya da çözümlenmez |
| Export edilen adlar hook fonksiyon adlarıyla eşleşiyor | Platform hook'ları adı paket niteliği olmadan çağırır |
| Cartridge, sitenin path'inde (organizasyon düzeyi kod için Business Manager sitesi) | Hook script'leri bir site cartridge'ında olmalı |
| API hook execution feature switch'i açık | Aksi halde SCAPI ve OCAPI hook'ları çalışmaz |
| SCAPI'nin ulaştığı calculate hook'larında transaction yok | SCAPI'yi bozduğu dokümante edilmiş |
| Uzak çağrılar 10 saniyelik hook ve gateway varsayılanlarına sığıyor | Timeout'lar 500 ya da 504 olarak döner |
| `modifyResponse` yalnızca `c_` property'leri ekliyor, önbellekli endpoint'lerde istek başına veri eklemiyor | Önbellekten dönen yanıtlar hook'unuzu yeniden çalıştırmaz |
| Extension point, path üzerinde başka bir yerde kayıtlı değil | Custom hook'lar her kaydı çalıştırır |

---

## Önemli çıkarımlar

- Kayıt, `package.json`, `hooks.json` ve export edilen fonksiyondan oluşur; cartridge sitenin path'inde olmalıdır.
- Custom hook'lar her kaydı cartridge path sırasıyla çalıştırır; `callHook` yalnızca son değeri döndürür.
- Shopper API hook'ları ilk dönen değerde durur; başarıda hiçbir şey döndürmeyin.
- Beklenen hatalar için kodlu `Status.ERROR` kullanın; yakalanmamış exception'lar 500'e mal olur ve circuit breaker sayacına yazılır.
- `onRequest`, hesaplama ve ürün ya da arama `modifyGETResponse` hook'larını sık çalışan yol (hot path) olarak ele alın.

Tekrarlanan kayıtları, artık SCAPI'ye hizmet eden controller dönemi calculate hook'larını ya da sürekli açılan bir circuit breaker'ı denetlemek, sunduğum [SFCC mimari ve geliştirme hizmetlerinin](https://www.ozanaltinbas.com/tr/hizmet) bir parçası. İkinci bir göz isterseniz [iletişime geçin](https://www.ozanaltinbas.com/tr/iletisim).

## Ek kaynaklar

- [SFRA Hooks](https://developer.salesforce.com/docs/commerce/sfra/guide/b2c-sfra-hooks.html): kayıt formatı ve birden fazla cartridge'da çalışma sırası.
- [Customization with Hooks (SCAPI)](https://developer.salesforce.com/docs/commerce/commerce-api/guide/extensibility_via_hooks.html): before, after ve modifyResponse hook'ları, dönüş değeri kuralları, hatalar ve önbellekleme.
- [Hook Method Details](https://developer.salesforce.com/docs/commerce/b2c-commerce/guide/hook-method-details.html): tüm Shopper API extension point'leri ve imzaları.
- [Class HookMgr](https://developer.salesforce.com/docs/commerce/b2c-commerce/references/b2c-script-api/dw.system.HookMgr.html): `callHook` ve `hasHook` referansı.
