Yönlendirici, kayıt defterinin kendisidir
Hanzo Cloud'da depoya girmiş bir OpenAPI dosyası yoktur. Canlı rota tablosu kaynaktır, üç biçimde yansıtılır ve herhangi bir izdüşüm kayarsa bir birebir eşleme testi derlemeyi düşürür. İstek anında süreç başına üretilen, 963 yol üzerinde 1,362 işlem.

Bu sayfada
Hanzo Cloud deposunda bir openapi.yaml yoktur. Uçları listeleyen ikinci bir kayıt defteri, bir açıklama dosyası ve CI'de diske bir belirtim yazan bir üreteç adımı da yoktur. API'nin ne olduğunu bilmek istiyorsanız çalışan bir sürece sorarsınız; o da kendi yönlendiricisini okuyarak söyler.
Bu yazı, bunun neden ayakta kalan tek düzen olduğunu ve çalışmayan parçaları anlatır — daha yararlı yarı çıkanlar onlardır.
Bir tablo, üç izdüşüm
serve.go tek bir rota tablosu kurar. Sonra üç şey onu okur, hepsi MountAll ardından, böylece her biri tam tabloyu görür:
/zap,/v1işleyicilerini ZAP taşıması üzerinde yeniden oynatır.- Konsol onları çizer.
GET /v1/openapi.jsononları betimler.
Üçü de hiçbir şeyin kopyasını tutmaz. Tasarım kısıtı bütünüyle budur ve geri kalanı bundan çıkar. Kendi uç listesini tutan bir izdüşüm ikinci bir doğruluk kaynağı olurdu ve ikinci bir doğruluk kaynağı kayar — bazen değil, her zaman, birinin unutma sıklığının koyduğu takvimle.
Betimleyen izdüşüm insanların sorduğudur, o yüzden: openapi.Live(app), app.Fiber().GetRoutes(true) çağırır ve openapi/ içindeki diğer her fonksiyon, dönen []Route değerinin saf bir fonksiyonudur. Belge yönlendiriciden kurulmaz. Belge, başka bir biçimde, yönlendiricinin kendisidir.
Canlı yönlendiriciyi okumak neden tek tam kaynaktır
Açık alternatif kaynağı taramaktır. İşe yaramaz ve nedenini kesin söylemeye değer, çünkü bir yığın API aracının sessizce eksik bildirmesinin nedeni budur.
POST /v1/kms/auth/login şöyle kaydedilir:
Group("/v1/kms/auth").Post("/login")
Hiçbir grep o yolu bulmaz. /v1/kms/auth/login dizgesi kod tabanında yoktur. Yalnızca, çerçevenin grup önekini yaprakla birleştirmesinden sonra, çalışma anında, kurulmuş yönlendiricide vardır.
Sonra daha da kötüleşir, aslında doğru olan bir biçimde. Rota kümesi dağıtım yapılandırmasının bir fonksiyonudur — cfg.Enabled, artı KMS'in if kc != nil gibi iç kapıları. Admin'i bağlamayan bir dağıtım admin rotalarını sunmaz. O dağıtımın dürüst belirtimi de onları ilan etmez.
Belgenin CI'de bir kez kurulmak yerine süreç başına, istek anında üretilmesinin nedeni budur. CI'de kurulan bir belirtim, konuştuğunuz dağıtım olmayabilecek varsayımsal bir azami dağıtımı anlatır. Canlı yönlendiriciden okunan bir belirtim size yanıt veren süreci anlatır.
Bunu doğru kılan test
Belirtimin kayamadığı bir mimari bir iddiadır ve iddiaların bir kapıya ihtiyacı vardır. Bizimki cmd/cloud/openapi_test.go içindeki bir birebir eşlemedir:
func TestSpecDoesNotDriftFromLiveRouter(t *testing.T) {
apps.Wire() içindeki her alt sistemi bağlar, belgeyi üretir ve eşlemeyi iki yönde de ileri sürer: her canlı rota bir işlem olarak görünür ve her işlemin arkasında canlı bir rota vardır. İki yönde de bir alt küme değil.
Bugün çalıştırılınca:
bijection holds over 1362 operations / 963 paths / 138 products
Depodaki tek testtir ki başarısızlığı, yayımlanan belgenin yalan söylediği anlamına gelir. Kırılan her şey ürünü yanlış kılar; bu, sözleşmeyi yanlış kılar, ki daha kötüdür, çünkü tümleştirenler ona karşı çoktan kurmuştur.
Sayının oynaması sorun değildir — bir alt sistem eklendikçe oynar. Önemli olan sayı iki tarafın farkıdır ve o sayı sıfırdır, yoksa derleme düşer.
Ürün ekseni mekaniktir
/v1/ sonrasındaki ilk yol parçası üründür. openapi.Product onu okur ve her işlemi onunla etiketler; bir CLI'nin, bir komutun nerede yaşaması gerektiğine kimse karar vermeden hanzo <product> <resource> <verb> kurmasını sağlayan budur.
Bilerek alt sistemin adı değildir. clients/billing ayrıca /v1/finance/* sunar ve çağıranın gördüğü URL'dir, o yüzden URL kazanır. Ekseni iç pakete göre adlandırmak CLI'yi küratörlü bir eser yapardı — içinde görüşler olan, birinin sürdürmesi gereken bir şey — bir izdüşüm yerine.
Yönlendiricinin size söyleyemeyeceği
Sınır burasıdır ve etrafından dolanmayı düşünmüyoruz.
Yöntem, yol, yol parametreleri ve ürün yönlendiriciden türetilebilir. İstek ve yanıt şemaları, sorgu ve başlık parametreleri, durum kodları ve kimlik doğrulama değildir. Yönlendirici bir func(*zip.Ctx) error tutar. İstek türü, işleyici gövdesinin içindeki yerel bir değişkendir:
var req secretPutRequest
json.Unmarshal(ctx.Body(), &req)
Go, bir fonksiyon değerinden gövdesine yansıtamaz. Burada kurnaz bir onarım yoktur ve üreteçte denemek tahmin etmek olur — bir belirtim kendinden emin, yanlış girdileri böyle edinir.
Şemalara giden tek yol tipli bir işlemdir:
zip.Get[In, Out](...)
In ve Out kayıt üzerindedir, bu yüzden şema kimsenin aklını okumadan elde edilir. Ve kayıt üzerinde oldukları için aynı girdi bir MCP aracı da verir — zip/openapi.go ve zip/mcp.go tek bir kayıt defterinin iki okuyucusudur. Bu dördüncü izdüşümdür ve dördüncü bir mekanizma olmadan gelmiştir.
Göç, kurgu gereği artımlıdır: GetRoutes(), app.ops değerinin bir üst kümesidir, bu yüzden bir işleyiciyi tipli bir işleme çevirmek, onun yukarı akışında hiçbir şeyi değiştirmeden şema ekler.
Tiplenemez rotalar ve nedeni
clients/integrations, telin izin verdiği yere kadar çevrilmiştir: 41 rotadan 20'si tipli işlemdir. Diğer 21'i ham işleyici kalır ve her biri, neden taşınamadığıyla birlikte, ops_projection_test.go içindeki bir rawRoutes haritasında listelenir:
- 13 tarayıcı yönlendirmesi. OAuth geri çağrısı ve her bağ ayağı
302yanıtlar. Tipli bir işlem bir değer döndürür, birLocationbaşlığı ve 300'lerde bir durum değil. - 6 web kancası. Slack ve GitHub HMAC, Discord Ed25519, Teams Bot Framework JWT, Telegram'ın secret-token başlığı. Her biri imzayı ham istek baytları üzerinde doğrular. Tipli bir işlem çözülmüş bir
Inalır ve imzanın hesaplandığı baytları hiç görmez, bu yüzden bunları tiplemek kimlik doğrulamalarını bozardı. - 2
202 Acceptedoluşturucusu.cloud.Createdbize bir 201 dikişi verir. 202 dikişi yoktur. İki rotanın bir dikişe ihtiyacı vardır, o yüzden iki rota bekler.
Bu listenin bütün sistemdeki en değerli eser olduğunu düşünüyoruz. Soyutlamanın tam olarak nerede durduğunun, teste çakılı, sayılmış bir envanteridir; her girdi için bir gözden geçirenin tartışabileceği bir neden vardır. Önlediği bozukluk, bir rotanın sessizce ham bir işleyiciye geri kayması ve belgeden, MCP araç kümesinden ve CLI'den birden yok olmasıdır — görünmez biçimde, çünkü orada olduğunu ileri süren bir şey yoktu.
Bir mimari, genelleşen parçalar değildir. Genelleşen parçalar, artı genelleşmeyen parçaların dürüst ve zorlanmış bir hesabıdır.
Bunun aldığı şey
Hanzo Cloud'a karşı tümleştiren biri, isteklerine yanıt veren sürecin, gerçekten konuştuğu dağıtımda, birkaç milisaniye önce ürettiği bir belge okur. MCP üzerinden çağıran bir aracı, bir REST çağıranıyla aynı işleyiciye, aynı kiracı denetimiyle ulaşır — anonim bir /mcp çağrısı, REST'in verdiği aynı 403'ü alır, çünkü aynı kod yoludur ve bir test onu sabitler.
Bunların hiçbiri, birinin bir şeyi yeniden üretmeyi hatırlamasını gerektirmedi.
Genel biçim: iki eser uyuşmak zorundaysa, birini diğerinden üretip ummayın. Birini diğerinin görünümü yapın ve olmadıklarında düşen testi yazın.
Devamını oku

Cloud-Native Commerce: Why Architecture Matters
How we built Crowdstart as a cloud-native platform from day one, and why this matters for commerce.

Aracı dil modelleri çağında vitrinsiz ticaret
Alıcılar aracıya dönüşüyor. Bir dil modelinin arada insan olmadan okuyabilmesi, imzalayabilmesi ve ödeyebilmesi için gerekenler ve Hanzo'nun bugün bunun için sundukları.

Introducing Enso — one API, routed to the best frontier intelligence
Enso is Hanzo's learned router: no single frontier model leads every benchmark, so Enso routes each request to the model most likely to win it — and learns from your feedback as it goes. Microsecond routing on a CPU, a transparent per-request meter, and a 1% fee that pays for itself. Here is how it works, the measured results, and the cost-transparency angle a monolith cannot offer.