Badanie kontraktowe
1) Gdzie stosować umowy
HTTP REST/JSON: zasoby, paginacja, filtry, idempotencja, kody błędów.
gRPC/Protobuf: rodzaje wiadomości, statusy, semantyka „termin”, kompat wsteczny v.proto.
GraphQL: schematy, inne niż nieważne, dyrektywy, dopuszczalne dla pól.
Wiadomości/strumienie (Kafka/Pulsar/SQS): schematy wydarzeń (Avro/JSON/Protobuf), klucze partycji, zamówienia, klucze idempotentne.
Wewnętrzne SDK/Biblioteki: Cechy publiczne/Wyjątki/Umowy wykonania.
2) Model CDC: Role i artefakty
Konsument publikuje umowę oczekiwań (przykładowe wnioski/odpowiedzi, matchery typu, niezmienne).
Dostawca przeprowadza weryfikację kontraktu przeciwko swoim usługom/adapterom/obsługującym.
Broker kontraktowy (Pact Broker/Backstage/repo artifact) przechowuje wersje, tagi ('prod',' staging ',' canary ') i' consumer @ v → provider @ v 'matrix kompatybilności.
Zasady udostępniania: wysyłanie dostawcy jest zabronione, jeśli jakakolwiek „prod-istotna” umowa jest naruszona.
3) Co naprawić w umowie (przykład HTTP)
Minimum:- Metoda/ścieżka/parametry/nagłówki (w tym Auth, klucz idempotentny).
- Korpus i typowe matchery (typ/format/regexp/zakresy).
- Kody błędów i struktura; stabilny 'error _ code'.
- Niezmienne semantyczne: sortowanie, wyjątkowość, monotonia „created _ at”.
- Oczekiwania niefunkcjonalne (opcjonalne): p95, limity rozmiarów, nagłówki limitów prędkości.
json
{
"interaction": "GET /v1/users/{id}",
"request": { "method": "GET", "path": "/v1/users/123", "headers": {"Accept":"application/json"} },
"matchers": {
"response.body.id": "type:number",
"response.body.email": "regex:^.+@.+\\..+$",
"response.body.created_at": "format:rfc3339"
},
"response": {
"status": 200,
"headers": {"Content-Type":"application/json"},
"body": {"id": 123, "email": "alice@example.com", "created_at": "2025-10-31T12:00:00Z"}
},
"error_cases": [
{
"name":"not_found",
"request":{"path":"/v1/users/9999"},
"response":{"status":404, "body":{"error_code":"USER_NOT_FOUND"}}
}
]
}
4) Umowy oparte na zdarzeniach
Schemat zdarzeń: 'type', 'version', 'id',' occurred _ at _ utc', 'manufacturer', 'subject', 'payload'.
Niezmienne: niezmienność 'id' i idempotencja przez' (typ, id) ', kolejność w ramach klucza części, monotoniczna' sekwencja '.
Schemat Registry-Stores zasady ewolucji i kompatybilności (do tyłu/do przodu/do końca).
Testy umów konsumenckich: powtórzyć „złote” wydarzenia i fazy negatywów (nieznane pola, nieznane).
json
{
"type":"record","name":"UserRegistered","namespace":"events.v1",
"fields":[
{"name":"id","type":"string"},
{"name":"occurred_at_utc","type":{"type":"long","logicalType":"timestamp-millis"}},
{"name":"email","type":"string"},
{"name":"marketing_opt_in","type":["null","boolean"],"default":null}
]
}
5) Ewolucja i kompatybilność
Wersje kontraktowe: semantyka „MAJOR”. DROBNE. PATCH '(MAJOR - łamanie).
Zasady dotyczące REST:- Nie łamać: nie usuwać pól, nie zmieniać typu/wartości „error _ code”.
- Dodaj opcjonalne pola z domyślnym; nowe punkty końcowe zamiast „magii”.
- Zmniejszenie: deklaracja, jednoczesne wsparcie, skreślenie według mierników.
- GraphQL: pola dodawane tylko, nieważne wchodzą przez fazy; obniżenie dyrektyw.
- gRPC/Proto: nie należy ponownie używać numerów pól; dodać tylko nowe z opcjonalnym.
- Wydarzenia: program "vN'; konsumenci muszą ignorować nieznane dziedziny (łagodzenie kar).
6) Kontrole negatywne i niezmienne
Negatywne: nieprawidłowe typy, zakazane wartości, sprzeczne parametry, przekraczające limity.
Niezmienne: sortowanie odpowiedzi, unikalność 'id', poprawność' next _ cursor ', stabilność reakcji idempotentnej po powtórzeniu.
Umowy o charakterze tymczasowym: „created _ at” RFC3339/UTC, prawidłowa projekcja dni lokalnych nie jest częścią umowy transportowej - jest przekazywana stałym firmom.
7) Wytwarzanie pchnięcia i rozwój lokalny
Z umów, dostawcy stosy są generowane dla rozwoju konsumentów.
Dla zdarzeń - generatory wiadomości „ważne/pograniczne” zgodnie z schematem.
Personel jest oznaczony wersją umowy i datą budowy; publikacja w prod.
8) Wbudowanie w CI/CD (rurociąg referencyjny)
1. Konsument CI:
Lint/build → generacja zamówienia → jednostka/umowa testowa → publikacja w kontrakcie-broker (tag: 'consumer @ 1. 7. 0`).
2. Dostawca CI:
Podniesienie usługi lokalnie/w kontenerze → pobierz odpowiednie umowy ("prod'/" staging") → weryfikacja → publikacja statusu w brokerze.
3. Brama uwolnienia:
Rozmieszczenie dostawcy jest zablokowane, jeśli istnieją zaległe umowy.
4. Nightly Matrix:
matryca zgodności „wersje konsumenckie × wersje dostawców”; raporty i alarmy.
9) Przykłady praktyk według domen
9. 1 ODPOCZYNEK: paginacja kursora (umowa niezmienna)
Odpowiedź zawiera 'items []', 'next _ cursor' (nullable), 'limit', 'total' (opcjonalnie).
Niezmienne: 'len (items) ≤ limit', powtarzane wywołanie z tym samym 'cursor' → idempotent set.
Błąd, jeśli 'cursor' i 'page' są określone.
9. 2 Idempotencja POST
Kontrakt wymaga nagłówka „Idempotency-Key”.
Niezmienne: Powtarzające się zapytanie z tym samym kluczem zwraca ten sam 'id'/status.
9. 3 Wydarzenia: gwarancje porządku
Kluczem partycji w umowie jest 'partition _ key = user_id'.
Niezmienne: „sekwencja” zwiększa się monotonicznie w obrębie klucza; konsument musi załatwić powtórki.
10) Bezpieczeństwo i prywatność w umowach
Nie włączaj danych osobowych/tajemnic do przykładów - tylko syntetyki.
Naprawić obowiązkowe nagłówki zabezpieczeń: „Autoryzacja”, „X-Signature”, „Replay-Prevention”.
W przypadku haków internetowych - umowa podpisania i odpowiedzi „2xx ”/przekaźniki.
W dziennikach testów kontraktowych - maskowanie pól wrażliwych.
11) Narzędzia
Pakt/Pactflow/Pact Broker - HTTP/Umowy wiadomości, matryca kompatybilności.
OpenAPI/AsyncAPI - dane techniczne + generatory testowe (Dredd, Schemathesis).
Karate/REST Assured - scenariusz kontroli umów REST.
Protobuf/gRPC - 'buf', 'protolint', badania zgodności; Schemat rejestru Avro/JSON/Proto w strumieniach.
Testy zgodności dla GraphQL (graphql-compat), badania obwodów migawek.
12) Pseudokoda weryfikacji dostawców (uproszczona)
python def verify_contract(provider, contract):
for case in contract["cases"]:
req = build_request(case["request"])
res = provider.handle(req) # локально/контейнер assert match_status(res.status, case["response"]["status"])
assert match_headers(res.headers, case["response"].get("headers", {}))
assert match_body(res.body, case["matchers"], allow_extra_fields=True)
for neg in contract.get("error_cases", []):
res = provider.handle(build_request(neg["request"]))
assert res.status == neg["response"]["status"]
assert res.json.get("error_code") == neg["response"]["body"]["error_code"]
13) Anty-wzory
„Zrzuty ekranu listonosza są umową”: brak wersji/typowych matcherów/automatyczna walidacja.
Oversnapping: kontrakt naprawia dokładne wartości zamiast typów/wzorów → false falls.
Jeden wspólny kontrakt dla różnych regionów/kanałów: ignoruje zmienność (flagi, geo-reguły).
Kontrakty bez brokera/matrycy: niemożliwe jest zrozumienie, które wersje są kompatybilne.
Postaw na e2e zamiast kontraktów: powolne, drogie, niestabilne.
Brak przypadków negatywnych/niezmiennych: testowany jest tylko „zielony tor”.
14) Obserwowalność i działanie
Status eksportu do brokera + deska rozdzielcza „umowy zdrowotne”.
Ostrzeżenia: nowe spadki w dostawcy przed kontraktami "prod', wzrost" nieznanego pola "w wydarzeniach.
Trace: 'contract _ id',' version ',' decision _ id' w dziennikach weryfikacji.
15) Proces depresji
1. Dodaj pole/punkt końcowy (bez złamania).
2. Zaznaczyć stare jako „przestarzałe” w specyfikacji, ogłosić daty.
3. śledzenie konsumentów za pomocą dzienników/brokera; przewodników migracyjnych.
4. Włącz odmowę „cienia” na etapie (dry-run), a następnie wymuś.
5. Usuń po zerowym użyciu i kompatybilności.
16) Lista kontrolna architekta
1. Zidentyfikowano konsumentów i ich właścicieli? Kontrakty są zmieniane?
2. Czy istnieje broker i matryca kompatybilności ze znacznikami środowiskowymi?
3. Czy w umowie zawarte są negatywy i niezmienne (idiempotencja, kursory, sortowanie)?
4. Czy rejestr schematu i tryb kompatybilności są skonfigurowane dla zdarzeń?
5. Rurociąg blokuje zwolnienie dostawcy w przypadku naruszenia umów produkcyjnych?
6. Czy opisano proces depresji i politykę ewolucji?
7. Pchnięcia są generowane z kontraktów, czy są lokalne generatory wydarzeń?
8. Czy maskowanie PD i obowiązkowe pozycje bezpieczeństwa są udokumentowane?
9. Metryka/wpisy dotyczące umów są połączone, czy są raporty dryfujące?
10. Umowy są weryfikowane w CI przez obie strony (konsumenta i dostawcę)?
Wniosek
Testowanie kontraktów przenosi „prawdę” o interakcjach do wersjonowanych artefaktów i sprawia, że integracje są przewidywalne. CDC, broker kontraktów i dyscyplina ewolucji programu zastępują „przełamywanie niespodzianek” zarządzanym procesem: szybkie kontrole, wyraźne niezmienne i przejrzysta kompatybilność wersji. Zmniejsza to koszt e2e, przyspiesza wydania i poprawia jakość całej platformy.