はじめに
この記事はTwilio Advent Calendar 2022の18日目の記事です
今年の10月にTwilioのGoライブラリが正式にリリースされたので、使い心地を試してみます
RESTクライントの生成
SMSの送信やTwilioのリソースへアクセスする際には認証が必要で、RESTクライアントを作成すると容易にAPIを叩くことが可能になります
以下環境変数やパラメータを指定した方法やサブアカウント、APIキーを利用したクライアントの生成方法を紹介します
環境変数を利用した初期化
// TWILIO_ACCOUNT_SIDとTWILIO_AUTH_TOKENの環境変数が認証情報として利用されるclient := twilio.NewRestClient()
パラメータを利用した初期化
accountSID := "ACXXXXXXXXXXXXXXX"authToken := "yyyyyyyyyyyyyyyyyy"client := twilio.NewRestClientWithParams(twilio.ClientParams{ Username: accountSID, Password: authToken,})
サブアカウントの初期化
accountSID := "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"authToken := "yyyyyyyyyyyyyyyyyy"subAccountSID := "ACZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"client := twilio.NewRestClientWithParams(twilio.ClientParams{ Username: accountSID, Password: authToken, AccountSid: subAccountSID,})
APIキーを利用した初期化
accountSID := "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"apiKey := "SKXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"apiSecret := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" client := twilio.NewRestClientWithParams(twilio.ClientParams{ Username: apiKey, Password: apiSecret, AccountSid: accountSID,})
パラメータとして Username
と Password
, AccountSid
を与えられるのですが、サブアカウントやAPIキーを利用する場合は、読み変えて値を設定する必要があるので、やや注意が必要です。
RESTクライアントの設定項目(edgeとタイムアウト)
初期化したRESTクライアントの設定項目としてEdgeとタイムアウトを設定することが可能です
// EdgeとしてTokyoを指定 (※TWILIO_EDGEとして環境変数が設定されていれば不要)client.SetEdge("tokyo")// APIのタイムアウト時間を設定(デフォルトではタイムアウト設定はされない)client.SetTimeout(1 * time.Second)
RESTクライアントの使い方
RESTクライアントはAccountやFlexなど各TwilioサービスごとにAPIのインタフェースを持っていて、関数を呼び出すことで各アクションが可能です
メッセージの送信
// 送信メッセージのパラメータの設定params := &openapi.CreateMessageParams{}params.SetTo("090xxxxxxxxx")params.SetFrom("050xxxxxxxx")params.SetBody("hello twilio-go!")// メッセージの送信resp, err := client.Api.CreateMessage(params)
Twilio Functionの作成
params := &twilioApi.CreateFunctionParams{}params.SetFriendlyName("My Serverless func")resp, err := client.ServerlessV1.CreateFunction(serviceSid, params)
APIの仕様についてはOPEN APIで定義されていて、必要あれば見てみてください
https://github.com/twilio/twilio-oai
データの取得(ListXXX, StreamXXX, PageXXX)
リソース一覧を取得する関数名は ListXXX
として定義されています
// メッセージ一覧の取得resp, _ := client.Api.ListMessage(params)for record := range resp { fmt.Println("Body: ", *resp[record].Body)}
非同期に複数リソースを取得したい場合、 StreamXXX
という関数名でチャネルを扱うことができます
// チャネルを利用してメッセージ一覧の取得channel, _ := client.Api.StreamMessage(params)for record := range channel { fmt.Println("Body: ", *record.Body)}
ListXXXやStreamXXXによるデータ取得はデフォルト50件となっていて、最大1000件まで取得することが可能です
https://github.com/twilio/twilio-go/blob/main/client/page_util.go#L10-L26
また、バッチで処理をする場合 PageXXX
として処理することも可能です
// ページング情報を扱う変数var currentPage, nextPageToken string// 5件ずつ処理するリクエストを生成params := &openapi.ListMessageParams{}params.SetPageSize(5)// 次ページのトークンがからになるまでループを回すfor { // ページリクエストによるバッチデータ取得 resp, _ := client.Api.PageMessage(params, nextPageToken, currentPage) for _, record := range resp.Messages { fmt.Println("Body: ", *record.Body) } // 次ページへの情報はUriとして返ってくるので必要な値のパース(ex. /2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Message.json?PageSize=5&Page=2&PageToken=PAIDc54f6171674c3fed47879caeed457ffe) u, _ := url.Parse(resp.NextPageUri) q := u.Query() currentPage = q.Get("Page") nextPageToken = q.Get("PageToken") // 次ページが無くなったら処理を終了 if nextPageToken == "" { break }}
TwiML周りの扱い
Twilio Client SDKを使って発着信をする場合、TwiMLを生成する必要があります
ここでは、①アクセストークンの生成, ②TwiMLの生成例を示します
アクセストークンの作成
アクセストークンの発行例を下記に示します
// identyを受け取ってアクセストークンの発行func genCallToken(identity string) (string, error) { tk := jwt.CreateAccessToken(jwt.AccessTokenParams{ AccountSid: env.TwilioAccountSID, SigningKeySid: env.TwilioAPIKeyID, Secret: env.TwilioAPIKeySecret, Identity: identity, }) // アクセストークンの初期化と権限設定 tk.AddGrant(&jwt.VoiceGrant{ Incoming: jwt.Incoming{Allow: true}, Outgoing: jwt.Outgoing{ ApplicationSid: env.TwilioAppSID, }, }) return tk.ToJwt()}
発行されるトークンの有効期限( TTL
)はデフォルトで1時間となっています
https://github.com/twilio/twilio-go/blob/main/client/jwt/access_token.go#L55
有効期限を変更する場合はパラメータに指定することが可能です
tk := jwt.CreateAccessToken(jwt.AccessTokenParams{ AccountSid: env.TwilioAccountSID, SigningKeySid: env.TwilioAPIKeyID, Secret: env.TwilioAPIKeySecret, Identity: identity, Ttl: 60 * 60 * 24, // 24時間 ※秒で指定する必要あり})
TwiMLの生成例
発信用のTwiMLの生成例を以下に示します
下記の例では、Twilioで購入した電話番号( to
)を利用して、 from
へ発信するTwiMLを生成します
// 発信用のTwiML生成func genOutgoingTwiML(from, to string) (string, error) { dial := twiml.VoiceDial{ Number: to, CallerId: from, Record: "record-from-answer-dual", Timeout: "50", } return twiml.Voice([]twiml.Element{dial}) // XML宣言がついた状態で文字列が生成される}
生成を行うと下記のXMLが生成されます
<?xml version="1.0" encoding="UTF-8"?><Response> <Dial record="record-from-answer-dual" timeout="50" callerId="+81 50-xxxx-xxxx">+81 90xxxxxxxx</Dial></Response>
複数のアクションを設定する場合は、生成時の可変長引数として渡すことで可能です
// 音声合成アクションsay := twiml.VoiceSay{ Message: "hello twilio-go",}// 発信アクションdial := twiml.VoiceDial{ Number: to, CallerId: from, Record: "record-from-answer-dual", Timeout: "50",}return twiml.Voice([]twiml.Element{say, dial})
まとめ&所感
公式としてGoのSDKをサポートしてくれるのは心強いですね!
呼び出し可能なAPIは関数として補間されるので、ドキュメントを調べずに色々なメソッドを呼び出せるのは非常に便利!
Goを日常的に使う身としては、関数や変数名の命名規則が公式が推奨するベストプラクティスに則っていなかったり、TwiMLのパラメータを与える時にboolや数字自体も文字列として与えなきゃいけない部分に違和感や不便を感じたり...
https://github.com/golang/go/wiki/CodeReviewComments#initialisms
とはいえ今後より使いやすい形になることに期待!