[PYTHON] Présentation du mécanisme Twilio # 3-1 - Procédure pas à pas de mise en œuvre de la passerelle API API + Lambda (partie 1)

Cet article est une continuation de l'article suivant. Nous vous recommandons de lire ceci en premier. Compréhension du mécanisme Twilio # 1 --Introduction Twilio # 2-Comprendre le mécanisme

Passer un appel depuis Twilio Client / Nous mettrons en place une application pour passer un appel vers Twilio Client. Étant donné que le montant sera important, nous le diviserons en deux parties. Le contenu suivant est destiné à ceux qui ont une certaine expérience du développement sur AWS, en particulier ceux qui ont développé et publié des API en combinant AWS Lambda et API Gateway. Si vous n'avez aucune expérience, nous vous recommandons de combiner les deux pour créer une API et de la publier pour en avoir une idée.

―― 1. Introduction ―― 1. Définition de la structure de base et des termes lors de l'utilisation de Twilio ―― 2. Environnement vérifié cette fois ―― 2. Structure des données de flux de communication ―― 1. Transfert de jeton d'authentification / capacité ―― 2. Appel (appel entrant) depuis un téléphone externe vers un client Twilio ―― 3. Appel du client Twilio vers un téléphone externe (OutgoingCall) --3-1. ** Procédure pas à pas de mise en œuvre d'AWS API Gateway + Lambda (partie 1) ** ** ← Maintenant ici **

Présentation de la procédure pas à pas

Reconfirmons les spécifications du client Twilio qui seront réalisées cette fois.

--Ce que tu peux faire --Depuis Twilio Client, vous pouvez passer un appel téléphonique général en spécifiant n'importe quel numéro (appel sortant)

On suppose que les paramètres tels que le numéro de téléphone sont les suivants.

Paramètres valeur Explication / Remarques
Numéro de téléphone Twilio 050-3123-4567 Le numéro de téléphone attribué au client Twilio. Veuillez acheter à l'avance sur la console Twilio.
Client Name DeviceId_0001 Le nom utilisé pour identifier et contrôler le client Twilio dans le serveur Twilio.
Téléphone externe 090-5987-6543 Téléphone à l'extérieur de Twilio. Veuillez utiliser votre propre téléphone portable.

Reconfirmons la configuration réalisée cette fois. TwilioDiagrams_Fig1-1.png

Implémentez chaque API à l'aide d'AWS Lambda et créez-la pour qu'elle puisse être utilisée à partir d'API Gateway. Le nom de l'API, le nom de la fonction Lambda et le nom de la ressource API Gateway correspondent comme suit.

Nom de l'API Nom de la fonction AWS Lambda Nom de la ressource
API d'acquisition de jetons de capacité TwilioRetrieveCapabilityToken /twilio/retrieve_capability_token
API de retour TwiML pour les appels entrants TwilioRetieveTwimlCallIncoming /twilio/retrieve_twiml/call_incoming
API de retour TwiML pour les appels sortants TwilioRetieveTwimlCallOutgoing /twilio/retrieve_twiml/call_outgoing

Chaque API sera déployée à l'étape de production à API Gateway. Par conséquent, API Server fournira éventuellement l'URL suivante.

Le client Twilio implémenté en JavaScript a l'écran suivant. À partir de cet écran, vous pouvez passer un appel vers un téléphone ordinaire et recevoir un appel téléphonique régulier. twilio_client_webbrowser.png

Le travail de configuration lié à Twilio est [Ouvrir et préparer un compte Twilio](http://qiita.com/tmiki/items/ac28b6f6ad745f3e1b2e#twilio%E3%82%A2%E3%82%AB%E3%82%A6%E3% 83% B3% E3% 83% 88% E3% 81% AE% E9% 96% 8B% E8% A8% AD% E6% BA% 96% E5% 82% 99).

Le travail spécifique lié à AWS est le suivant. On suppose que vous avez déjà ouvert un compte AWS.

―― 1. Implémentation du traitement API Server (Python sur AWS Lambda) --1-1. Implémentation et déploiement de l'API d'acquisition CapabilityToken en tant que fonction Lambda --1-2. Implémentation et déploiement de l'API de retour TwiML pour les appels entrants en tant que fonction Lambda --1-3 Implémentez et déployez l'API de retour TwiML pour les appels sortants en tant que fonction Lambda. --2 paramètres de la passerelle API --2-1. Créez une API à partir du menu Amazon API Gateway dans AWS Management Console ―― 2-2. Définir la ressource pour chaque API --2-3. Définir CORS --2-4. Définir la méthode pour l'API d'acquisition CapabilityToken (/ twilio / retrieve_capability_token) --2-5. Définir la méthode pour l'API de retour TwiML (/ twilio / retrieve_twiml / call_incoming) pour les appels entrants --2-6. Définir la méthode pour l'API de retour TwiML (/ twilio / retrieve_twiml / call_outgoing) pour les appels sortants ―― 2-7. Prod Créer une scène et déployer ―― 2-8. Vérifiez le fonctionnement de chaque API ―― 3. Implémentation et déploiement de Twilio Client --3-1. Implémentation du client Twilio avec JavaScirpt --3-2. Créer un compartiment S3 et activer l'hébergement de site Web statique --3-3. Placer sur le seau S3 ―― 4. Contrôle de fonctionnement! --4-1. Accédez au client Twilio sur S3 avec un navigateur Web via HTTPS --4-2. Appelez le client Twilio à partir d'un numéro de téléphone vérifié ―― 4-3. Appeler un numéro de téléphone vérifié depuis Twilio Client

Regardons chacun de ce qui suit.

1. Implémentation du traitement API Server (Python sur AWS Lambda)

L'API créée lors de cette vérification est implémentée en Python sur AWS Lambda. Si vous êtes nouveau sur Lambda, il est conseillé de suivre les étapes de la documentation ci-dessous pour avoir une idée de ce à quoi il ressemble.

Guide du développeur AWS Lambda - Mise en route https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/getting-started.html

Comme vous pouvez le voir en l'utilisant, JSON est le plus simple à utiliser comme format d'entrée / sortie de la fonction Lambda. Par conséquent, la fonction implémentée cette fois utilise aussi JSON autant que possible.

1-1. Implémenter l'API d'acquisition CapabilityToken en tant que fonction Lambda

Interface (entrée / sortie)

Tout d'abord, déterminez les structures d'entrée et de sortie de cette fonction Lambda. Tel que défini dans Certification / Capability Token transfer Faisons-en la structure de.

Input


{"twilioPhoneNumber": "+81-50-1234-9876"}

Le client Twilio suppose qu'un numéro de téléphone Twilio lui est associé dans le code source. Cette API s'authentifie en vérifiant uniquement si le numéro de téléphone Twilio spécifié dans Input est enregistré.

Output


{"capabilityToken": capabilityToken, "success": true}

Si l'authentification réussit, cette API générera un jeton de capacité. Il renvoie également le succès ou l'échec du processus.

la mise en oeuvre

Écrivons maintenant la fonction Lambda.

TwilioRetrieveCapabilityToken.py


from __future__ import print_function
from twilio.util import TwilioCapability

print('Loading function')


class UnregisteredPhoneNumberException(Exception):
    def __init__(self,value):
        self.value = value


def get_client_name_by_phone_number (phone_number):
    ''' This function returns a valid clientName.
        If the parameter "phone_number" is not registered, this function raise an "UnregisteredPhoneNumberException".
    '''

    # regularize the input string "phone_number" to match registered phone numbers.
    phone_number_wo_hyphen = phone_number.replace('-','')

    # match and get the correct clientName
    if (phone_number_wo_hyphen == "+8150312345678"):
        clientName= "DeviceId_0001"

    else:
        raise UnregisteredPhoneNumberException('Unregistered phone number "' + phone_number + '"')

    return clientName


def lambda_handler(event, context):
    ''' Creates and responds a Twilio Capability Token.
    This function will be received a json formatted string like below.
    {"twilioPhoneNumber": "+81-50-1234-9876"}

    This function will return a json formatted string like below.
    If this function succeed, the parameter "success" will be set as true.
    {"capabilityToken": capabilityToken, "success": true}
    '''

    # configure parameters belong to Twilio
    twilio_account_sid = "{{twilio_accound_sid}}"
    twilio_auth_token = "{{twilio_account_auth_token}}"
    twilio_app_sid = "{{twilio_app_sid}}"
    expiration_time_for_capability_token = 3600


    # get necessary parameter from "event" and "context"
    twilio_phone_number = event.get("twilioPhoneNumber")


    # Create a Capability token with twilio_account_sid and its twilio_auth_token
    # It enables a Twilio client to receive an incoming call and to make an outgoing call.
    try:
        capability = TwilioCapability(twilio_account_sid, twilio_auth_token)
        capability.allow_client_incoming(get_client_name_by_phone_number(twilio_phone_number))
        capability.allow_client_outgoing(twilio_app_sid)
        capabilityToken = capability.generate(expiration_time_for_capability_token)
        res = {"capabilityToken": capabilityToken, "success": True}

    except UnregisteredPhoneNumberException:
        res = {"capabilityToken": None, "success": False}

    return res

Jetons un coup d'œil à la fonction Lambda que nous avons créée.

Premièrement, les éléments suivants sont des valeurs qui dépendent de l'environnement. Veuillez lire en fonction de votre environnement.

--Dans la fonction lambda_handler

    # configure parameters belong to Twilio
    twilio_account_sid = "{{twilio_accound_sid}}"
    twilio_auth_token = "{{twilio_account_auth_token}}"
    twilio_app_sid = "{{twilio_app_sid}}"
    expiration_time_for_capability_token = 3600

Au début de la fonction, le SID du compte Twilio, le jeton d'authentification qui lui est associé et le SID de l'application créé à l'avance sont spécifiés, changez-les en fonction de votre environnement. La date d'expiration du jeton de capacité est ici définie sur 3600 secondes, mais veuillez la modifier si nécessaire.

--Dans la fonction get_client_name_by_phone_number

    # match and get the correct clientName
    if (phone_number_wo_hyphen == "+815012349876"):
        clientName = "DeviceId_0001"

Veuillez indiquer le numéro de téléphone Twilio que vous avez obtenu lors de la configuration de votre compte Twilio. Changez le clientName à votre convenance. Cette fonction a actuellement un lien entre le numéro de téléphone Twilio et le nom du client dans le code source, mais à l'avenir, on suppose qu'une connexion à la base de données sera établie et que les informations de lien seront extraites de la base de données.

Le flux de traitement est le suivant.

--Get "twilioPhoneNumber" du paramètre Input à la fonction Lambda. --Créez un objet TwilioCapability. (* Ce n'est pas encore un jeton de capacité.)

Déployer

Cette fonction Lambda nécessite le package twilio.util. Par conséquent, le simple fait de coller le code source ci-dessus à partir de l'éditeur en ligne de l'AWS Management Console ne fonctionnera pas. Vous devez créer un package de déploiement et le télécharger. Suivez les étapes ci-dessous pour créer un package de déploiement (fichier zip).

Créer un package de déploiement (Python) https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html

Connectez-vous à un serveur Linux approprié et exécutez comme suit. Placez le code source et toutes les bibliothèques nécessaires dans le répertoire en cours et compressez ce répertoire.

#Cloner le démarrage rapide du client Twilio pour Python pour obtenir des informations sur les dépendances de la bibliothèque Twilio
#Tout ce dont vous avez besoin, ce sont des exigences.Comme il ne s'agit que de txt, vous pouvez l'apporter manuellement
$ git clone https://github.com/TwilioDevEd/client-quickstart-python

#Créer un répertoire de travail
$ mkdir ./twilio_on_aws
$ cd ./twilio_on_aws

#Créez le code source. Copiez et collez la source ci-dessus.
$ vi TwilioRetrieveCapabilityToken.py

#Installez les bibliothèques associées dans votre répertoire de travail
$ pip install -r ../client-quickstart-python/requirements.txt -t ./

#Compressez le code source et les bibliothèques associées dans un fichier zip et créez un package de déploiement
$ zip -r ../TwilioRetrieveCapabilityToken.zip ./

Une fois que vous avez le package de déploiement ci-dessus, téléchargez-le à partir de l'AWS Management Console. LambdaFunction_TwilioRetrieveCapabilityToken_1.png

Je pense qu'il n'y a pas de problème avec la configuration par défaut tant que les paramètres du gestionnaire sont corrects. Cette fonction Lambda n'utilise pas d'autres services AWS, le rôle IAM peut donc être lambda_basic_execution. LambdaFunction_TwilioRetrieveCapabilityToken_2.png

Ceci termine la mise en œuvre et le déploiement de l'API d'acquisition CapabilityToken.

1-2. Implémenter l'API de retour TwiML pour les appels entrants en tant que fonction Lambda

Interface (entrée / sortie)

Les détails de l'interface entre Twilio Server et API Server sont résumés ci-dessous. [Appel depuis un téléphone externe vers le client Twilio (appel entrant)](http://qiita.com/tmiki/items/fad1a22ba1fe14d32e34#%E5%A4%96%E9%83%A8%E9%9B%BB%E8%A9 % B1% E3% 81% 8B% E3% 82% 89twilio% E3% 82% AF% E3% 83% A9% E3% 82% A4% E3% 82% A2% E3% 83% B3% E3% 83% 88 % E3% 81% B8% E3% 81% AEappel entrant)

Les paramètres transmis par Twilio Server en tant qu'entrée sont proches de la structure des paramètres HTTP GET, et Output doit renvoyer XML, donc les deux semblent avoir une mauvaise affinité avec JSON. Il est possible d'effectuer un traitement de conversion de structure de données dans la fonction Lambda, mais il n'est pas préférable d'un point de vue architectural de décrire un traitement non essentiel. Cependant, s'en tenir à JSON est également une perte de temps. Par conséquent, laissez API Gateway gérer le processus de conversion uniquement pour l'entrée. L'entrée doit être convertie au format JSON par API Gateway. La sortie générera du XML avec la fonction Lambda et le renverra tel quel.

Laissez API Gateway traduire la requête HTTP POST de Twilio Server, et cette API attend le JSON suivant.

Input


{
    "AccountSid": "AC3exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "ApiVersion": "2010-04-01",
    "Called": "+815031234567",
    "CalledCountry": "JP",
    "CalledVia": "815031234567",
    "Caller": "+819059876543",
    "CallerCountry": "JP",
    "CallSid": "CA1fnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
    "CallStatus": "ringing",
    "Direction": "inbound",
    "ForwardedFrom": "815031234567",
    "From": "+819059876543",
    "FromCountry": "JP",
    "To": "+815031234567",
    "ToCountry": "JP"
}

Je retournerai TwiML tel quel.

Output


<?xml version="1.0\" encoding="UTF-8"?><Response><Dial timeout="60"><Client>DeviceId_0001</Client></Dial></Response>

la mise en oeuvre

Écrivons maintenant la fonction Lambda.

TwilioRetrieveTwimlCallIncoming.py


from __future__ import print_function
import json

print('Loading function')

def get_client_name_by_phone_number(phone_number):
    # regularize the input string "phone_number" to match registered phone numbers.
    phone_number_wo_hyphen = phone_number.replace('-','')

    # match and get the correct clientName
    if (phone_number_wo_hyphen == "+815031234567"):
        clientName = "DeviceId_0001"

    else:
        clientName = None

    return clientName

def lambda_handler(event, context):
    ''' Returns a TwiML to enable a real phone to call a Twilio device.
    This function will be received the following parameters.

    {
        "Caller": "+819012345678",
        "To": "+815098765432"
    }
    '''

    call_incoming_phone_number = event.get("To")
    client_name = get_client_name_by_phone_number(call_incoming_phone_number)

    if (client_name is None):
        res = '<?xml version="1.0" encoding="UTF-8"?><Response><Say language="en-US" loop="0">An error occurred. Your Twilio phone number {CallIncomingPhoneNumber} is invalid.</Say></Response>'
    else:
        res = '<?xml version="1.0\" encoding="UTF-8"?><Response><Dial timeout="60"><Client>{ClientName}</Client></Dial></Response>'


    strfmt = {"ClientName": client_name, "CallIncomingPhoneNumber": call_incoming_phone_number}

    return res.format(**strfmt)

Jetons un coup d'œil à la fonction Lambda que nous avons créée.

Tout d'abord, il y a les éléments suivants en tant que valeurs qui dépendent de l'environnement, alors réécrivons-les.

def get_client_name_by_phone_number(phone_number):
    #Omission

    if (phone_number_wo_hyphen == "+815031234567"):
        clientName = "DeviceId_0001"

Veuillez indiquer le numéro de téléphone Twilio que vous avez obtenu lors de la configuration de votre compte Twilio. Changez le clientName à votre convenance. Cette fonction get_client_name_by_phone_number devrait établir une connexion à la base de données et récupérer ultérieurement les informations d'association de la base de données. Pour plus de commodité, nous aurons actuellement un lien entre le numéro de téléphone Twilio et le nom du client dans le code source.

Le flux de traitement est le suivant.

--Get "To" du paramètre Input à la fonction Lambda. Ce sera le numéro de téléphone Twilio du destinataire

Déployer

Cette fonction Lambda ne nécessite pas de bibliothèque externe et peut être déployée à partir de l'éditeur en ligne de l'AWS Management Console. LambdaFunction_TwilioRetrieveTwimlCallIncoming_1.png

Je pense qu'il n'y a pas de problème avec la configuration par défaut tant que les paramètres du gestionnaire sont corrects. Cette fonction Lambda n'utilise pas d'autres services AWS, le rôle IAM peut donc être lambda_basic_execution. LambdaFunction_TwilioRetrieveTwimlCallIncoming_2.png

1-3. Implémentez l'API de retour TwiML pour les appels sortants en tant que fonction Lambda

Interface (entrée / sortie)

Les détails de l'interface entre Twilio Server et API Server sont résumés ci-dessous. [Appel du client Twilio vers un téléphone externe (appel sortant)](http://qiita.com/tmiki/items/fad1a22ba1fe14d32e34#twilio%E3%82%AF%E3%83%A9%E3%82%A4%E3% 82% A2% E3% 83% B3% E3% 83% 88% E3% 81% 8B% E3% 82% 89% E5% A4% 96% E9% 83% A8% E9% 9B% BB% E8% A9% B1% E3% 81% B8% E3% 81% AEappel sortant)

Semblable à l'API de retour TwiML pour les appels entrants, il s'agit également d'une méthode permettant de convertir l'entrée en passerelle API et de la saisir dans la fonction Lambda, et de renvoyer TwiML directement à partir de la fonction Lambda.

Laissez API Gateway traduire la requête HTTP POST de Twilio Server, et cette API attend le JSON suivant.

Input


{
    "Direction": "inbound",
    "CallSid": "CA48nnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
    "From": "client:DeviceId_0001",
    "Caller": "client:DeviceId_0001",
    "ApiVersion": "2010-04-01",
    "ApplicationSid": "APf7xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "AccountSid": "AC3exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "CallStatus": "ringing",
    "callerPhoneNumber": "+81-50-3123-4567",
    "callOutgoingPhoneNumber": "+81-90-5987-6543"
}

Je retournerai TwiML tel quel.

Output


<?xml version="1.0" encoding="UTF-8"?><Response><Dial timeout="60" callerId="+81-50-3123-4567"><Number>+81-90-5987-6543</Number></Dial></Response>

la mise en oeuvre

Écrivons maintenant la fonction Lambda.

TwilioRetrieveTwimlCallOutgoing.py


from __future__ import print_function
import json

print('Loading function')

def lambda_handler(event, context):
    ''' Returns a TwiML to enable a Twilio device to call a real phone.
    This function will be received the following parameters.

    {
        "callerPhoneNumber": "+81-50-3123-4567",
        "callOutgoingPhoneNumber": "+81-90-59876543"
    }
    '''

    print ("event: " + json.dumps(event))
    caller_phone_number = event.get("callerPhoneNumber")
    call_outgoing_phone_number = event.get("callOutgoingPhoneNumber")


    res = '<?xml version="1.0" encoding="UTF-8"?><Response><Dial timeout="60" callerId="{callerId}"><Number>{callOutgoingPhoneNumber}</Number></Dial></Response>'
    strfmt = {"callerId": caller_phone_number, "callOutgoingPhoneNumber": call_outgoing_phone_number}

    return res.format(**strfmt)

Cette fonction Lambda est juste un processus pour générer TwiML en fonction des paramètres passés en entrée. Par conséquent, aucune partie ne dépend de l'environnement.

Le flux de traitement est le suivant.

Déployer

Cette fonction Lambda ne nécessite pas de bibliothèque externe et peut être déployée à partir de l'éditeur en ligne de l'AWS Management Console. LambdaFunction_TwilioRetrieveTwimlCallOutgoing_1.png

Je pense qu'il n'y a pas de problème avec la configuration par défaut tant que les paramètres du gestionnaire sont corrects. Cette fonction Lambda n'utilise pas d'autres services AWS, le rôle IAM peut donc être lambda_basic_execution. LambdaFunction_TwilioRetrieveTwimlCallOutgoing_2.png

Résumé

La mise en œuvre de l'API requise est terminée ci-dessus. Entrez les paramètres requis dans JSON et vérifiez que le résultat attendu est renvoyé. Vous pouvez facilement vérifier le fonctionnement à partir de l'AWS Management Console. Le format des entrées / sorties est résumé.

Nom de l'API Input Output
API d'acquisition de jetons de capacité JSON JSON
API de retour TwiML pour les appels entrants JSON XML
API de retour TwiML pour les appels sortants JSON XML

2. Paramètres de la passerelle API

2-1. Lors de l'utilisation d'API Gateway

AWS API Gateway fournit des fonctions utiles pour réaliser des API RESTful. Il existe un concept unique, alors supprimons-le à l'avance.

Concept d'Amazon API Gateway https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-basic-concept.html

Les concepts importants de cette procédure pas à pas sont les suivants.

Je ne pense pas que le concept ci-dessus vient à l'esprit juste en lisant la documentation. Essayez les didacticiels ci-dessous pour avoir une idée de API Gateway et comprendre les concepts.

Démarrez avec Amazon API Gateway https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/getting-started-intro.html

2-1. Créez une API à partir du menu Amazon API Gateway dans AWS Management Console

Depuis AWS Management Console, ouvrez la console Amazon API Gateway (https://ap-northeast-1.console.aws.amazon.com/apigateway/home?region=ap-northeast-1#/apis).

Appuyez sur le bouton "Créer des API" pour créer une nouvelle API API Gateway. Ici, créez-le avec le nom "twilio_on_aws". Une fois créée, l'API API Gateway sera ajoutée à la liste "API". APIGateway_Create_4.png

2-2. Définir les ressources pour chaque API

Passerelle API Une fois l'API créée, nous ajouterons les ressources nécessaires. Vous pouvez le considérer comme un composant de l'API Path of Resource ≒.

Commencez par créer une ressource appelée "/ twilio". Nous ajouterons les ressources nécessaires ci-dessous afin de pouvoir enfin configurer les chemins suivants. Le nom de la ressource et le chemin de la ressource sont spécifiés séparément, mais je ne pense pas qu'il y ait beaucoup d'intérêt à les spécifier séparément, alors faites-les de la même manière. Par défaut, le délimiteur de chemin de ressource est "-", mais il doit être "_".

/twilio/retrieve_capability_token /twilio/retrieve_twiml/call_incoming /twilio/retrieve_twiml/call_outgoing

APIGateway_Resources_1.png

2-3. Définir la méthode pour l'API d'acquisition CapabilityToken (/ twilio / retrieve_capability_token)

Sélectionnez / twilio / retrieve_capability_token et sélectionnez Actions> Créer une méthode. Sélectionnez "POST" comme méthode. Comme l'écran de sélection du type d'implémentation auquel connecter cette méthode s'affiche, définissez la valeur comme indiqué ci-dessous et liez-la à la fonction Lambda créée précédemment.

nom de l'article Définir la valeur
Integration Type Lambda Function
Lambda Region ap-northeast-1
Lambda Function TwilioRetrieveCapabilityToken

APIGateway_retrieve_capability_token_1.png

Lorsque vous appuyez sur le bouton «Enregistrer», la fenêtre contextuelle «Ajouter une autorisation à la fonction Lambda» s'affiche, alors appuyez sur «OK». APIGateway_retrieve_capability_token_2.png

Cela signifie que la «stratégie de fonction Lambda» définie pour chaque fonction Lambda a été modifiée. L'autorisation d'exécuter la fonction Lambda "TwilioRetrieveCapabilityToken" est accordée à partir de la ressource "/ twilio / retrieve_capability_token". Pour plus d'informations sur les stratégies de fonction Lambda, reportez-vous aux documents suivants.

Utiliser des stratégies basées sur les ressources avec AWS Lambda (stratégies de fonction Lambda) https://docs.aws.amazon.com/{ja_jp/lambda/latest/dg/access-control-resource-based.html

Ceci termine la mise en œuvre de l'API d'acquisition CapabilityToken.

Vous pouvez tester la passerelle API créée et les fonctions Lambda à partir de "TEST", alors exécutons l'API en spécifiant l'entrée par défaut et confirmons que le résultat attendu est renvoyé.

RequestBody


{
  "twilioPhoneNumber": "+81-50-1234-9876"
}

ResponseBody


{
  "success": true,
  "capabilityToken": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJ...."
}

À ce stade, il ne peut pas être appelé à partir d'autres hôtes en tant qu'API RESTful. Le travail de déploiement décrit plus loin est requis.

2-4. Définir la méthode pour l'API de retour TwiML (/ twilio / retrieve_twiml / call_incoming) pour les appels entrants

Sélectionnez / twilio / retrieve_twiml / call_incoming et sélectionnez Actions> Créer une méthode. Sélectionnez "POST" comme méthode. Comme l'écran de sélection du type d'implémentation auquel connecter cette méthode s'affiche, définissez la valeur comme indiqué ci-dessous et liez-la à la fonction Lambda créée précédemment.

nom de l'article Définir la valeur
Integration Type Lambda Function
Lambda Region ap-northeast-1
Lambda Function TwilioRetrieveTwimlCallIncoming

APIGateway_retrieve_twiml_call_incoming_1.png

Lorsque vous appuyez sur le bouton «Enregistrer», la fenêtre contextuelle «Ajouter une autorisation à la fonction Lambda» s'affiche, alors appuyez sur «OK». Cela modifie également la «stratégie de fonction Lambda» APIGateway_retrieve_twiml_call_incoming_2.png

Une fois que vous avez défini la ressource / méthode, testons-la. Vous pouvez tester à partir de "TEST". Spécifiez le JSON suivant dans le corps de la requête et testez si le TwiML souhaité est renvoyé.

RequestBody


{
    "Caller": "+819059876543",
    "From": "+819059876543",
    "Called": "+815031234567",
    "To": "+815031234567"
}

ResponseBody


"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><Dial timeout=\"60\"><Client>DeviceId_0001</Client></Dial></Response>"

En plus du travail ci-dessus, l'API construite cette fois doit réaliser les deux choses suivantes.

--Convertir l'entrée en API (Convertir la clé = paire de valeurs séparées par "&" en JSON)

Arrêter l'échappement de la réponse automatique

Tout d'abord, arrêtez le traitement d'échappement automatique de la réponse. Ceci est défini dans "Réponse d'intégration". Ouvrez «Réponse d'intégration», développez «État de la réponse de méthode» à 200 lignes, puis développez «Modèles de mappage corporel». Par défaut, "application / json" est spécifié, appuyez donc sur le bouton "-" pour le supprimer. APIGateway_retrieve_twiml_call_incoming_3.png

Après cela, appuyez sur le bouton "+" de "Ajouter un modèle de mappage" et ajoutez "application / xml" comme Content-Type. En même temps, vous pouvez spécifier le contenu des "Modèles de mappage corporel", spécifiez donc une ligne ci-dessous et appuyez sur le bouton "Enregistrer".

$input.path('$')

APIGateway_retrieve_twiml_call_incoming_4.png

Testons la méthode avec la même requête que précédemment et vérifions le contenu de la réponse. Le "" "a été supprimé pour créer un XML bien formé.

ResponseBody


<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Dial timeout="60"><Client>DeviceId_0001</Client></Dial>
</Response>

Convertir l'entrée en API (Convertir la clé = paire de valeurs séparées par "&" en JSON)

Les paramètres transmis par Twilio Server ne sont pas JSON, mais des paires clé = valeur comme les paramètres GET. Pour convertir cela, il est nécessaire de définir "Body Mapping Template" dans "Integration Request".

Ouvrez la demande d'intégration et développez les modèles de mappage corporel. Cochez «Nous pou- vons qu'aucun modèle n'est défini (recommandé)» dans «Demander le passage du corps». Appuyez sur le bouton "+" de "Ajouter un modèle de mappage" pour ajouter "application / x-www-form-urlencoded". APIGateway_retrieve_twiml_call_incoming_6.png

Collez le contenu suivant comme "Body Mapping Template" et appuyez sur "Enregistrer".

#set($raw_input = $input.path("$"))

{
  #foreach( $kvpairs in $raw_input.split( '&' ) )
    #set( $kvpair = $kvpairs.split( '=' ) )
      #if($kvpair.length == 2)
        "$kvpair[0]" : "$kvpair[1]"#if( $foreach.hasNext ),#end
      #end
  #end
}

APIGateway_retrieve_twiml_call_incoming_7.png

Les détails du modèle de mappage sont résumés dans l'article suivant. Veuillez vous y référer si nécessaire.

Convertir des chaînes telles que les paramètres de requête GET en JSON avec le modèle de mappage de passerelle API

Je veux tester après le réglage, mais je ne peux pas spécifier les paramètres de la demande et il semble que je ne puisse pas bien tester. APIGateway_retrieve_twiml_call_incoming_8.png

Par conséquent, vérifiez le fonctionnement après le déploiement. Avant de créer l'API de retour TwiML pour les appels sortants, effectuez les tâches 2-7 et 2-8 et vérifiez l'opération.

2-5. Définir la méthode pour l'API de retour TwiML (/ twilio / retrieve_twiml / call_outgoing) pour les appels sortants

Sélectionnez twilio / retrieve_twiml / call_outgoing et sélectionnez Actions> Créer une méthode. Sélectionnez "POST" comme méthode. Comme l'écran de sélection du type d'implémentation auquel connecter cette méthode s'affiche, définissez la valeur comme indiqué ci-dessous et liez-la à la fonction Lambda créée précédemment. APIGateway_retrieve_twiml_call_outgoing_2.png

nom de l'article Définir la valeur
Integration Type Lambda Function
Lambda Region ap-northeast-1
Lambda Function TwilioRetrieveTwimlCallOutgoing

Lorsque vous appuyez sur le bouton «Enregistrer», la fenêtre contextuelle «Ajouter une autorisation à la fonction Lambda» s'affiche, alors appuyez sur «OK». Cela modifie également la «stratégie de fonction Lambda» APIGateway_retrieve_twiml_call_outgoing_2.png

Une fois que vous avez défini la ressource / méthode, testons-la. Vous pouvez tester à partir de "TEST". Spécifiez le JSON suivant dans le corps de la requête et testez si le TwiML souhaité est renvoyé.

RequestBody


{
    "callerPhoneNumber": "+81-50-3123-4567",
    "callOutgoingPhoneNumber": "+81-90-5987-6543"
}

ResponseBody


"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><Dial timeout=\"60\" callerId=\"+81-50-3123-4567\"><Number>+81-90-5987-6543</Number></Dial></Response>"

Semblable à l'API de retour TwiML pour les appels entrants, cette API doit également réaliser les deux choses suivantes en plus du travail ci-dessus.

--Convertir l'entrée en API (Convertir la clé = paire de valeurs séparées par "&" en JSON)

Arrêter l'échappement de la réponse automatique

Tout d'abord, arrêtez le traitement d'échappement automatique de la réponse. Ceci est défini dans "Réponse d'intégration". Ouvrez «Réponse d'intégration», développez «État de la réponse de méthode» à 200 lignes, puis développez «Modèles de mappage corporel». Par défaut, "application / json" est spécifié, appuyez donc sur le bouton "-" pour le supprimer. APIGateway_retrieve_twiml_call_outgoing_3.png

Après cela, appuyez sur le bouton "+" de "Ajouter un modèle de mappage" et ajoutez "application / xml" comme Content-Type. En même temps, vous pouvez spécifier le contenu des "Modèles de mappage corporel", spécifiez donc une ligne ci-dessous et appuyez sur le bouton "Enregistrer".

$input.path('$')

APIGateway_retrieve_twiml_call_outgoing_4.png

Testons la méthode avec la même requête que précédemment et vérifions le contenu de la réponse. Le "" "a été supprimé pour créer un XML bien formé.

ResponseBody


<?xml version="1.0" encoding="UTF-8"?><Response><Dial timeout="60" callerId="+81-50-3123-4567"><Number>+81-90-5987-6543</Number></Dial></Response>

Convertir l'entrée en API (Convertir la clé = paire de valeurs séparées par "&" en JSON)

Les paramètres transmis par Twilio Server ne sont pas JSON, mais des paires clé = valeur comme les paramètres GET. Pour convertir cela, il est nécessaire de définir "Body Mapping Template" dans "Integration Request".

Ouvrez la demande d'intégration et développez les modèles de mappage corporel. Cochez «Nous pou- vons qu'aucun modèle n'est défini (recommandé)» dans «Demander le passage du corps». Appuyez sur le bouton "+" de "Ajouter un modèle de mappage" pour ajouter "application / x-www-form-urlencoded". APIGateway_retrieve_twiml_call_outgoing_6.png

Collez le contenu suivant comme "Body Mapping Template" et appuyez sur "Enregistrer".

#set($raw_input = $input.path("$"))

{
  #foreach( $kvpairs in $raw_input.split( '&' ) )
    #set( $kvpair = $kvpairs.split( '=' ) )
      #if($kvpair.length == 2)
        "$kvpair[0]" : "$kvpair[1]"#if( $foreach.hasNext ),#end
      #end
  #end
}

APIGateway_retrieve_twiml_call_outgoing_7.png

Les détails du modèle de mappage sont résumés dans l'article suivant. Veuillez vous y référer si nécessaire.

Convertir des chaînes telles que les paramètres de requête GET en JSON avec le modèle de mappage de passerelle API

Je veux tester après le réglage, mais je ne peux pas spécifier les paramètres de la demande et il semble que je ne puisse pas bien tester. APIGateway_retrieve_twiml_call_outgoing_8.png

Par conséquent, vérifiez le fonctionnement après le déploiement. Exécutez d'abord les étapes 2-7 et 2-8 pour vérifier le fonctionnement.

2-6. Définir CORS

Après avoir créé la méthode, définissons chaque ressource pour autoriser CORS (Cross Origin Resource Sharing). Il s'agit d'une spécification appliquée aux applications de navigateur Web implémentées dans JavaScript, et est définie pour autoriser / refuser les appels d'API entre les domaines. Le client Twilio mis en œuvre cette fois-ci est fourni par https://twilio-on-aws-us.s3.amazonaws.com, qui est le domaine de S3 en HTML lui-même. Cependant, l'API est fournie dans le domaine d'API Gateway, tel que https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/. Par conséquent, l'API que vous créez actuellement doit être configurée avec CORS pour autoriser les appels d'API à partir du contenu du domaine S3.

Veuillez consulter les sites suivants pour une explication détaillée de CORS.

Contrôle d'accès HTTP (CORS) https://developer.mozilla.org/ja/docs/Web/HTTP/HTTP_access_control

À l'origine, il est nécessaire de spécifier un nom de domaine individuel à partir duquel le contenu du domaine peut appeler l'API, mais cette procédure pas à pas ne contrôle pas beaucoup et autorise les appels d'API à partir de tous les domaines.

Le réglage dans ce cas est facile. Avec la ressource cible sélectionnée, sélectionnez «Activer CORS» dans «Actions». Vous pouvez personnaliser les en-têtes à ajouter, mais appuyez simplement sur le bouton "Activer CORS et remplacer les en-têtes CORS existants". APIGateway_CORS_1.png

Une fenêtre de confirmation s'affichera, il vous suffit donc d'appuyer sur le bouton "Oui, remplacer les valeurs existantes". APIGateway_CORS_2.png

"OPTIONS" a été ajouté à la méthode. Si vous cochez les paramètres «Réponse d'intégration» et «Réponse de méthode», vous pouvez voir que les paramètres CORS ont été ajoutés.

APIGateway_CORS_3.png APIGateway_CORS_4.png

Définissez les mêmes paramètres pour toutes les ressources qui fournissent l'API.

2-7. Prod Créer une scène et déployer

Après avoir défini la ressource / méthode requise, déployez-la afin qu'elle puisse être appelée de l'extérieur. Tout d'abord, sélectionnez «Déployer l'API» dans «Actions». Initialement, l'étape n'est pas définie. Sélectionnez [Nouvelle étape] dans [Étape de déploiement]. Définissez chaque valeur comme indiqué ci-dessous et appuyez sur le bouton «Déployer».

nom de l'article Définir la valeur
Stage name* prod
Stage description ※Tout. Ici, cela s'appelle l'environnement de production.
Deployment description ※Tout. Ici, cela s'appelle Première version.

APIGateway_Deploy_1.png

Après le déploiement, vous pouvez vérifier l'étape créée à partir de "API" -> "Nom de l'API" -> "Stages" dans le volet gauche. "Invoke URL" est l'URL qui peut être utilisée de l'extérieur. APIGateway_Deploy_2.png

Si vous développez le nom de l'étape, vous pouvez voir que la ressource / méthode créée jusqu'à présent est mappée telle quelle. Il est nécessaire de vérifier l'opération, vérifions donc l'URL d'appel spécifique de chaque API. APIGateway_Deploy_3.png

2-8. Vérifier le fonctionnement de chaque API

Vérifiez le fonctionnement avec curl. Créons une instance Linux à l'avance. Notez que curl peut afficher des informations détaillées en spécifiant l'option "-v". Si cela ne fonctionne pas, utilisez l'option "-v" pour résoudre le problème.

API d'acquisition de jetons de capacité

Exécutez la commande suivante sous Linux.

$ curl -v -H "Content-type: application/json" -X POST -d '{"twilioPhoneNumber": "+81-50-3123-4567"}' https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/twilio/retrieve_capability_token

#Confirmez que la réponse par défaut est renvoyée.
{"success": true, "capabilityToken": "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9....."}

API de retour TwiML pour les appels entrants

Exécutez la commande suivante sous Linux. Le corps de la requête POST est [requête HTTP POST du serveur Twilio lors d'un appel entrant](http://qiita.com/tmiki/items/fad1a22ba1fe14d32e34#twilio-server%E3%81%8B%E3%82%89% E3% 81% AE http-post% E3% 83% AA% E3% 82% AF% E3% 82% A8% E3% 82% B9% E3% 83% 88) Spécifiez le même contenu.

curl -v -H "Content-type: application/x-www-form-urlencoded; charset=UTF-8" -X POST -d 'ApplicationSid=AP75zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz&ApiVersion=2010-04-01&Called=&Caller=%2B819059876543&CallStatus=ringing&CallSid=CCA86nnnnnnnnnnnnnnnnnnnnnnnnnnnnnn&To=%2B815031234567&From=%2B819059876543&Direction=inbound&AccountSid=AC3exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/twilio/retrieve_twiml/call_incoming

#Confirmez que la réponse par défaut est renvoyée.
<?xml version="1.0" encoding="UTF-8"?><Response><Dial timeout="60"><Client>DeviceId_0001</Client></Dial></Response>

API de retour TwiML pour les appels sortants

Exécutez la commande suivante sous Linux. Le corps de la requête POST est [requête HTTP POST du serveur Twilio lors d'un appel sortant](http://qiita.com/tmiki/items/fad1a22ba1fe14d32e34#twilio-server%E3%81%8B%E3%82%89% E3% 81% AE http-post% E3% 83% AA% E3% 82% AF% E3% 82% A8% E3% 82% B9% E3% 83% 88-1) Spécifiez le même contenu.

curl -v -H "Content-type: application/x-www-form-urlencoded; charset=UTF-8" -X POST -d 'AccountSid=AC3exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&ApiVersion=2010-04-01&ApplicationSid=AP75zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz&Called=&Caller=client%3ADeviceId_0001&CallSid=CA06nnnnnnnnnnnnnnnnnnnnnnnnnnnnnn&CallStatus=ringing&Direction=inbound&From=client%3ADeviceId_0001&To=&callerPhoneNumber=%2B81-50-3123-4567&callOutgoingPhoneNumber=%2B81-90-5987-6543' https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/twilio/retrieve_twiml/call_outgoing

#Confirmez que la réponse par défaut est renvoyée.
<?xml version="1.0" encoding="UTF-8"?><Response><Dial timeout="60" callerId="+81-50-3123-4567"><Number>+81-90-5987-6543</Number></Dial></Response>

Cela termine l'implémentation du côté du serveur API. Nous implémenterons le client Twilio à partir du prochain.

Recommended Posts

Présentation du mécanisme Twilio # 3-1 - Procédure pas à pas de mise en œuvre de la passerelle API API + Lambda (partie 1)
L'implémentation la plus simple d'AWS Lambda
[AWS] Créer une API avec API Gateway + Lambda
[AWS SAM] Créer une API avec DynamoDB + Lambda + API Gateway
LINE BOT avec Python + AWS Lambda + API Gateway
[AWS] Essayez de tracer API Gateway + Lambda avec X-Ray
Version Amazon API Gateway et AWS Lambda Python
Tweet d'AWS Lambda
Créez rapidement une API avec Python, lambda et API Gateway à l'aide d'AWS SAM
AWS CDK-Lambda + API Gateway (Python)
Envoyer les images prises avec ESP32-WROOM-32 vers AWS (API Gateway → Lambda → S3)
[Python] J'ai écrit une API REST en utilisant AWS API Gateway et Lambda.