Go言語でゆるふわにYAMLを使う

# はじめに

YAMLをGo言語でパースしたり、逆に文字列に戻したりしたかったのですが、`struct`定義をせずにやる方法をまとめた記事が見当たらなかったので、忘れない内に記事にします。



サンプルのソースコードは以下に置きました。
https://github.com/segurvita/yaml-encoding-practice



# 用意したYAML

[以前の記事](https://qiita.com/segur/items/71609488d9745de998fa)で作成したswagger.yamlを再利用します。

```yaml
swagger: '2.0'
info:
  description: これはアパートに関するAPIです。
  version: 0.0.1
  title: アパートAPI
paths:
  '/rooms/{room-id}':
    get:
      summary: 部屋情報API
      description: 指定されたroom-idの情報を返します
      parameters:
        - name: room-id
          in: path
          description: 取得したい部屋のID
          required: true
          type: integer
          format: int64
      responses:
        '200':
          description: OK
          schema:
            type: object
            properties:
              id:
                type: integer
                format: int64
                example: 404
              comment:
                type: string
                example: 404号室です。どこにも存在しない部屋かも。
```



# サンプルコード

main.goの中身はこんな感じです。YAML文字列をオブジェクトに変換して、そのオブジェクトをYAML文字列に戻すということをしています。（意味はあまりありません。）

```go
package main

import "fmt"
import "gopkg.in/yaml.v2"

func main() {
	// 入力YAMLを定義
	yamlInput := []byte(`
swagger: '2.0'
info:
  description: これはアパートに関するAPIです。
  version: 0.0.1
  title: アパートAPI
paths:
  '/rooms/{room-id}':
    get:
      summary: 部屋情報API
      description: 指定されたroom-idの情報を返します
      parameters:
        - name: room-id
          in: path
          description: 取得したい部屋のID
          required: true
          type: integer
          format: int64
      responses:
        '200':
          description: OK
          schema:
            type: object
            properties:
              id:
                type: integer
                format: int64
                example: 404
              comment:
                type: string
                example: 404号室です。どこにも存在しない部屋かも。
  `)

	// YAMLをオブジェクトに変換
	var objInput interface{}
	err := yaml.Unmarshal(yamlInput, &objInput)
	if err != nil {
		fmt.Println("エラー: ", err)
	}

	// オブジェクトをYAMLに変換
	yamlOutput, err := yaml.Marshal(&objInput)
	if err != nil {
		fmt.Println("エラー: ", err)
	}

	// 標準出力
	fmt.Println("# ------------------------------------------------------------")
	fmt.Println("# 入力YAML:")
	fmt.Println("# ------------------------------------------------------------")
	fmt.Println(string(yamlInput), "\n")
	fmt.Println("# ------------------------------------------------------------")
	fmt.Println("# オブジェクト:")
	fmt.Println("# ------------------------------------------------------------")
	fmt.Println(objInput, "\n")
	fmt.Println("# ------------------------------------------------------------")
	fmt.Println("# 出力YAML:")
	fmt.Println("# ------------------------------------------------------------")
	fmt.Println(string(yamlOutput), "\n")
}
```



# 解説

YAMLの解析処理には`go-yaml`を使いました。

- `Unmarshal`がparse処理です。文字列をオブジェクトに変換します。
- `Marshal` がstringify処理です。オブジェクトを文字列に変換します。



`Unmarshal`の第二引数に`interface{}`な変数を指定することで、`struct`定義を回避しています。（便利！）

`Marshal` も特に `struct` を定義せずに使用できました。



# 出力結果

上記のコードを実行すると、以下のように出力されました。

```yaml:
info:
  description: これはアパートに関するAPIです。
  title: アパートAPI
  version: 0.0.1
paths:
  /rooms/{room-id}:
    get:
      description: 指定されたroom-idの情報を返します
      parameters:
      - description: 取得したい部屋のID
        format: int64
        in: path
        name: room-id
        required: true
        type: integer
      responses:
        "200":
          description: OK
          schema:
            properties:
              comment:
                example: 404号室です。どこにも存在しない部屋かも。
                type: string
              id:
                example: 404
                format: int64
                type: integer
            type: object
      summary: 部屋情報API
swagger: "2.0"
```

同じ階層のキーがアルファベット順でソートされてしまいましたが、内容は入力したYAMLとまったく同一でした。



# 参考サイト

以下のサイトを参考にさせていただきました。

- [golang は ゆるふわに JSON を扱えまぁす!](https://www.kaoriya.net/blog/2016/06/25/)
- [Go言語のjson.Marshal()でゆるふわにjsonを使う。](https://qiita.com/nnao45/items/8aa218d2978d3b97f8e0)
- [go-yaml/yaml](https://github.com/go-yaml/yaml)



# さいごに

意外と簡単にできて良かったです。