Perfectを使って、Swiftでサーバーサイドプログラミング3 - MySQLに接続


##目次

・[Perfectを使って、Swiftでサーバーサイドプログラミング1 - 導入](http://qiita.com/s0hno/items/cbc595837a24e7523908)
・[Perfectを使って、Swiftでサーバーサイドプログラミング2 - Hello PerfectをWebページに表示](http://qiita.com/s0hno/items/ca2aa414e5951e67301a)
・[Perfectを使って、Swiftでサーバーサイドプログラミング3 - MySQLに接続](http://qiita.com/s0hno/items/462d4aaf191039b0aa1c)←イマココ

##はじめに

前回、サーバー立ち上げて、サイトにHello Perfectを表示できたので、今回はローカルのMySQLに接続して、DBとTableの作成、データの読み込みと書き込みの部分をやりたいと思います。

##MySQLプロジェクトを追加

メニューからFile > Add Filesを選択。

![スクリーンショット 2016-05-20 2.40.03.png](https://qiita-image-store.s3.amazonaws.com/0/24465/38d6c03b-7c5d-531a-5237-31d5f982c3f6.png "スクリーンショット 2016-05-20 2.40.03.png")

[Perfectを使って、Swiftでサーバーサイドプログラミング1 - 導入](http://qiita.com/s0hno/items/cbc595837a24e7523908)でダウンロードしたPerfectLibの中にMySQLのプロジェクトが入っているので、選択して追加します。

![スクリーンショット 2016-05-20 2.40.45.png](https://qiita-image-store.s3.amazonaws.com/0/24465/982906fc-95c2-011d-56e3-98966e45095f.png "スクリーンショット 2016-05-20 2.40.45.png")

HelloPerfectプロジェクトにMySQLを追加します。

![スクリーンショット 2016-05-20 2.41.47.png](https://qiita-image-store.s3.amazonaws.com/0/24465/65e57f08-ac4b-155e-8686-afeb29a4c3a2.png "スクリーンショット 2016-05-20 2.41.47.png")

##MySQL設定

次にHost名やDB名などを設定します。
HelloPerfectHandler.swiftのPerfectServerModuleInit()メソッドの上あたりにでも以下をコピーしてhogeの値を書き換えてください。

```
private let DB_HOST = "127.0.0.1"  //localhost
private let DB_USER = "hoge"       // MySQLユーザー名
private let DB_PASSWORD = "hoge"   // MySQLパスワード
private let DB_NAME = "hoge"       // 新しく作成するDB名
private let DB_TABLE_NAME = "hoge" // 新しく作成するTable名
```

##DBとTableを作成する

・[Perfectを使って、Swiftでサーバーサイドプログラミング2 - Hello PerfectをWebページに表示](http://qiita.com/s0hno/items/ca2aa414e5951e67301a)で追加したHelloPerfectHandler.swift内のIndexHandlerクラスのhandleRequestメソッド内に以下のコードを記述。

```
let mysql = MySQL()
let connected = mysql.connect(DB_HOST, user: DB_USER, password: DB_PASSWORD)
guard connected else {
    print(mysql.errorMessage())
    return  
}
        
defer {
	mysql.close()
}

//DB,Tableがなければ作成する
var schemaExists = mysql.selectDatabase(DB_NAME)
if !schemaExists {
	schemaExists = mysql.query("CREATE SCHEMA \(DB_NAME) DEFAULT CHARACTER SET utf8mb4;")
}
        
let tableSuccess = mysql.query("CREATE TABLE IF NOT EXISTS \(DB_TABLE_NAME) (id INT(11) AUTO_INCREMENT, Content varchar(255), PRIMARY KEY (id))")
        
guard schemaExists && tableSuccess else {
	print(mysql.errorMessage())
	return
}
```

[http://0.0.0.0:8181/](http://0.0.0.0:8181/)にアクセスした際にDBとTableが作成されてなければ、作成するようにしています。

##DBにデータを追加する

次に、[http://0.0.0.0:8181/post/投稿したい文字列](http://0.0.0.0:8181/post/投稿したい文字列)にアクセスした際に「投稿したい文字列」をDBにInsertするために、PerfectServerModuleInitメソッド内にRoutingを追加します。

```
Routing.Routes["GET", "/post/{content}"] = { (_:WebResponse) in return PostHandler() }
```

urlの{content}の部分に入る文字列は、次に作成するPostHandlerメソッド内で

```
request.urlVariables["content"]
```

とすると取得できます。

では、[http://0.0.0.0:8181/post/投稿したい文字列](http://0.0.0.0:8181/post/投稿したい文字列)にアクセスした際のHandlerを作成しましょう。
HelloPerfectHandler.swift内に以下クラスを追加。

```
class PostHandler: RequestHandler {
    
    func handleRequest(request: WebRequest, response: WebResponse) {
        let reqData = request.urlVariables["content"]!
        
        // MySQLに接続
        let mysql = MySQL()
        let connected = mysql.connect(DB_HOST, user: DB_USER, password: DB_PASSWORD)
        guard connected else {
            print(mysql.errorMessage())
            response.setStatus(500, message: "Server Error")
            response.requestCompletedCallback()
            return
        }
        
        // DBを選択
        mysql.selectDatabase(DB_NAME)
        
        defer {
            mysql.close()
        }
        
        // Insert query発行(DB_TABLE_NAMEのContentカラムにreqDataを追加)
        let querySuccess = mysql.query("INSERT INTO \(DB_TABLE_NAME) (Content) VALUES ('\(reqData)')")
        guard querySuccess else {
            print(mysql.errorMessage())
            response.setStatus(500, message: "Server Error")
            response.requestCompletedCallback()
            return
        }
        
        response.appendBodyString("Sccess!! Insert \(reqData)")
        response.setStatus(201, message: "Created")
        response.requestCompletedCallback()
    }
    
}
```

これでDBに追加できます。処理が成功したら以下のように表示されるはずです。

![スクリーンショット 2016-05-21 12.15.50.png](https://qiita-image-store.s3.amazonaws.com/0/24465/4709b82b-0a5c-6d12-b5c9-f64674f070a4.png "スクリーンショット 2016-05-21 12.15.50.png")


##DBからデータを読み込む
次に先ほど格納したデータを読み込んでみます。
[http://0.0.0.0:8181/get](http://0.0.0.0:8181/get)にアクセスするために、PerfectServerModuleInitメソッド内にRoutingを追加します。

```
Routing.Routes["GET", "/get"] = { (_:WebResponse) in return GetHandler() }
```

次にHandlerを追加します。

```
class GetHandler: RequestHandler {
    
    func handleRequest(request: WebRequest, response: WebResponse) {
        
        // MySQL接続
        let mysql = MySQL()
        let connected = mysql.connect(DB_HOST, user: DB_USER, password: DB_PASSWORD)
        guard connected else {
            print(mysql.errorMessage())
            response.setStatus(500, message: "Server Error")
            response.requestCompletedCallback()
            return
        }
        
        // DB選択
        mysql.selectDatabase(DB_NAME)
        defer {
            mysql.close()
        }
        
        // SELECT query発行（DB_TABLE_NAMEのContentカラムから10件取得）
        let querySuccess = mysql.query("SELECT Content FROM \(DB_TABLE_NAME) LIMIT 10")
        guard querySuccess else {
            print(mysql.errorMessage())
            response.setStatus(500, message: "Server Error")
            response.requestCompletedCallback()
            return
        }
        
        // resultsのカウントが0件ならリターン
        let results = mysql.storeResults()!
        if results.numRows() == 0 {
            print("no rows found")
            response.setStatus(500, message: "Server Error")
            response.requestCompletedCallback()
            return
        }
        
        // 値を配列にする
        var contents = [String]()
        results.forEachRow { row in
            contents.append(row[0])
        }
        
        //JSONを文字列にしてAppendBodyStringに追加
        do {
            let data = try NSJSONSerialization.dataWithJSONObject(["content": contents], options: .PrettyPrinted)
            let string = NSString(data: data, encoding: NSUTF8StringEncoding)
            
            response.appendBodyString(string as! String)
            response.addHeader("Content-Type", value: "application/json")
            response.setStatus(200, message: "OK")
        } catch {
            response.setStatus(500, message: "Server Error")
        }
        
        response.requestCompletedCallback()
        
    }
    
}
```

処理がうまくいったらこんな感じで取得できます。

![スクリーンショット 2016-05-21 12.16.28.png](https://qiita-image-store.s3.amazonaws.com/0/24465/687915a2-75f2-50fc-6f4e-64e23a4b7cc4.png "スクリーンショット 2016-05-21 12.16.28.png")


##おわり

MySQLへのデータ取得、追加は思ったよりもシンプルにできた。
次はクライアント側の操作で取得、追加をしてみたい。

##Sample
・[Perfectを使って、Swiftでサーバーサイドプログラミングシリーズの
SampleCode](https://github.com/s0hno/HelloPerfect)