- That time when you thought you knew Y(A)ML โ ๐ต
- Original author: ALXIZR
- The Nuggets translation Project
- Permanent link to this article: github.com/xitu/gold-m…
- Translator: finalwhy
- Proofreader: CristoMonte, PingHGao
Do you really know anything about Y(A)ML? โ ๐ต
Thank you for reading this article about YAML files. This is a lightweight tutorial on YAML files. In this article, we’ll cover what YAML is, how to write a YAML file, and what scenarios I can use YAML files in, without going into too much detail.
Y(A)ML is A data serialization language that is A strict superset of JSON (javascript object representation). It is a structured data-oriented language that can be used as an input format for a variety of applications. We can infer from this that the language is ultimately represented as key-value pairs. The design goal of YML is to improve readability in the most straightforward way possible.
We often use tools by interacting with GUI interfaces, not realizing that behind them there is just a YAML file that stores our personalized configuration for a particular task. Today, we’ll look at some examples as we learn the language.
We have two main types in YAML: Scalar and Collection. We learned that scalars consist only of values that describe their size, a concept that has similar applications in YAML. This means that we can only hold a value with a unique key, and if we use the same key repeatedly in the file, the later assignment will overwrite the previous one. For example, if we declare a variable named “NAME” in the file and assign it the value “Joey”, then. The key value “NAME” should be unique throughout the file, and we can use it globally in the file.
# key: value
NAME: Joey
Copy the code
If we accidentally declare the variable repeatedly and give it a new value, such as “Chandler”, the last instance will overwrite its initial value.
NAME: Joey
#...
# other
# yaml
# configuration
NAME: Chandler
# When the file is parsed, only this line's definition of "NAME" is actually valid.
Copy the code
A Collection is also represented by key-value pairs, but a single key in the Collection can hold multiple values. Take the following list of names.
# list
NAMES: ["Joey"."Chandler"."Ross"."Phoebe"."Rachel"."Monica"]
Copy the code
An array of NAMES can also be represented using the following method:
# list or sequence
NAMES:
- "Joey"
- "Chandler"
- "Ross"
- "Phoebe"
- "Rachel"
- "Monica"
Copy the code
Collections in YAML can be described not only as arrays, but also as maps. Let’s take describing a person’s mailing address as an example, assuming that the address consists of a street name, street number, city, state, and zip code. Let’s see how to convert this address to YAML. For convenience, the location of a pizza hut in the United States will be selected.
# yaml object
address:
street_name: North Mathilda Avenue
street_number: 464
city: Sunnyvale
state: CA
zipcode: 94085
Copy the code
As above, we declare a key named “address” that contains multiple key-value pairs in its value. When writing YAML files, you need to be careful about indentation. When we want to combine multiple key-value pairs into a logical parent container, we must indent them with two Spaces, and the new line must be aligned vertically with the previous line, otherwise the YAML file will report an error before execution.
This particular form of description is called a “mapping”. This mapping is called “Address,” and it maintains a set of data, usually in the form of key:value. You’ll also notice that these values can be of type not only ‘String’ but also ‘Number’, including integers and floating-point numbers, as well as Booleans. Incidentally, quotes are optional for string values. We can also define date-type variables, but note that the date format must conform to the ISO 8601 specification: “YYYY-MM-DD HH: MM: SS: SSSS”.
# dates ISO 8601
some_date: 30-2018-09
some_datetime: The 2020-10-01 09:10:30
Copy the code
Because YAML files are composed of key-value pairs and are JSON supersets, we can also describe mapped objects in JSON format.
Json-style mapping objects in YAML
person: { name: "Johnny".age: 35.single: true }
Copy the code
Personally, I advise against mixing the two styles, because mixing them makes debugging for errors very bad when YML files are very long. After all, just because you can do something doesn’t mean you have to do it.
So far, we’ve talked about the various data types in YAML, with some simple examples. We’ll start with an example and talk about something complicated. In the first example, we’ll see how maps and collections are used together in YAML. Suppose I want to represent a list of people and represent this list as a collection of mapped objects. We can write it in the following format:
people:
# Method 1 - JSON-style mapping object
- { name: Alex.age: 18.single: false }
# Method 2 - YAML format mapping object
- name: Eric
age: 19
single: true
# method 3 - another YAML format mapping object, note the newline here
-
name: "Sam"
age: 22
single: true
Copy the code
In this case, we have declared a variable named “people” that maintains multiple objects with the same structure. Also notice that there are three different ways to declare variables with the same structure, but they are all equivalent to YAML. It is worth noting that we are free to nest as much as we want. For example, if the Person object has a property that describes a “hobby,” we can simply add it, creating a list object that contains a list. The following is an example.
people:
- name: Tamara
age: 20
single: true
hobbies: [movies.sports.food]
- name: Julia
age: 25
single: false
hobbies:
- movies
- sports
- food
# Notice the nesting here
-
name: Elaine
age: 29
single: false
hobbies:
- movies
- sports:
- swimming
- hiking
- dancing
- food
Copy the code
So far, we’ve covered the various data types in YAML and how to use them. Let’s take a look at some of the features that YAML supports. Suppose a YAML file has a key that needs to maintain a large amount of data, such as a description of this particular object, and we can format it in two ways. The right Angle brackets “>” operators “|” or pipes. The main difference between the two approaches is whether the parsing retains the same format as the writing. Use right Angle brackets “>” logo not retain format (translator note: namely the YAML analytical engine type, line breaks inside the multiline text will be replaced with Spaces) and use pipe “|” will keep format. We format it to make it more readable, but the YAML interpretation engine parses all the syntax into one line. Let’s take a look with practice.
# unformatted, all text on one line
car:
model: Toyota
make: 2021
description: "Awarded Green Car Journal's 2020 Green Car of the Yearยฎ, Corolla Hybrid even comes with an enhanced Hybrid Battery Warranty that lasts for 10 years from date of first use, Or 150,000 miles, tails comes first"
Copy the code
# Text marked by close Angle brackets ">" will not retain written form when parsing; Multiline text does not need quotation marks
car:
description: ">"
Awarded Green Car Journal's 2020 Green Car of the Year ยฎ,
Corolla Hybrid even comes with an enhanced Hybrid Battery Warranty that lasts for 10 years from date of first use,
or 150, 000, miles, whichever comes first
model: Toyota
make: 2021
Copy the code
# pipe "|" logo text when parsing keep writing format in, Multiline text does not need quotation marks
car:
description: "|"
Awarded Green Car Journal's 2020 Green Car of the Year ยฎ,
Corolla Hybrid even comes with an enhanced Hybrid Battery Warranty that lasts for 10 years from date of first use,
or 150, 000, miles, whichever comes first
model: Toyota
year: 2021
Copy the code
At this point, you’ve learned all the basics you need to use YAML in your daily work. We have another topic that we will discuss later. But I want to point out some nuances beforehand.
YAML also supports some of the other features we didn’t discuss in this article, for example is used to display types of labels, tuples, the string types of key name (translator note: reference, for example), group, and other functions, the reason why I choose not to discuss them because of application of these functions use cases very edge, when you need to use, you can read the official] [YAML document.
If you’d like me to demonstrate some examples, let me know, and I’ll make a separate short section highlighting these features.
YAML also has another feature called anchor points, but I often see people not using it properly for different reasons. To be honest, I don’t think anchors are scary and think the value that can be gained from using them is enormous. Anchors enable us to copy (an already declared) configuration or content, or even inherit properties throughout the file. Not only can we copy a piece of configuration, but we can also override a key already defined in an anchor when we reuse an object anchor, which makes YAML very flexible. Of course, if your YMAL files are small or just basic configuration files, there is no reason to use them. But if we assume that the content of the file will grow, then the extra effort in setting up anchor points is worth it.
We can create anchor points by “&” and refer to the specified anchor points by “*”. Anchor points are defined in the form of a key (variable) declaration, followed by the name of the anchor point starting with an ampersand, followed by the value of the key.
mykey: &myanchor myvalue
Copy the code
You should also notice that the name of the key and the name of the anchor can be different. When we want to use an anchor point, we assign the anchor point name preceded by an “*” sign as a value to another key.
anotherkey: *myanchor
Copy the code
๐ฐ – YAML anchor point 1
name: &actor Neo
movie_charachter: *actor The value of # movie_charachter will change to Neo
Copy the code
This simple example is not the most appropriate scenario in which we should use anchor points. I also want to introduce more than just the simple use of anchors. The most common scenarios I use anchors in my work include when I need to reuse a complex object with multiple attributes, or reuse some key-value pairs that shouldn’t be modified anywhere in a file. We can use the “<<” symbol before the anchor name to refer to an anchor with complex key-value pairs.
๐ฐ – YAML anchor point 2
The global CAR object
car: &base_car
year: 2021
make: Toyota
model: Corolla
color: Grey
# Reuse car objects directly without modification
corolla:
< < : *base_car
# Reuse the CAR object and override its original Model properties
runx:
< < : *base_car
model: runx
# Reuse car and override its original Model and color attributes
prius:
< < : *base_car
model: prius
color: Red
# reuse car object, overwrite its Model property, and add a new property seats that does not exist in the anchor object
camry:
< < : *base_car
model: camry
seats: 5
Copy the code
In the example above, we declared an anchor point, used it in different places in the YAML file, and customized it to varying degrees when reused. It is worth noting that even nested properties in anchors support overwriting. You can go back and read our section on nesting and implement it. By using anchor points, each mapping object can reuse the contents of the anchor object.
Let’s look at the YAML file configuration that you’re most likely to encounter in your daily work. As developers or DevOps engineers (or maybe both), we always come across YAML configurations when we need to use Docker, especially Docker Compose, and CI/CD pipelines. The following two examples are the most common.
๐ฐ – YAML Docker Compose
In this example, let’s take a look at a simple Docker compose configuration file in our local development environment:
# docker compose example
# Simple key-value pairs
version: "3"
Complex mapping objects with nested mapping objects, each representing a service in Docker Compose
services:
# service Map object
redis_sentinel:
image: redis:alpine
volumes:
- sentinel_data:/data
# service Map object
redis_worker:
image: redis:alpine
environment:
- ALLOW_EMPTY_PASSWORD=yes
volumes:
- worker_data:/data
# Another complex mapping object with nested mapping objects is the volume used to define persistent storage in docker. Docker containers are ephemeral, which means they are not designed to run forever, especially in a local development environment, which is why we need to create a volume and bind the localhost's file system to the Docker container's file system.
volumes:
# service Map object
sentinel_data:
driver: local
# service Map object
worker_data:
driver: local
Copy the code
As shown above, we have a common use case of a YAML configuration file written in a repetitive fashion. I’m sure you’re confident enough to try to rewrite the YAML configuration file yourself. Let’s give it a try:
# docker compose example
redis_service: &base_redis
image: redis
volume: null
volumes:
sentinel_data:
driver: local
worker_data:
driver: local
version: "3"
services:
sentinal:
< < : *base_redis
volume:
- sentinal_data:/data
worker:
< < : *base_redis
volume:
- worker_data:/data
environment:
- ALLOW_EMPTY_PASSWORD=yes
Copy the code
You can see that I didn’t change the global configuration of Volumes because it is docker specific and usually doesn’t need to be changed. However, we can see that overwriting doesn’t make much of a difference because this is just a very basic Docker Compose configuration file; If you add another service under Services, you will be able to see that another service will be affected. Also, the object to which the base_redis anchor points in this example is very simple, but you can imagine what the final configuration file would look like if we had 20 properties, each with its own nested properties.
๐ฐ – yaml-ci
# Travis ci
language: node_js
node_js:
- node
env:
global:
- PATH=$HOME/.local/bin:$PATH
before_install:
- pyenv global 3.71.
- pip install -U pip
- pip install awscli
script:
- yarn build
- echo "Commit sha - $TRAVIS_COMMIT"
- mkdir -p dist/@myapp/$TRAVIS_COMMIT
- mv dist/*.* dist/@myapp/$TRAVIS_COMMIT/
deploy:
provider: s3
access_key_id: "$AWS_ACCESS_KEY_ID"
secret_access_key: "$AWS_SECRET_ACCESS_KEY"
bucket: "my_project_bucket"
region: "us-west-2"
cache-control: "max-age=31536000"
acl: "public_read"
local_dir: dist
skip_cleanup: true
on:
branch: master
after_deploy:
- chmod +x after_deploy_script.sh
- "./after_deploy_script.sh"
Copy the code
As you can see, the configuration above is self-explanatory and you can see that the pattern is consistent. We use key-value pairs and most of the configuration is complex mapping objects.
That’s all you need to know about YAML. From now on, you should be able to handle YAML configuration files with more confidence, and you can even start improving existing files.
The cool tool I usually use to validate the YAML files I’m working with is one that checks spelling and configuration to make sure nothing is missing, otherwise it throws an error ๐
By the way, if you ask yourself what YAML stands for, it’s just another markup language. ๐ ๐ ๐
If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.
The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.