https://d226lax1qjow5r.cloudfront.net/blog/blogposts/how-to-send-sms-messages-with-swift-and-vapor-using-async-await/2fa_swift-vaporasync-1.png

SwiftとVaporで非同期/待機を使ってSMSメッセージを送信する方法

最終更新日 November 19, 2021

所要時間:1 分

Swift 5.5は、完了ハンドラの必要性を取り除くことによって、同時実行Swiftコードの可読性を向上させるのに役立つasync/await言語機能を導入しています。この投稿は、以下と非常に似ています。 Swift、Vapor、VonageでSMSメッセージを送信する方法に非常に似ています。この投稿では メッセージ API V1を使用しますが、async/awaitを使用することによる改善を説明する良い方法です。

元のブログ記事をご存知の方は、「SMSを送信する」セクションまで読み飛ばしていただいて結構です。

前提条件

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

  • Xcode 13およびSwift 5.5以上。

  • 蒸気ツールボックス ツールボックスをインストールしてください。

ベーパープロジェクトの作成

Vaporプロジェクトを作成するには、ターミナルでnew projectコマンド vapor new AsyncTextMessageを使います。最初にFluentを使うかどうか(スキップするには nを押してスキップしてください)、次にLeafを使うかどうか尋ねられます。 Leafは動的な HTML ページを生成するために使うテンプレート言語です。 yを押します。コマンドが終了したら、ディレクトリを変更して cd AsyncTextMessage.

また .envファイルを作成する必要があります。ターミナルで、以下のコマンドを使用してファイルを作成します。 XYをそれぞれ API キーとシークレットに置き換えてファイルを作成します:

echo "APIKEY=X \nAPISECRET=Y" > .env

これで、Xcodeでプロジェクトを開くことができます。 vapor xcodeコマンドを使って開きます。Xcodeが開いたら、Swift Package Manager (SPM)を使ってVaporの依存関係をダウンロードし始めます。依存関係を見るには Package.swiftファイルを開きます。

デフォルトでは、Xcode はランダムなローカルディレクトリからアプリケーションを実行します。ローカルリソースをロードするので、カスタム作業ディレクトリを設定する必要があります。Product > Scheme > Edit Scheme...と進み、作業ディレクトリをプロジェクトのルートフォルダに設定します。

Setting custom working directory

CMD+Rを押してビルドし、実行する。完了したら、あなたのウェブページを localhost:8080.

ウェブページの作成

プロジェクトがセットアップされたので、SMS用の電話番号とメッセージを入力するためのインターフェースを作成します。Resources/Viewsの下にある index.leafファイルを開き、更新します:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Send a text message</title>
  </head>

  <body>
    <h1>Send a text message using the Vonage Messages API</h1>

    #if(messageId):
      <p> Successful SMS ID: #(messageId)</p>
    #endif

    <form action="/send" method="post">
        <p>
        <label>Phone number E.g. 447000000000</label><br>
        <input type="text" name="to">
        </p>

        <p>
        <label>Text message</label><br>
        <textarea name="text"> </textarea>
        </p>
        <button type="submit">Send text</button>
    </form>
  </body>
</html>

上記のコードでは、電話番号とメッセージを入力するフォームを追加している。 POSTリクエストを /send.で始まるリーフブロックに注目してください。if(messageId):.変数 messageId変数の値をチェックし、設定されていればページにテキストを追加します。ビルドして実行(CMD + R)すると、更新されたページが表示されます。

モデル構造体を作成する

Vaporを使うことの利点は、Swift言語の型安全性を利用できることだ。プロトコルに準拠するものを使って、サーバーへの入力と出力をモデル化することができます。 Codableプロトコルに準拠した入出力をモデル化することができます。 Contentプロトコルがあります。

という構造体を作る。 Inputという構造体を作成する。 Contentに準拠した routes.swiftファイルの最下部に適合する

struct Input: Content {
    let to: String
    let text: String
    let from = "SwiftText"
    let channel = "sms"
    let messageType = "text"

    private enum CodingKeys: String, CodingKey {
        case to
        case text
        case from
        case channel
        case messageType = "message_type"
    }
}

Vonage Messages APIではフィールドの大文字と小文字が区別されるため、構造体にはCodingKeys列挙型を使用してプロパティ名を大文字と小文字の対応にマッピングします。Input構造体の下に、Messages APIから期待される応答用の別の構造体を作成します:

struct Response: Content {
    let messageId: String
    
    private enum CodingKeys: String, CodingKey {
        case messageId = "message_uuid"
    }
}

SMSを送信する

SMSを送信するには、Vonage Messages APIを呼び出す必要があります。そのためには /sendルートを定義し、フォームデータを解析し、リクエストを行う必要があります。まず routes関数で新しいルートを定義します:

app.post("send") { req async throws -> View in
    do {
        let input = try req.content.decode(Input.self)
    }
}

このメソッドでは req async throws -> View in.これは、関数が非同期であり、エラーを投げる可能性があることを意味する。したがって doブロックの内部では、ウェブフォームのフィールドを Input構造体にデコードしています。クロージャは View.これは、以前はfutureを返さなければならず、それが最終的に View.

次に、Vaporの クライアントAPI を使って Messages API を呼び出します。送信ルートに呼び出しを追加します:

app.post("send") { req async throws -> View in
    do {
        let input = try req.content.decode(Input.self)
        
        let clientResponse = try await req.client.post("https://api.nexmo.com/v1/messages") { req in
            try req.content.encode(input, as: .json)
            let auth = BasicAuthorization(
                username: Environment.get("APIKEY")!,
                password: Environment.get("APISECRET")!
            )
            req.headers.basicAuthorization = auth
        }
        
        let messageResponse = try clientResponse.content.decode(Response.self)
        
        return try await req.view.render(
            "index",
            ["messageId": "\(messageResponse.messageId)"]
        )
    }
}

上記のコードでは、Messages APIをコールした結果を待ちます。 clientResponseにはその結果がセットされる。これにより、あたかも同期的であるかのようにコードを書くことができる。また、コードは doブロックの中にあるので、エラーが発生しても自動的にスローされ処理されます。 catchを追加して自分で処理することもできる。

次の行は、Messages APIからのレスポンスをデコードし、最後にそれを使ってページをレンダリングする。ここでも try awaitを使うので req.view.renderが完了すると Viewインスタンスを返すか、エラーをスローします。

試してみる

プロジェクトをビルドして実行(CMD + R)し、ブラウザで localhost:8080ブラウザで開き、電話番号とメッセージを入力する。

Sending a message via the web page

送信ボタンをクリックすると、先ほど定義したルートにデータが送信され、Vonage Messages APIへの呼び出しが行われ、成功するとメッセージIDが表示されます。

The web page showing a successful message ID

次はどうする?

完成したプロジェクトは 完成したプロジェクトは GitHub.

WhatsappやFacebook Messengerでのメッセージ送信など、Messages APIでできることはまだまだあります。詳しくは 開発者プラットフォーム.

シェア:

https://a.storyblok.com/f/270183/400x400/19c02db2d3/abdul-ajetunmobi.png
Abdul AjetunmobiVonage 元チームメンバー

アブドゥルはVonageのデベロッパー・アドボケイト。iOSエンジニアとして消費者向け製品に携わった経歴を持つ。余暇には、サイクリング、音楽鑑賞、技術者としての道を歩み始めたばかりの人々の指導を楽しんでいる。