Teknik yaklaşım
Nasıl yazıyorum
Aşağıdakiler tercih değil, sahada bir kere kaybedip öğrenilmiş kurallar. Hepsi bir hataya mal olmuş; bu yüzden istisnasız uygulanıyor.
İlkeler
API sürümü koda gömülü kalmaz
Shopify API'si dönemsel sürümler yayınlıyor ve her sürüm sınırlı süre destekleniyor. Uygulama bir sürüme kilitlenir, yükseltme planlı yapılır. Sürüm adı kodun içine dağılmışsa bir gün sessizce kırılır — tek yerden yönetilir.
Hız limiti baştan hesaba katılır
Admin GraphQL API sorgu maliyeti hesaplayıp bütçeye göre sınırlıyor. Toplu işlerde sayfa sayfa gezmek yerine toplu işlem uçları kullanılır; sınıra yaklaşıldığında geri çekilme ve yeniden deneme mantığı kurulur.
Her webhook doğrulanır, her işlem idempotent yazılır
Gelen isteğin imzası uygulama gizli anahtarıyla doğrulanmadan hiçbir şey işlenmez. Aynı olay birden çok kez gelebilir; ikinci işlem bir şey değiştirmemeli.
Kapsam dar istenir
İstenen her erişim kapsamının kullanıldığı yer gösterilebilmeli. Geniş kapsam hem incelemede geri döner hem mağaza sahibini tedirgin eder. Yeni kapsam gerektiğinde yeniden yetkilendirme istenir.
Toplu iş loglanır ve geri alınabilir
İş gruplar hâlinde yürür, her adım satır satır log dosyasına yazılır, yarıda kalırsa kaldığı yerden devam eder. Değişen alanların eski değerleri kimlikleriyle saklanır.
Doğrulama kaynağın kendisinden yapılır
Başarı çıktısına güvenilmez: yazılan değişiklik geri çekilip aranır. Sayfa önbelleği kaynakla aynı değildir; doğrulama panelden ya da API'den yapılır, tarayıcıdan değil.
Silmeden önce yönlendirme kurulur
Koleksiyon, sayfa ya da ürün silinecekse önce 301 kurulur, sonra silinir, sonra yönlendirmenin çalıştığı doğrulanır. Sıra bu değilse adres bir süre 404 verir.
Ölçüm CSS okuyarak değil, tarayıcıdan yapılır
Hangi kuralın kazandığı özgüllük yarışıyla belirlenir; kaynağa bakarak tahmin etmek yanıltır. Konum ve boyut değerleri çalışan sayfadan okunur.
Webhook imzası doğrulanmadan hiçbir şey işlenmez
const gelen = req.get('X-Shopify-Hmac-Sha256') || '';
const hesaplanan = crypto
.createHmac('sha256', process.env.SHOPIFY_API_SECRET)
.update(hamGovde, 'utf8')
.digest('base64');
const a = Buffer.from(hesaplanan, 'base64');
const b = Buffer.from(gelen, 'base64');
// uzunluk farkliysa timingSafeEqual firlatir, once onu ele
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).send();
}
İmza doğrulaması olmayan bir webhook ucu, herkesin veri yazabildiği açık bir kapıdır.
Boş render eden blok bırakmamak
{%- comment -%}
Isaret ettigi kayit yoksa blok hic basilmaz.
Bos render eden blok aylarca fark edilmez.
{%- endcomment -%}
{%- assign hediye = all_products[section.settings.hediye_handle] -%}
{%- if hediye != blank and hediye.available -%}
<div class="hediye" data-esik="{{ section.settings.esik }}">
<p>{{ section.settings.mesaj }}</p>
</div>
{%- endif -%}
Bir mağazada silinmiş bir ürüne işaret eden hediye bloğu aylarca sessizce boş basmıştı. Koşul olmadan yazılan her referanslı blok aynı riski taşır.
Shopify tarafında çalıştığım yüzeyler
Mevcut kurulumunuz bu ölçütleri karşılıyor mu?
Bakıp ne gördüğümü yazayım — mağazanın adresi yeterli.