Help us understand the problem. What is going on with this article?

30分で終わる「iOSアプリの通信入門」 with "GAE/Go"

More than 1 year has passed since last update.

こんな人向け

  • 自作アプリ専用のWebAPIを作りたい
  • SwiftとGoで通信処理を実装してみたい
  • Google App Engineを使ってみたい

何をするの?

WebAPIを自作し、iOSからそのAPIを叩いてデータを取得する」を簡潔に行う。
GETをメインに書きましたが、POSTも書いてます。

サーバーサイド(GAE/Go)

公式チュートリアル

まずはこれを終える。
チュートリアルの指示に従って、ハローワールドを出すだけです。
エラーに出くわしたら、多分PATHまわりだと思います。
vim ~/.bashrcでbashrcを開き、

export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
export PATH=$PATH:$HOME/Downloads/google-cloud-sdk/bin

みたいに設定しておきましょう。
編集したら、source ~/.bashrcの実行を忘れずに。

チュートリアルを終えれば準備万端!
こっからが楽しい本番!!(30分かかんないはず!)

APIを自作

1) 先ほどの、チュートリアルのhelloworldプロジェクトに移動する
2) go get github.com/gin-gonic/ginginをダウンロードする 1
3) hello.goに以下をコピペ

hello.go
package hello

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

type User struct {
        ID           string `json:"id"`
        Name         string `json:"name"`
        Introduction string `json:"introduction"`
}

// 初期化
func init() {
    http.Handle("/", GetEngine())
}

// APIのルーティング
func GetEngine() *gin.Engine {
    router := gin.Default()
    router.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "yea! rootだね!")
    })
    router.GET("/api/users/:id", GetUser)
    router.POST("/api/users", SaveUser)
    return router
}

// Userをjsonで返す
func GetUser(c *gin.Context) {
    // パラメータを抽出
    id := c.Param("id")
    // Userを生成
    u := User{
        ID:           id,
        Name:         "jsonてすと君",
        Introduction: "ハロー iOSさん",
    }
    // jsonとして返す
    c.JSON(http.StatusOK, u)
}

// Userをデータストアに保存する
func SaveUser(c *gin.Context) {
    u := User{}
    // POSTで渡ってきたjsonを構造体に埋め込む
    c.BindJSON(&u)

    // >> 本来はここでデータストアへの保存処理などを行う。今回は省略。 <<

    // 今回はただ出力するだけ
    c.String(http.StatusOK, "SaveUser Success. %+v", u)
}

4) dev_appserver.py app.yamlを実行し、ブラウザで「localhost:8080/」を見てみる。→「yea! rootだね!」を確認
5)ブラウザに 「localhost:8080/api/users/好きな数字」を打ち込み、jsonが返ってくることを確認。
以下は「localhost:8080/api/users/1」の例
スクリーンショット 2018-01-24 21.51.19.png
感動ですね!!

クライアント(iOS/Swift)

XcodeでSingle Viewのプロジェクトを作り、ViewController.swiftに以下をコピペ

ViewController.swift
import UIKit

// jsonの変換先となる構造体(初期値あり)
struct User : Codable {
    var id           : String = "0"
    var name         : String = "加賀鉄男"
    var introduction : String = "将棋が強い"
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // サーバーからUser情報を取得
        let user = getUser()
        // Userを出力してみる
        print("GETの結果: ", user)

        // サーバーにPOSTしてみる
        postUser()
    }

}

func getUser() -> User {
    // 情報の欲しいユーザーIDを指定
    let id = 1
    // URLを指定(今回はローカルサーバー)
    let url = URL(string: "http://localhost:8080/api/users/\(id)")!

    let decoder: JSONDecoder = JSONDecoder()

    do {
        // jsonを取得
        let data = try Data(contentsOf: url, options: [])
        // User構造体に値を埋め込む
        let user = try decoder.decode(User.self, from: data)
        return user
    } catch {
        print(error)
        return User()
    }
}

func postUser() {
    // URLを指定(今回はローカルサーバー)
    let url = URL(string: "http://localhost:8080/api/users")!

    // POSTリクエストを生成
    let request = NSMutableURLRequest(url: url)
    request.httpMethod = "POST"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")

    // POSTで渡したいパラメータを生成
    let params:[String:Any] = [
        "id": "789",
        "name": "postテストさん",
        "introduction": "Hello Go I'm Post",
        ]

    // それをjsonとして生成し、httpBodyに付加
    do {
        let json = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
        request.httpBody = json
    } catch {
        print("Error:\(error)")
        return
    }

    // POSTリクエストを発行
    let task = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: {data, response, error in
        if error != nil {
            print("Connection Error: ", error!)
            return
        }
        if let httpResponse = response as? HTTPURLResponse {
            let result = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)!
            if httpResponse.statusCode != 200 {
                print(httpResponse)
            }
            print("POSTの結果:", result)
        }
    })
    task.resume()
}

さあ、シュミレータを起動してみましょう!
スクリーンショット 2018-01-29 17.53.30.png

最高ですね!!!

データストアについて

本記事はデータストア処理を省略しています。
実際の開発では、GETでデータストアのデータを取得したり、POSTでデータストアにデータを保存したりするはずです。
その際は、GAE/GoのDatastoreチートシート with "goonライブラリ"が参考になれば嬉しいです。

真にローカルから抜け出すには?

チュートリアルにもあるように、hello.goのあるディレクトリでgcloud app deploy app.yamlを実行するだけで、GCP上にデプロイされます。
あとは、swiftのURL指定部分を任意のURLに変えるだけです

なお、料金については小規模なら無料です。

おわりに

このような一連の流れをまとめた記事があまりなかったので、筆者なりに書いてみました。
30分以上かかってたらごめんなさい:bow_tone1:


  1. もちろん入れなくても書けます。最近はgorilla系の方が人気ぽい 

sensuikan1973
Flutter+GCP/Firebase. Othello player.
https://github.com/sensuikan1973
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした