0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

VaporAdvent Calendar 2019

Day 4

VaporからDockerで立てたMySQL8に接続し、Leafで表示する

Last updated at Posted at 2020-01-16

前回の記事 VaporからDockerで立てたMySQL8に接続する では Vapor から Docker に立てた MySQL に接続するところまで実装しました。
今回の記事では、接続したデータベースから値を取り出し、テンプレートエンジンである Leaf で使っていこうと思います。

リポジトリはこちら O-Junpei/sommelier-vapor

まず Docker で立てた MySQL にテーブルを作成し、検証用のデータを追加します。
IT企業の技術ブログをまとめを作りたいので、企業ブログの記事の情報が入る article テーブルを作成します。

01_ddl.sql
create table article(
    article_id int(11) not null auto_increment,
    title varchar(255),
    article_url varchar(255),
    site_name varchar(255),
    site_url varchar(255),
    primary key (article_id)
);

サンプルデータとして、以下の6記事を追加します。

02_data.sql
SET CHARACTER_SET_CLIENT = utf8mb4;
SET CHARACTER_SET_CONNECTION = utf8mb4;

insert into article (article_id, title, article_url, site_name, site_url)
values (1, 'Amazon Elasticsearch ServiceをつかったRDSのスロークエリの集計と監視', 'https://techlife.cookpad.com/entry/2019/12/27/000000', 'クックパッド開発者ブログ', 'https://techlife.cookpad.com');

insert into article (article_id, title, article_url, site_name, site_url)
values (2, 'プロと読み解くRuby 2.7 NEWS', 'https://techlife.cookpad.com/entry/2019/12/25/121834', 'クックパッド開発者ブログ', 'https://techlife.cookpad.com');

insert into article (article_id, title, article_url, site_name, site_url)
values (3, 'センサクッキング 技術検証とユーザー体験検証', 'https://techlife.cookpad.com/entry/2019/12/18/110000', 'クックパッド開発者ブログ', 'https://techlife.cookpad.com');

insert into article (article_id, title, article_url, site_name, site_url)
values (4, '[小ネタ]WorkSpacesのディレクトリが消せないし理由も分からない?そんな時はAWS Directory Serviceを見てみよう', 'https://dev.classmethod.jp/cloud/aws/how-to-delete-ad-for-workspaces-and-find-the-cause/', 'クラスメソッド発「やってみた」系技術メディア | Developers.IO', 'https://dev.classmethod.jp');

insert into article (article_id, title, article_url, site_name, site_url)
values (5, '[レポート] 可観測性は AI ・メトリクス・ログの幸せな結婚を夢見るか? AIOps の雄、Moogsoft の CEO が語る #AIM310 #reinvent', 'https://dev.classmethod.jp/cloud/aws/201912-report-reinvent-2019-aim310/', 'クラスメソッド発「やってみた」系技術メディア | Developers.IO', 'https://dev.classmethod.jp');

insert into article (article_id, title, article_url, site_name, site_url)
values (6, '[レポート] Container Insight, FireLens, AppMesh を使ってコンテナ環境 (ECS/EKS/Fargate) の可観測性を向上させる #CON328 #reinvent', 'https://dev.classmethod.jp/cloud/aws/201912-report-reinvent-2019-con328/', 'クラスメソッド発「やってみた」系技術メディア | Developers.IO', 'https://dev.classmethod.jp');

01_ddl.sql02_data.sqlinitdb ディレクトリに入れ、initdb ディレクトリ は /docker-entrypoint-initdb.d ディレクトリ としてマウントするようにしました。
こうすることで、MySQL コンテナ作成時に2つの .sql ファイルがコンテナの新規作成時に実行されます。

docker-compose.yml
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
    volumes:
      - ./Database/initdb:/docker-entrypoint-initdb.d

参考: DockerHub MySQL Initializing a fresh instance

article テーブルに対応する Article クラスを作成します。
entity プロパティにテーブル名を設定し、カラム名と同名のプロパティを作成します。

Article.swift
import FluentMySQL
import Vapor

struct Article: Decodable, MySQLModel {
    var id: Int?
    static let entity = "article"  // テーブル名

    var article_id: Int?
    var title: String?
    var article_url: String?
    var site_name: String?
    var site_url: String?
}

extension Article: Content { }
extension Article: Migration { }

CodingKeys を使用することで、カラム名と異なるプロパティ名にすることもできます。

Article.swift
import FluentMySQL
import Vapor

struct Article: Decodable, MySQLModel {
    var id: Int?
    static let entity = "article"  // テーブル名
    
    var articleId: Int?
    var title: String?
    var articleUrl: String?
    var site_name: String?
    var siteUrl: String?
    
    private enum CodingKeys: String, CodingKey {
        case articleId = "article_id"
        case title = "title"
        case articleUrl = "article_url"
        case site_name = "site_name"
        case siteUrl = "site_url"
    }
}

extension Article: Content { }
extension Article: Migration { }

参考:
Models - Vapor Docs
Option to convert to snake_case

作成した Articleクラスの設定を configure.swift で行います。

configure.swift
/// Configure migrations
var migrations = MigrationConfig()
migrations.add(model: Article.self, database: .mysql)
services.register(migrations)

このこと関連する内容の記事を書いてくださった方がおりますので紹介します。
本番運用するアプリでモデルの自動マイグレーションを使ってはいけない  

これで MySQL のデータを簡単に扱うことができます。

file.png

ArticleController.swift
import Vapor
import FluentMySQL

final class ArticleController {
    static func blogs(req: Request) throws -> Future<[Blog]> {
        let cookpadArticles: Future<[Article]> = Article.query(on: req).filter(\.site_url == "https://techlife.cookpad.com") .all()
        let classmethodArticles: Future<[Article]> = Article.query(on: req).filter(\.site_url == "https://dev.classmethod.jp") .all()

        let blogs = map(cookpadArticles, classmethodArticles) { (cookpadArticles, classmethodArticles) -> ([Blog]) in
            let cookpadBlog = Blog(name: "クックパッド開発者ブログ", url: "https://techlife.cookpad.com", articles: cookpadArticles)
            let classmethodBlog = Blog(name: "クラスメソッド発「やってみた」系技術メディア | Developers.IO", url: "https://dev.classmethod.jp", articles: classmethodArticles)
            return [cookpadBlog, classmethodBlog]
        }
        return blogs
    }
}
routes.swift
import Vapor

public func routes(_ router: Router) throws {

    // 2chmm page
    router.get { req -> Future<View> in
        return try req.view().render("2chmm", [
            "blogs": ArticleController.blogs(req: req)
        ])
    }
}
2chmm.leaf
#set("title") { 技術ブログまとめ }

#set("body") {
    <ul>
    #for(blog in blogs) {
        <li>
          <a href="#(blog.url)"><h1>#(blog.name)</h1></a>
          <ul>
            #for(article in blog.articles) {
              <li><a href="#(article.article_url)">#(article.title)</h1></a></li>
            }
          </ul>
        </li>
    }
    </ul>
}

#embed("base")

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?