Les architectures basées sur les microservices sont l’avenir des applications complexes. Dans ce blog, nous allons nous intéresser à l’un des composants critiques de cette architecture: L’API Gateway (Passerelle API).
Disons que vous essayez de créer un magasin en ligne (web-store). Vous utiliserez probablement plusieurs API pour fournir les actifs et les données nécessaires à la création de chaque page de produits. Les microservices que vous pouvez déployer peuvent inclure : services d’information sur le produit, services de tarification, services de commande, services d’inventaire, etc.
En plus de tous ces services, vous devrez déployer plusieurs versions de ces services pour interagir avec les clients qui communiquent à partir de plates-formes mobiles, de bureau et de navigateurs Web différents. Comment le développeur doit gérer tout ça ? C’est là que les APIs gateway rentrent en jeu.
Pros API Gateway
- Les Microservices peuvent être dédiés uniquement à l’implémentation de la logique métier. La gestion de l’authentification, la journalisation et la surveillance seront déléguées à l’API Gateway
- Diriger une requête donnée au microservice adéquat
- Les clients peuvent obtenir toutes les données en un seul coup (agrégation des résultats de plusieurs services)
- Exécuter plusieurs versions de la même API simultanément, ce qui permet d’itérer, de tester et de publier rapidement de nouvelles versions
Cons API Gateway
- Ils peuvent entraîner une dégradation des performances en raison de nombreux événements survenus qu’ils doivent gérer
- Parfois, ils deviennent des SPOFs
- La gestion du routage est une surcharge du modèle
- Trop d’implémentation logique dans cette passerelle entraînera un autre problème de dépendance
Malgré ces arguments qui leur sont opposés, les APIs Gateway continuent de prospérer dans les implémentations. Pour preuve, presque tous les principaux fournisseurs mettent à disposition leurs passerelles. Voici quelques exemples :
- Azure API Gateway
- Oracle API Manager
- AWS API Gateway
- Tyk API Gateway (open source)
- Kong API Gateway (open source)
- Express API Gateway (open source)
Produit | Description | Déploiement | Code |
---|---|---|---|
Azure API Gateway | Elle fait partie de l’offre cloud Microsoft Azure | Cloud ou en On promise | Source fermée |
Oracle API Gateway | Produit par Oracle et étroitement couplé aux services Oracle SOA Suite / SOA Cloud | Cloud SaaS ou On premise | Source fermée |
AWS API Gateway | Elle fait partie de la suite de produits AWS | Cloud | Source fermée |
Tyk API Gateway | C’est un produit API Gateway open source de nouvelle génération | Cloud ou On promise | Libre (langage GO) |
Kong API Gateway | C’est une API Gateway open source basée sur Nginx et OpenResty | On premise | Open source (Nginx + Lua) |
Express API Gateway | C’est un projet open source utilisant Nodejs et ExpressJS | On premise | Open source (NodeJS) |
Dans la continuité de notre série de blogs AWS, nous allons nous intéresser à AWS API Gateway.
AWS API Gateway
AWS propose sa version d’API Gateway. C’est un service managé de proxy d’API, qui permet de créer, publier, surveiller et sécuriser des APIs. vers des services AWS tels que EC2, Lambda, Kinesis, etc.
AWS API Gateway aide les développeurs à gérer les tâches liées aux API comme la gestion du trafic entrant, la restriction du nombre d’appels à une ressource donnée, le contrôle des autorisations et accès (via IAM et Cognito), la surveillance, versionning de l’API, etc. Chaque appel repose sur le concept HTTP « REST », en appelant des ressources créées par un développeur par l’intermédiaire de méthodes HTTP (i.e GET, POST, PUT, DELETE, OPTIONS).
Assez parlé théorie et passons à la pratique. Nous allons découvrir AWS API Gateway au travers d’un cas d’usage simple (architecture ci-dessous). Nous allons utiliser AWS API Gateway pour créer une API et son Endpoint qui doit déclencher (trigger) une fonction lambda en lui envoyant un message POST. Cette fonction va simplement récupérer ce message, le traiter et ensuite le stoker dans une table DynamoDB.
Cas pratique
Création du rôle de la fonction Lambda
Création de la relation d’approbation du rôle
Pour permettre à un mandataire de service, lambda.amazonaws.com dans notre cas, d’endosser le rôle et permettre ainsi d’exécuter notre fonction Lambda, il va falloir commencer par créer ce qu’on appelle une relation d’approbation (Trust Relationship) et ensuite créer le rôle en s’y basant.
Nous pouvons créer un fichier, que nous appelons trust-relationship.json pouvant ressembler à ceci:
{
'Version':'2012-10-17',
'Statement': [
{
'Effect': 'Allow',
'Principal': {
'Service': [
'lambda.amazonaws.com',
'edgelambda.amazonaws.com'
]
},
'Action': 'sts:AssumeRole'
}
]
}
Définir le rôle
Utiliser les informations d’approbation pour définir notre rôle IAM. Pour ce faire, on utilise la commande suivante :
aws iam create-role --role-name myprodcatalog-lambda-role --assume-role-policy-document file://trust-relationship.json
Ce qui donne
{
'Role': {
'Path': '/',
'RoleName': 'myprodcatalog-lambda-role',
'RoleId': 'AROAISKGWVDB5WESR2SKS',
'Arn': 'arn:aws:iam::123456789800:role/myprodcatalog-lambda-role',
'CreateDate': '2019-01-25T09:14:51Z',
'AssumeRolePolicyDocument': {
'Version': '2012-10-17',
'Statement': [
{
'Effect': 'Allow',
'Principal': {
'Service': [
'lambda.amazonaws.com',
'edgelambda.amazonaws.com'
]
},
'Action': 'sts:AssumeRole'
}
]
}
}
}
Maintenant qu’on a créé le rôle, on doit définir la stratégie d’accès (Policy) de celui-ci. Ainsi, on va déterminer avec quels services notre fonction lambda va pouvoir communiquer.
Création de la stratégie d’accès
Ouvrir un éditeur et créer un fichier de configuration JSON. Ce fichier indique que notre fonction Lambda est autorisée à communiquer avec CloudWatch (pour envoyer des logs) et avec DynamoDb (afin d’écrire nos messsages POST).
{
'Version': '2012-10-17',
'Statement': [
{
'Sid': 'logandDatas',
'Effect': 'Allow',
'Action': [
'cloudwatch:*',
'dynamodb:*'
],
'Resource': '*'
}
]
}
aws iam create-policy --policy-name myprodcatalog-policy --policy-document file://policies_lambda.json
{
'Policy': {
'PolicyName': 'myprodcatalog-policy',
'PolicyId': 'ANPAIR2EEPJMUURQD3CBI',
'Arn': 'arn:aws:iam::123456789800:policy/myprodcatalog-policy',
'Path': '/',
'DefaultVersionId': 'v1',
'AttachmentCount': 0,
'PermissionsBoundaryUsageCount': 0,
'IsAttachable': true,
'CreateDate': '2019-01-25T09:27:40Z',
'UpdateDate': '2019-01-25T09:27:40Z'
}
}
Rattacher la stratégie d’accès au rôle
Maintenant que notre stratégie est créée, nous pouvons récupérer son ARN (Amazon Resource Name) pour pouvoir rattacher cette stratégie à notre rôle. Voici la commande à lancer:
aws iam attach-role-policy -- --policy-arn arn:aws:iam::123456789800:policy/myprodcatalog-policy --role-name myprodcatalog-lambda-role
Si aucun message d’erreur ne s’affiche, on peut demander la liste des policies rattachées au rôle pour s’assurer que le rattachement a été bien fait :
aws iam list-attached-role-policies --role-name myprodcatalog-lambda-role
{
'AttachedPolicies': [
{
'PolicyName': 'myprodcatalog-policy',
'PolicyArn': 'arn:aws:iam::123456789800:policy/myprodcatalog-policy'
}
]
}
Créer la fonction Lambda
import json
import boto3
dynamodb = boto3.resource('dynamodb')
tableProduct = dynamodb.Table('ProductCatalog')
def lambda_handler(event, context):
tableProduct.put_item(Item=event)
return {'code':200, 'message':'Produit ajoute'}
Pour créer la fonction lambda avec AWS CLI, nous devons indiquer quelques paramètres:
- nom de la région : eu-west-1 pour l’Irlande
- nom du package zip : Il suffit de créer un fichier zip à partir de la fonction Lambda (lambda_function.py)
- nom du handler: voir votre fonction Lambda
- nom et version du runtime : Dans notre cas, on a utilisé python3.7 pour définir le corp de la fonction lambda, mais il possible d’utiliser d’autres runtimes (Java, Node.Js, Ruby, C#, Go, PowerShell à date)
aws lambda create-function \
--region eu-west-1 \
--function-name AddProduct \
--zip-file fileb://lambda_function.zip \
--role arn:aws:iam::123456789800:role/myprodcatalog-lambda-role --handler lambda_function.lambda_handler \
--runtime python3.7
{
FunctionName: AddProduct,
FunctionArn: arn:aws:lambda:eu-west-1:123456789800:function:AddProduct,
Runtime: python3.7,
Role: arn:aws:iam::123456789800:role/myprodcatalog-lambda-role,
Handler: lambda_function.lambda_handler,
CodeSize: 342,
Description: ,
Timeout: 3,
MemorySize: 128,
LastModified: 2019-01-25T14:34:24.665+0000,
CodeSha256: DpjG2LWxOcgt5C50tpe12WFRjEP/BEPujfvBqwd0Qbg=,
Version: $LATEST,
TracingConfig: {
Mode: PassThrough
},
RevisionId: 8f4f2ac4-d790-47dc-9605-fa8f9852b0fa
}
Créer la table dynamodb
aws dynamodb create-table \
--table-name ProductCatalog --attribute-definitions \
AttributeName=idProd,AttributeType=S AttributeName=ProductCategory,AttributeType=S \
--key-schema AttributeName=idProd,KeyType=HASH AttributeName=ProductCategory,KeyType=RANGE \
--provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
C:\Travail\tools\serverless\blogApiGatewaygt;aws dynamodb create-table --table-name ProductCatalog --attribute-definitions AttributeName=idProd,AttributeType=S AttributeName=ProductCategory,AttributeType=S --key-schema AttributeName=idProd,KeyType=HASH AttributeName=ProductCategory,KeyType=RANGE --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
{
TableDescription: {
AttributeDefinitions: [
{
AttributeName: ProductCategory,
AttributeType: S
},
{
AttributeName: idProd,
AttributeType: S
}
],
TableName: ProductCatalog,
KeySchema: [
{
AttributeName: idProd,
KeyType: HASH
},
{
AttributeName: ProductCategory,
KeyType: RANGE
}
],
TableStatus: CREATING,
CreationDateTime: 1548232357.28,
ProvisionedThroughput: {
NumberOfDecreasesToday: 0,
ReadCapacityUnits: 1,
WriteCapacityUnits: 1
},
TableSizeBytes: 0,
ItemCount: 0,
TableArn: arn:aws:dynamodb:eu-west-1:123456789800:table/ProductCatalog,
TableId: d063eb88-702b-4f3b-a77f-588ae8e5be1a
}
}
Créer l’Api REST en utilisant l’API Gateway
aws apigateway create-rest-api --name prodcatalog-api --region eu-west-1
{
id: ntc3qlrlvh,
name: prodcatalog-api,
createdDate: 1548427095,
apiKeySource: HEADER,
endpointConfiguration: {
types: [
EDGE
]
}
}
Afficher les ressources de l’API
aws apigateway get-resources --rest-api-id ntc3qlrlvh --region eu-west-1
Ajouter la ressource «Product» à l’API REST
aws apigateway create-resource --rest-api-id ntc3qlrlvh --parent-id apgmkc7a82 --path-part Product
{
id: 3a2321,
parentId: apgmkc7a82,
pathPart: Product,
path: /Product
}
Créer la méthode HTTP POST
Nous voulons maintenant ajouter une méthode POST à notre ressource Product qu’on vient de créer. Pour ce faire, nous aurons besoin de l’id de L’API REST et de l’id de la ressource Product.
aws apigateway put-method --rest-api-id ntc3qlrlvh --resource-id 3a2321 --http-method POST --authorization-type NONE --region eu-west-1
{
httpMethod: POST,
authorizationType: NONE,
apiKeyRequired: false
}
Intégrer l’API Gateway et la fonction Lambda
Il s’agit de définir notre fonction Lambda comme destination de la méthode POST
Note- La syntaxe est la suivante :
aws apigateway put-integration --rest-api-id $API --resource-id $RESOURCE \
--http-method POST --type AWS --integration-http-method POST \
--uri arn:aws:apigateway:$REGION:lambda:path/2015-03-31/functions/arn:aws:lambda:$REGION:$ACCOUNT:function:LambdaFunctionOverHttps/invocations
{
type: AWS,
httpMethod: POST,
uri: arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-west-1:123456789800:function:AddProduct/invocations,
passthroughBehavior: WHEN_NO_MATCH,
timeoutInMillis: 29000,
cacheNamespace: 3a2321,
cacheKeyParameters: []
}
Autoriser l’API Gateway à appeler la fonction Lambda
aws lambda add-permission --region eu-west-1 \
--function-name AddProduct --statement-id apigateway-statement-1
--action lambda:InvokeFunction --principal apigateway.amazonaws.com \
--source-arn arn:aws:execute-api:eu-west-1:123456789800:ntc3qlrl*vh//POST/Product*
{
Statement: {\Sid\:\apigateway-statement-1\,\Effect\:\Allow\,\Principal\:{\Service\:\apigateway.amazonaws.com\},\Action\:\lambda:InvokeFunction\,\Resource\:\arn:aws:lambda:eu-west-1:123456789800:function:AddProduct\,\Condition\:{\ArnLike\:{\AWS:SourceArn\:\arn:aws:execute-api:eu-west-1:123456789800:ntc3qlrlvh/*/POST/Product\}}}
}
Configurer l’API
Ajouter une « Method Response » au POST
Une « Method Response » d’API encapsule le résultat d’appel d’une méthode d’API que le client va recevoir. Afin de formater le résultat de la méthode POST en JSON, on utilise la configuration suivante :
aws apigateway put-method-response \
--rest-api-id ntc3qlrlvh --resource-id 3a2321 \
--http-method POST --status-code 200 \
--response-models application/json=Empty
{
statusCode: 200,
responseModels: {
application/json: Empty
}
}
Pour approfondir les concepts de Method Response:
Ajouter une « Integration Response » au POST
C’est ici qu’on peut définir des paramètres de mappages entre la réponse renvoyée par le backend et celle devant être renvoyée par l’API Gateway.
Dans notre cas, on souhaite garder le format JSON avec les mêmes résultats renvoyés par la fonction Lambda.
aws apigateway put-integration-response \
--rest-api-id ntc3qlrlvh --resource-id 3a2321 \
--http-method POST --status-code 200 \
--response-templates application/json=
{
statusCode: 200,
responseTemplates: {
application/json: null
}
}
Déployer l’API
Dans cette dernière étape, nous allons déployer l’API que nous avons créé dans un environnement appelé dev (on peut créer plusieurs environnements : preprod, prod, test, …Etc)
aws apigateway create-deployment –rest-api-id ntc3qlrlvh –stage-name dev
{
id: dl9wnx,
createdDate: 1548433834
}
Tester
Nous allons utiliser PostMan pour effectuer le bon fonctionnement.
Et si on regarde du côté de notre table Dynamodb, on trouve que le produit qu’on vient de poster est bien ajouté.
Pour aller plus loin
- Enrichir l’API en ajoutant d’autres méthodes: Recherche, suppression et mise à jour de produit (GET, DELETE, PUT)
- Sécuriser l’API en utilisant une clé API par exemple.
- Dépolyer rapidement les développements en utilisant un framework dédié tel que CloudFormation, Serverless Framework, Terraform, etc.
0 commentaire