GraphQL iOS:Swiftアプリでクラウドファンクションを使う

この記事では、Back4appのNodeJSクラウド・コードでGraphQLを使う方法を紹介した。

そしてこのガイドでは、SwiftでApollo GraphQL iOS Clientを使う方法を紹介した。

さて、これらをまとめて、本当に簡単なコードを作成することで、複雑な操作をたくさんできるようにしよう。そして、クラスを変更しても、XCodeがAPIコードを自動生成してくれるようにしよう。

いい感じ?さぁ、コーヒーでも飲んで、さっそく始めましょう!

始める前に

Back4appのアカウントが必要です。まだお持ちでない方は、このガイドに従ってください。

役立つソフトウェア…

また、スピードアップのためにいくつかのものを使用します。

もちろん、すべて手動で行うこともできますが、特に初心者の方にはお勧めしません。
手作業でパッケージを追加することで、パッケージのメンテナンスも手作業で行う必要があり、時間が経つと面倒なことになります。

ここで紹介するパッケージマネージャを使う必要はありませんが、手動で管理する代わりに、少なくともいくつかのパッケージマネージャを使うことを強くお勧めします。前にも言ったように、手作業での管理は時間が経つと癖が出てくることがある。

iOSのパッケージ管理にはCocoapodsを使い、デスクトップの管理にはNPMを使うつもりだが、あなたの好きなものを自由に使ってほしい。

Cocoapodsのインストール方法はこのサイトにある。

NPMのインストール方法は、こちらのサイトにあります。

クラスの作成

3つのクラスを実装する予定です:オーナー、犬、犬種です。

私たちのモデルは次のことを意味します:

  • オーナーは複数の犬を持つことができます。
  • 犬は1つの犬種しか持つことができません。

プロパティは次のようになります:

  • オーナー
    • 名前 (文字列)
    • 年齢 (数字)
    • 住所 (文字列)
    • hasDogs (犬との関係。オーナーは複数の犬を持つことができる)
    • 名前 (文字列)
    • 誕生日 (日付)
    • 犬種 (犬は1つの犬種しか持たないため、犬種へのポインター)
  • 犬種
    • 名前 (文字列

これらのクラスをグラフィカルまたはプログラムで作成し、いくつかのデータを入力します。私のクラスはこのようになりました:

screen-shot-2019-08-15-at-12-08-46

犬種

screen-shot-2019-08-15-at-13-50-39

犬種

screen-shot-2019-08-15-at-12-15-45

オーナー

クラウド・コードを持ってこい、ベイビー!

クラウド・コードの時間だ。しかし、今回はそれについても深く掘り下げたいと思います。

Cloud CodeがNPMモジュールと互換性があることを話したことがあるだろうか?そうです!そして多くの時間を節約できます!

あなたが欲しいと思っていたクールな機能を、他の誰かがすでに実装しているのをご存知ですか?それがNPMモジュールなら、使えます!

このチュートリアルを使ったモジュールの使い方の記事はすでにあるので、今回の実装では、犬の誕生日を使い、月齢を計算できるようにMomentを使うことにする。

私のpackage.jsonファイルは以下のようになります:

{
      "dependencies":{
           "moment":"*"
      }
}

は最新バージョンを使うという意味です。

私のクラウド・コードは以下のようになった。よくコメントされているので、ここではあまり詳しく説明しませんが、最初の行でMoment NPMモジュールを使用していることがわかります:

// Moment NPMモジュールのインスタンス化
const moment = require('moment')

Parse.Cloud.define("retrieveOwnersOrderedByAgeDescending",async req => {」を実行します。
    /*
        この関数は、すべてのOwnersを年齢の降順で取得します。
        Ownersが存在しない場合は、空の配列が取得されます。
    */
    const query = new Parse.Query("Owner"); 
    query.descending("age")
    const results = await query.find();

    結果を返します;
});

Parse.Cloud.define("retrieveAllGermanShepherds",非同期 req => {)
    /*
        この関数は、犬種が "German Shepherd" である Dogs を取得します。
        Dogsのすべてのプロパティが取得される。
        Dogsが存在しない場合は、空の配列が取得されます。
    */
    const breedQuery = new Parse.Query("Breed");
    breedQuery.equalTo("name", "German Shepherd") 
    const query = new Parse.Query("Dog"); 
    query.matchesQuery("breed", breedQuery);
    const results = await query.find();
    結果を返します;
});

Parse.Cloud.define("retrieveDogIncludingBreedByName", async req => {.
    /*
        この関数は、犬種詳細(名前)を含む特定のDogの詳細をDog名で取得します。
        DogsとBreedのすべてのプロパティが取得されます。
        Dogsが存在しない場合はNULLが取得されます。
    */
    const query = new Parse.Query("Dog"); 
    query.equalTo("name", req.params.name);
    query.include("breed")
    const results = await query.find();
    結果を返します;
});

Parse.Cloud.define("retrieveDogsNamesWithAgesInMonths", async req => {)
    /*
        この関数は、NPMモジュールを使って誕生日をMonthsに変換したDogsの名前を取得します。
        犬の名前のみが取得され、年齢は月単位で計算される。
        Dogsが存在しない場合は空の配列が取得されます。
    */
    let dogs = [];
    const query = new Parse.Query("Dog"); 
    const results = await query.find();

    for (let i = 0; i < results.length; i ++){ // NPMモジュールのMomentを使用してMonth単位で年齢を計算します。
        // NPM モジュール Moment を使って月齢を計算する。
        let ageInMonths = moment.duration(moment().diff(results[i].get("birthday"))).humanize();
        
        newDog = {
            "dogName": results[i].get("name")、
            "dogAgeInMonths": ageInMonths
        }

        dogs.push(newDog);
    }

    return dogs;
});

私のschema.graphqlファイルは、私の4つのメソッドを公開するために次のようになりました:

拡張タイプ Query {
  getAllOwnersAgeDescending:[OwnerClass!]resolve(to: "retrieveOwnersOrderedByAgeDescending")。
  getAllGermanShepherds:[DogClass!]resolve(to: "retrieveAllGermanShepherds")。
  getThisDogWithBreed (name:String):[DogClass!]resolve(to: "retrieveDogIncludingBreedByName")。
  getDogsAgesInMonths:[DogAge!]  resolve(to: "retrieveDogsNamesWithAgesInMonths")。
}

タイプ DogAge {
    dogName:文字列!
    dogAgeInMonths:string!
}

構文がよくわからない場合は、この記事の「ちょっとひと手間」を参照してほしい。
getDogsAgesInMonthsの[DogAge!]に注目してください。システムで生成されたオブジェクトを取得するので、GraphQLが解釈するスキーマを持たないので、クライアントが解釈できるように型も作成しなければならない。

テスト…テスト…

テストの時間だ!

Parse GraphQL Consoleでクエリを実行し、結果をチェックしてみましょう:

getAllOwnersAgeDescendingのクエリ:

query{
  getAllOwnersAgeDescending{。
    名前
    年齢
    住所
  }
}

screen-shot-2019-08-16-at-09-17-50

getAllGermanShepherdsのクエリです:

クエリー {
  getAllGermanShepherds { {を取得します。
    名前
    誕生日
  }
}

screen-shot-2019-08-16-at-09-46-24

getThisDogWithBreedのクエリ:

クエリ
  getThisDogWithBreed(name: "ファイドー"){。
    名前
    誕生日
    犬種
      名前
    }
  }
}

screen-shot-2019-08-16-at-09-50-05

getDogsAgesInMonthsのクエリです:

query{
  getDogsAgesInMonths
}

screen-shot-2019-08-16-at-09-50-51

すべてうまくいった!素晴らしい!さて、次は…

XCoding

Back4appから必要なものは全て手に入れた。次はそれをXCodeで実行する番だ。

このガイドでは、XCodeを立ち上げて実行する方法を紹介したが、今回は少し高度なことをする。複数のメソッドがあり、そのうちの1つは変数を期待するものなので、少し変更を加える必要がある。

もしまだこの記事を読んでいないのであれば、ぜひ読んでみてください。

まずはアプリケーションを作成し、記事で説明されているようにApolloクライアントをインストールしましょう。

その後、Main.storyboardファイルを開き、右上のObjectsボタンをクリックし、Table ViewをView Controllerにドラッグ&ドロップします:

screen-shot-2019-08-19-at-13-00-29

角の部分をドラッグして、テーブルビューの大きさをビューコントローラのビュー全体に合わせてください:

screen-shot-2019-08-19-at-13-01-01

そして、画面右下のAdd New Constraintsボタンをクリックして、4辺の制約を作成します。4つの辺(赤いマーカー)をクリックし、[Add Constraints]ボタンをクリックして、新しい制約を割り当てます:

screen-shot-2019-08-19-at-13-01-17

さて、テーブルビューを選択した状態で(クリックして選択します)、プロトタイプセルを追加しましょう。右上のAttributes Inspectorをクリックし、Prototype Cellsボックスの0を1に置き換えます:

screen-shot-2019-08-19-at-13-01-30

ここで、新しく作成したプロトタイプセルをクリックして選択し、適切な識別子を付けます:「cell”。
このセルを識別するために、後でこの識別子を使います。

screen-shot-2019-08-19-at-13-13-07

次に、データソースとDelegateをテーブルビューからビューコントローラにリンクします。
キーボードの Control キーを押しながらテーブルビューをクリックし、ビューコントローラーの上部にある黄色いアイコン(カーソルを置くと View Controller と表示されるアイコン)にドラッグします。
そこでテーブルビューのリンクを離すと、小さなポップアップが表示されます。そのポップアップでDataSourceとDelegateの両方を選択してください:

screen-shot-2019-08-19-at-13-02-09

これで基本的なことは完了だが、Back4appからデータを取得した後、テーブルビューのリフレッシュを行う必要がある。そのためには、Outletを作成し、User Interfaceに接続する必要があります。

一番簡単な方法は、画面右上のShow Assistant Editorをクリックして、UIとコードを並べて見ることです。

次に、テーブル・ビューをコントロール・クリックして、コードにドラッグします:

screen-shot-2019-08-19-at-17-10-53

離すと、ポップアップが表示されます。離すとポップアップが表示されるので、名前を入力し、Connectをクリックします:

screen-shot-2019-08-19-at-17-08-14

これで、きれいなアウトレットが接続されました(行番号の上に小さな丸が表示されていることに注目してください):

screen-shot-2019-08-19-at-17-08-34

これで、ViewController.swiftファイルに移動できます。

GraphQLファイル

GraphQLガイドでは、GraphQLファイルの作成方法を紹介しました。今回のプロジェクトでは以下のようにしました:

クエリ findAllOwners{
    getAllOwnersAgeDescending{。
        名前
        年齢
        アドレス
    }
}

クエリ findAllGermanShepherds{
    全ドイツ語シェパードを取得する{}。
        名前
    }
}

クエリ findThisDog ($name: String!){
    getThisDogWithBreed(名前:$name){この犬種を取得します。
        名前
        誕生日
        犬種
            名前
        }
    }
}

クエリーagesInMonths{
    getDogsAgesInMonths
}

いくつかのSwiftコード

もう一度、我々はすでにこのガイドでSwiftでApolloを構成する方法をカバーしたが、今日のコードはいくつかの変更があります。
テーブルビューにデータをグラフィカルに表示するつもりなので、データソースとDelegateが実行する2つのメソッドを含める必要があります。これらのメソッドは

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int

そして

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

この2つのメソッドについては、コードに記載されているので、ここではあまり触れない。ただ、この2つのメソッドはテーブル・ビューを動作させるために必須であることを覚えておいてほしい。

完全なコードは以下のようになります:

//
// ViewController.swift
// GraphQLApollo
//
// Venomによって19/08/19に作成されました。
// 著作権 © 2019 Venom.無断転載を禁じます。
//

インポート UIKit
インポートApollo

class ViewController:UIViewController, UITableViewDelegate, UITableViewDataSource { UIViewController, UITableViewDelegate, UITableViewDataSource
    IBOutlet weak var tableView:UITableView!
    
    var list = [] as [String] // この配列は表示する値を保持する
    
    // Apolloクライアントの初期化。
    // 詳しくはこちら:https://www.back4app.com/docs/ios/swift-graphql
    let apollo:Apolloクライアント = {
        let configuration = URLSessionConfiguration.default
        configuration.httpAdditionalHeaders = [
            "X-Parse-Application-Id":"lAcIOgR0ndd7R4uMqovhNAoudpi6tMsrOI9KCuyr"、
            "X-Parse-Client-Key":"f1wwm6uWqQoxazys3QrtY4fKuQuxYvNYJmYQJP": "f1wwm6uWqQoxazys3QrtY4fKuQuxYvNYJmYQJP"
        ]
        
        let url = URL(string: "https://parseapi.back4app.com/graphql")!
        
        return ApolloClient(
            networkTransport:HTTPNetworkTransport(
                url: url、
                構成: 構成
            )
        )
    }()
    
    オーバーライド func viewDidLoad() { { viewDidLoad()
        super.viewDidLoad()
        // ビューをロードした後に、追加の設定を行います。
        
        apollo.fetch(query:FindAllOwnersQuery()) { result in
            ガード let data = try? result.get().data else { return }.
            
            for name in data.getAllOwnersAgeDescending { /各名前をリストの配列に追加します。
                //リストの配列にそれぞれの名前を追加する
                self.list.append(name.name!)
            }
            
            //以下の行は、データを取得した後、テーブル・ビューを強制的にリロードします。
            dispatchQueue.main.async { self.tableView.reloadData() } //以下の行は、データを取得した後、テーブル・ビューを強制的にリロードする。
        }
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // この関数を呼び出します。
        // この関数は、データソースとデリゲートを通してテーブルビューから呼び出されます。
        // この関数は、テーブルビューが表示するオブジェクトの数を返します。
        // テーブルビューが動作するためには必須です。
        return list.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // この関数は、データソースとデリゲートを通してテーブルビューから呼び出されます。
        // この関数は、データソースとデリゲートを通してテーブルビューから呼び出されます。
        // ストーリーボードで設定した識別子で表示されるセルを作成します。
        // テーブルビューが動作するためには必須です。
        let cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "cell")
        cell.textLabel?.text = list[indexPath.row].
        return(cell)
    }
}

実行してみよう!

コードを実行しましょう!Command + Rキーを押すと、テーブル・ビューに私たちの名前が表示されます:

screen-shot-2019-08-19-at-17-26-09

クールでしょう?
では、他のGraphQLメソッドを実行するようにコードを変更して、どのように動作するか見てみましょう!

GraphQLクエリを変更して、getAllGermanShepherdsメソッドを実行してみましょう:

    override func viewDidLoad() { スーパー.ビューロード()
        super.viewDidLoad()
        // ビューをロードした後、追加のセットアップを行います。
        
        apollo.fetch(query:FindAllGermanShepherdsQuery()) { result in
            ガード let data = try? result.get().data else { return }.
            
            print(data.getAllGermanShepherds)
            
            for name in data.getAllGermanShepherds { /各名称をシェパードの名前に追加します。
                //各名前をリストの配列に追加する
                self.list.append(name.name!)
            }
            
            //以下の行は、データを取得した後、テーブル・ビューを強制的にリロードします。
            dispatchQueue.main.async { self.tableView.reloadData() } //以下の行は、データを取得した後、テーブル・ビューを強制的にリロードする。
        }
    }

そして結果は…

screen-shot-2019-08-20-at-08-45-40

クエリに変数を渡したい場合は?

    オーバーライド func viewDidLoad() {
        super.viewDidLoad()
        // ビューをロードした後に、追加の設定を行います。
        
        apollo.fetch(query:FindThisDogQuery(name: "Fido")) { result in
            ガード let data = try? result.get().data else { return }.
            
            print(data.getThisDogWithBreed)
            
            for name in data.getThisDogWithBreed { /それぞれの名前を、私たちの犬種に適用します。
                //各名前をリストの配列に追加します。
                self.list.append(name.name!+ " - " + (name.breed?.name!)!)。
            }
            
            // 以下の行は、データを取得した後、テーブルビューを強制的にリロードします。
            DispatchQueue.main.async { self.tableView.reloadData() } //以下の行は、データを取得した後、テーブルビューを強制的にリロードする。
        }
    }

これで、ファイドがパグであることがわかった:

screen-shot-2019-08-20-at-08-52-29

新しい型を返すメソッドはどうだろう?これもテストしてみよう:

   オーバーライド func viewDidLoad() { super.viewDidLoad()
        super.viewDidLoad()
        // ビューをロードした後、追加のセットアップを行います。
        
        apollo.fetch(query:AgesInMonthsQuery()) { result in
            ガード let data = try? result.get().data else { return }.

            print(data.getDogsAgesInMonths)

            for dog in data.getDogsAgesInMonths { /各犬の名前を追加します。
                //それぞれの名前をリストの配列に追加する
                self.list.append(dog.dogName + " - " + dog.dogAgeInMonths)
            }

            // 以下の行は、データを取得した後、テーブル・ビューを強制的にリロードします。
            DispatchQueue.main.async { self.tableView.reloadData() } //以下の行は、データを取得した後、テーブル・ビューを強制的にリロードする。
        }
    } 

と結果が表示されます:

screen-shot-2019-08-20-at-10-16-21

結論

クラウド・コードはクールだ。GraphQLは超クールだ。ApolloはiOSネイティブ・アプリケーションに新しいレベルの素晴らしさをもたらす。この3つを組み合わせることで、非常に複雑なアプリケーションを最小限の労力で作成するための強力なパワーを手に入れることができる。

これで、アプリのための完全に動作するフローを作成することができ、作成が簡単で、長期にわたって維持することができるようになりました。

楽しんでいただけましたか?まだまだ続きます!ご期待ください!

Swift アプリでクラウド機能を使用するにはどのソフトウェアを使用できますか?

ご自身の選択次第です。使いやすく操作しやすいソフトウェアをお使いください。上記の実習では、以下の2つを使用しました。

– iOSパッケージ管理:Cocoapods
– デスクトップパッケージ管理:NPM

NPM の魔法とは何でしょうか?

クラウドコードはNPMモジュールと互換性があります。これは素晴らしいことです。時間を大幅に節約できるだけでなく、競合他社に対しても優位に立つことができます。つまり、クラウドコードとNPMの互換性は、あなたのビジネスを飛躍的に成長させるのです。


Leave a reply

Your email address will not be published.