VaporからDockerで立てたMySQL8に接続する

VaporからDockerで立てたMySQL8に接続する方法です。

関連する公式ドキュメントはこちらです。
[Vapor Docs　MySQL](https://docs.vapor.codes/3.0/mysql/getting-started/)

リポジトリはこちら
[sommelier-vapor](https://github.com/O-Junpei/sommelier-vapor)

まず Docker で MySQL8 のコンテナを立てます。
以下のような `docker-compose.yml` ファイルを用意します。

```yml:docker-compose.yml
version: "3.7"

services:
  db:
    image: mysql:8.0.18
    container_name: sommelier-mysql
    environment:
      MYSQL_ROOT_PASSWORD: sommelier
      MYSQL_DATABASE: sommelier_local
      MYSQL_USER: sommelier
      MYSQL_PASSWORD: sommelier
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    ports:
      - 3306:3306
```

以下のコマンドで MySQL のコンテナを立ち上げます。

```
$ docker-compose up -d
```

立ち上げたMySQL8のコンテナの中に以下のコマンドで中に入ることができます。

```
$ mysql --host 127.0.0.1 --port 3306 -u root -p # パスワードは sommelier
$ brew upgrade mysql # mysql のクライアントが 8.x でない場合は更新が必要
```

`Package.swift` に MySQL の接続に不調なパッケージ `/vapor/mysql` を追加します。
Vapor の ORM である `/vapor/fluent-mysql` も併せて追加しました。

```
// 🔵 Swift ORM (queries, models, relations, etc) built on MySQL
.package(url: "https://github.com/vapor/mysql.git", from: "3.0.2"),
.package(url: "https://github.com/vapor/fluent-mysql.git", from: "3.1.0")
```

```
.target(name: "App", dependencies: ["FluentMySQL", "MySQL", "Leaf", "Vapor"]),
```

`Package.swift` 全文はこちらです。

```swift:Package.swift
// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "sommelier",
    dependencies: [
        // 💧 A server-side Swift web framework.
        .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),

        // 🍃 An expressive, performant, and extensible templating language built for Swift.
        .package(url: "https://github.com/vapor/leaf.git", from: "3.0.0"),

        // 🔵 Swift ORM (queries, models, relations, etc) built on MySQL
        .package(url: "https://github.com/vapor/mysql.git", from: "3.0.2"),
        .package(url: "https://github.com/vapor/fluent-mysql.git", from: "3.1.0")
    ],
    targets: [
        .target(name: "App", dependencies: ["FluentMySQL", "MySQL", "Leaf", "Vapor"]),
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: ["App"])
    ]
)
```

`Package.swift` に追加したらビルドを行い、xcode のプロジェクトファイルを再生成します。

```
$ swift build
$ vapor -y xcode
```
`configure.swift` にMySQLプロバイダーとDBのクレデンシャル情報を登録します。
MySQL8からlocalhost（セキュリティで保護されていない接続）で使用する場合は、MySQLトランスポートレイヤーセキュリティを無効にする必要があります。

参考: [MySQL & Vapor 3: unrecognized basic packet, full auth not supported](https://stackoverflow.com/questions/54304666/mysql-vapor-3-unrecognized-basic-packet-full-auth-not-supported)

```swift:configure.swift
import Leaf
import MySQL
import FluentMySQL
import Vapor

/// Called before your application initializes.
public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
    // Register providers first
    try services.register(MySQLProvider())
    // 略

    // 略

    // Configure a MySQL database
    let mysql = MySQLDatabase(config: MySQLDatabaseConfig(
        hostname: "127.0.0.1",
        port: 3306,
        username: "root",
        password: "sommelier",
        database: "sommelier_local",
        transport: MySQLTransportConfig.unverifiedTLS))

    /// Register the configured MySQL database to the database config.
    var databases = DatabasesConfig()
    databases.add(database: mysql, as: .mysql)
    services.register(databases)
}
```

`routes.swift` にMySQLのバージョンを取得するエンドポイントを作成します。

```swift:routes.swift
import Vapor

public func routes(_ router: Router) throws {
    
    struct MySQLVersion: Codable {
        let version: String
    }

    router.get("sql") { req in
        return req.withPooledConnection(to: .mysql) { conn in
            return conn.raw("SELECT @@version as version")
                .all(decoding: MySQLVersion.self)
            }.map { rows in
                return rows[0].version
        }
    }
    // 以下略
}
```

ブラウザから `http://localhost:8080/sql` にアクセスするとMySQLのバージョンを取得できます。
MySQL8 に接続することができました！

`8.0.18`