ToolDeck

YAML

2 narzędzi

Formaty serializacji danych

Serializacja danych to proces przekształcania ustrukturyzowanych danych do formatu, który można przechowywać lub przesyłać, a następnie odtworzyć. Różne formaty dokonują różnych kompromisów między czytelnością dla człowieka, parsowalnością maszynową, ekspresywnością i rozmiarem pliku. Wybór odpowiedniego formatu na wczesnym etapie projektu może znacznie ograniczyć liczbę konwersji i transformacji potrzebnych w późniejszych etapach.

JSON, YAML, TOML i XML to cztery dominujące tekstowe formaty serializacji w tworzeniu oprogramowania. Każdy z nich ma mocne strony, które czynią go najlepszym wyborem w określonych kontekstach — zrozumienie tych kompromisów pozwala wybrać właściwy format do każdego zadania. W praktyce większość systemów produkcyjnych obsługuje co najmniej dwa z tych formatów jednocześnie, dlatego znajomość narzędzi do konwersji między nimi jest niezbędna.

JSON i YAML obok siebie

JSON i YAML reprezentują ten sam model danych. YAML jest ścisłym nadzbiorem JSON — każdy prawidłowy dokument JSON jest również prawidłowym dokumentem YAML. Poniżej ta sama konfiguracja wyrażona w obu formatach:

JSON
{
  "server": {
    "host": "localhost",
    "port": 8080,
    "debug": true
  },
  "database": {
    "url": "postgres://localhost/mydb",
    "pool": 10
  }
}
YAML
server:
  host: localhost
  port: 8080
  debug: true
database:
  url: postgres://localhost/mydb
  pool: 10

YAML używa wcięć zamiast nawiasów klamrowych i kwadratowych, a w przypadku większości wartości tekstowych pomija cudzysłowy. Sprawia to, że jest bardziej zwarty i czytelny dla plików edytowanych ręcznie, ale wprowadza wrażliwość na wcięcia. Dla dużych plików konfiguracyjnych różnica w czytelności jest szczególnie odczuwalna — YAML pozwala uniknąć nadmiernego zagnieżdżenia nawiasów, które utrudnia orientację w strukturze dokumentu.

Porównanie formatów

FormatCzytelnośćKomentarzeTabliceNajlepszy do
JSON★★★☆☆Brak komentarzyNatywneAPI, wymiana danych
YAML★★★★★Tak (#)NatywnePliki konfiguracyjne, IaC
TOML★★★★☆Tak (#)NatywneKonfiguracja aplikacji (Rust, Python)
XML★★☆☆☆Tak (<!-- -->)Powtarzalne elementyDokumenty, SOAP, SVG

Pułapki YAML

YAML jest potężny, ale ma dobrze znane przypadki brzegowe, które zaskakują programistów. Oto najczęstsze z nich. Wiele z tych pułapek nie powoduje błędu parsowania — parser odczyta plik pomyślnie, ale dane będą miały inny typ lub wartość niż zamierzano, co prowadzi do trudnych do wykrycia błędów.

Problem Norwegii

Naga wartość 'NO' jest interpretowana jako logiczne false w YAML 1.1. Kody krajów takie jak NO (Norwegia), OFF, FALSE, N są wszystkie parsowane jako false. W YAML 1.2 zostało to naprawione, ale wiele parserów nadal używa reguł wersji 1.1. Zawsze umieszczaj niejednoznaczne ciągi w cudzysłowach. Ten problem dotyczy nie tylko kodów krajów — skróty takie jak 'on', 'off', 'yes', 'no' w kluczach konfiguracyjnych środowisk są równie podatne na błędną interpretację.

Wrażliwość na wcięcia

YAML używa wcięć do definiowania struktury. Jedna nadmiarowa spacja lub znak tabulatora może całkowicie zmienić znaczenie dokumentu. Tabulatory są zabronione jako wcięcia w YAML — używaj wyłącznie spacji. Narzędzia do lintowania YAML, takie jak yamllint, mogą automatycznie wykrywać tego rodzaju błędy i warto włączyć je do pipeline CI/CD.

Niejawne wymuszanie typów

Nagie wartości wyglądające jak liczby, wartości logiczne lub null są automatycznie konwertowane. '1.0' staje się liczbą zmiennoprzecinkową, a '2024-01-01' staje się obiektem daty w niektórych parserach. Umieszczaj w cudzysłowach wartości, które chcesz zachować jako ciągi znaków. Szczególną ostrożność należy zachować przy numerach wersji, numerach telefonów i identyfikatorach zaczynających się od zera — YAML może je zinterpretować jako liczby ósemkowe lub dziesiętne.

Tabulatory są zabronione

Specyfikacja YAML wprost zabrania używania znaków tabulatora do wcięć. Edytory automatycznie zamieniające spacje na tabulatory po cichu uszkodzą Twój plik YAML. Skonfiguruj edytor tak, aby używał spacji w plikach YAML.

Tryby wieloliniowych ciągów

YAML ma dwa wskaźniki ciągów wieloliniowych: | (blok literalny, zachowuje znaki nowej linii) i > (blok składany, zamienia znaki nowej linii na spacje). Pomylenie ich po cichu generuje błędne wyjście.

Pętle kotwic i aliasów

Kotwice (&) i aliasy (*) w YAML umożliwiają ponowne użycie węzłów, co jest potężne, ale może tworzyć odwołania cykliczne powodujące nieskończone pętle lub wyczerpanie pamięci w naiwnych parserach. Weryfikuj YAML z kotwicami pochodzący z niezaufanych źródeł. Dobrą praktyką jest ograniczenie głębokości aliasów i testowanie parsowania plików konfiguracyjnych dostarczanych przez użytkowników w odizolowanym środowisku.

Funkcje unikalne dla YAML

Komentarze

YAML obsługuje komentarze za pomocą znaku #. To jedna z największych praktycznych zalet nad JSON w przypadku plików konfiguracyjnych — możesz dokumentować ustawienia bezpośrednio w pliku. Komentarze mogą pojawiać się w osobnej linii lub po wartości. W dużych zespołach komentarze inline są szczególnie cenne: pozwalają wyjaśnić powód danego ustawienia i wskazać dokumentację zewnętrzną bez konieczności sięgania po oddzielną wikię czy plik README.

Kotwice i aliasy

YAML pozwala zdefiniować węzeł raz za pomocą &nazwa-kotwicy i użyć go w dowolnym miejscu za pomocą *nazwa-kotwicy. Eliminuje to powtórzenia w złożonych konfiguracjach. Kubernetes i Docker Compose szeroko używają kotwic do wspólnych definicji usług. Dzięki temu mechanizmowi zmiana jednej wartości w definicji bazowej automatycznie propaguje się do wszystkich miejsc, które odwołują się do tej kotwicy, co znacznie zmniejsza ryzyko niespójności konfiguracji.

Ciągi wieloliniowe

YAML obsługuje skalary blokowe w dwóch trybach: blok literalny (|) zachowuje znaki nowej linii dokładnie tak, jak zostały wpisane — przydatny do skryptów i szablonów. Blok składany (>) zawija długie ciągi w jedną linię — przydatny do długich opisów prozą. Oba tryby obsługują także modyfikatory zachowania końcowego znaku nowej linii: domyślnie (bez modyfikatora) zachowywany jest jeden znak nowej linii na końcu, |- i >- usuwają go całkowicie, a |+ i >+ zachowują wszystkie końcowe znaki nowej linii.

Kiedy potrzebujesz konwersji

Konfiguracja pipeline CI/CD

GitHub Actions, GitLab CI i CircleCI używają natywnie YAML. Kiedy programowo generujesz konfiguracje pipeline, często łatwiej jest zbudować obiekt JSON i przekonwertować go do YAML jako końcowe wyjście. Podejście to sprawdza się szczególnie dobrze w narzędziach, które dynamicznie komponują etapy pipeline na podstawie danych z bazy lub parametrów uruchomienia — generowanie JSON jest prostsze w większości języków programowania niż bezpośrednie budowanie wcięciowej składni YAML.

Manifesty Kubernetes

Zasoby Kubernetes są definiowane w YAML, ale szablonowanie Helm chart i niektóre narzędzia generują JSON. Konwersja między formatami pozwala analizować odpowiedzi API i korzystać ze standardowych narzędzi JSON. Polecenie kubectl obsługuje oba formaty bezpośrednio — możesz przekazać plik JSON lub YAML do kubectl apply, co ułatwia integrację z narzędziami generującymi różne formaty wyjściowe.

Przetwarzanie odpowiedzi API

REST API zwracają JSON. Kiedy podajesz te dane do systemów konfiguracyjnych opartych na YAML (Ansible, Salt, Kubernetes), konwerter wypełnia lukę bez ręcznego reformatowania.

Migracja konfiguracji

Migracja z jednego narzędzia do drugiego często oznacza konwersję formatu konfiguracji. Konwersja między JSON i YAML pozwala szybko przenosić się między ekosystemami (Node.js → Python, Docker → Kubernetes).

Przepływ pracy walidacji schematu

Narzędzia JSON Schema są bardziej dojrzałe niż YAML Schema. Powszechnym wzorcem jest pisanie konfiguracji w YAML dla czytelności, konwersja do JSON w celu walidacji względem schematu, a następnie konwersja z powrotem do wdrożenia. Biblioteki takie jak Ajv (JavaScript) czy jsonschema (Python) oferują pełną obsługę JSON Schema Draft 7 i nowszych, co czyni tę metodę niezawodnym sposobem na wykrycie błędów konfiguracyjnych przed wdrożeniem.

Wymiana danych z API

Wewnętrzne narzędzia mogą konsumować konfiguracje YAML, podczas gdy zewnętrzne API wymagają JSON. Konwerter w pipeline budowania utrzymuje obie reprezentacje zsynchronizowane bez potrzeby utrzymywania zduplikowanych plików.

Często zadawane pytania

Czy YAML jest nadzbiorem JSON?

Tak. YAML 1.2 jest ścisłym nadzbiorem JSON — każdy prawidłowy dokument JSON jest również prawidłowym dokumentem YAML. Jednak YAML 1.1 (nadal używany przez wiele parserów) ma kilka przypadków brzegowych, gdzie prawidłowy JSON nie jest prawidłowym YAML 1.1. W praktyce oznacza to, że warto sprawdzić wersję specyfikacji obsługiwaną przez parser używany w danym projekcie, zanim założysz pełną zgodność w obie strony.

Dlaczego wybrać YAML zamiast JSON dla plików konfiguracyjnych?

YAML obsługuje komentarze, czego JSON nie robi. YAML jest też bardziej zwarty dla głęboko zagnieżdżonych struktur. Te dwie właściwości czynią go preferowanym wyborem dla ręcznie edytowanych plików konfiguracyjnych (Docker, Kubernetes, GitHub Actions). Dodatkowym argumentem jest możliwość korzystania z kotwic i aliasów, które pozwalają unikać powtarzania tych samych bloków konfiguracji w wielu miejscach pliku.

Czym jest TOML i kiedy go używać?

TOML (Tom's Obvious Minimal Language) jest zaprojektowany dla plików konfiguracyjnych. Ma przejrzystą składnię podobną do INI z jawnymi typami i bez niejednoznaczności. Jest standardem dla projektów Rust (Cargo.toml) i Python (pyproject.toml). Jeśli Twój projekt jest pisany w jednym z tych języków i nie wymaga głębokiego zagnieżdżenia ani obsługi przez zewnętrzne narzędzia oczekujące YAML, TOML może być prostszym i bezpieczniejszym wyborem.

Czy konwersja JSON do YAML może powodować utratę informacji?

Rzadko, ale potencjalnie tak. JSON zachowuje kolejność kluczy w większości parserów (choć specyfikacja mówi, że jest nieuporządkowany). YAML obsługuje kotwice i znaczniki, które nie mają odpowiedników w JSON. Dla zachowania wierności konwersji w obie strony trzymaj się wspólnego podzbioru. Warto też pamiętać, że YAML pozwala na użycie kluczy nieciągowych (np. liczb lub wartości logicznych jako kluczy mapowania), co nie ma bezpośredniego odpowiednika w JSON i może prowadzić do utraty danych przy konwersji.

Co powoduje pojawienie się 'undefined' w wyjściu JSON?

JSON.stringify konwertuje wartości undefined na null w tablicach i pomija je w obiektach. Jeśli widzisz nieoczekiwane wartości null lub brakujące klucze w wyjściu JSON, obiekt JavaScript źródłowy prawdopodobnie zawierał właściwości undefined. Aby wykryć takie przypadki przed serializacją, warto sprawdzić obiekt narzędziem takim jak JSON.stringify z funkcją replacer lub użyć biblioteki walidacji schematu.

Czy można używać JSON wewnątrz pliku YAML?

Tak. Ponieważ YAML jest nadzbiorem JSON, możesz osadzać składnię JSON bezpośrednio wewnątrz dokumentu YAML. Czasem robi się to dla złożonych zagnieżdżonych struktur, gdzie wcięcia YAML byłyby mylące. Mieszanie obu składni w jednym pliku jest jednak odradzane w kodzie produkcyjnym — utrudnia czytelność i może mylić narzędzia do podświetlania składni oraz lintowania.