Comment intégrer DynamoDB dans votre API à l'aide d'AWS Lambda

Dans la première partie de ce didacticiel, nous avons créé une API qui transmettait les requêtes à un Lambda qui renvoyait la meilleure émission de télévision ou le meilleur film pour ce genre. Nous allons maintenant utiliser DynamoDB pour permettre aux utilisateurs de voter pour leur genre préféré.

Si vous n'avez pas lu la première partie de cette série, regardez-la ici!

DynamoDB

DynamoDB est une base de données non relationnelle créée par Amazon que nous pouvons utiliser pour stocker les votes des utilisateurs. C'est aussi génial, car nous pouvons y accéder facilement en utilisant le aws-sdkque Lambdas a préinstallé.

La première chose à faire est de créer une table pour stocker les votes du film. Accédez à DynamoDB dans AWS et cliquez sur «Créer une table».

Sur la page suivante, nous nommerons notre table et fournirons une clé primaire. La clé primaire doit être unique afin que nous n'ayons pas deux enregistrements avec la même clé. Nous pouvons appeler la table «movie-api» et définir la clé primaire sur «movie-genre», car chaque film ne doit apparaître qu'une seule fois dans chaque genre.

Nous avons maintenant configuré tout ce dont nous avons besoin pour configurer dans DynamoDB afin que nous puissions revenir dans notre code.

Ajout d'un gestionnaire Dynamo

L'obtention et la mise en place de données dans une table Dynamo se fait à l'aide de documentClienton aws-sdk , mais la structure des requêtes est très spécifique. Pour nous faciliter la vie, nous pouvons créer un gestionnaire Dynamo pour faire tout le formatage.

Commencez par créer un nouveau fichier appelé «dynamo.js» dans Lambda «movieAPI». Dans ce fichier, nous commençons par demander aws-sdk et créer notre fichierdocumentClient .

const AWS = require('aws-sdk');
let documentClient = new AWS.DynamoDB.DocumentClient({ 'region': 'eu-west-1'});

Nous voulons maintenant créer et exporter une classe contenant trois méthodes: a get, a writeet an update.

module.exports = class DB { get(key, value, table) {} write(ID, data, table) {} async increment(ID, table) {}}

Nous allons commencer par créer notre getméthode. La première chose que nous devons faire est de vérifier que nous avons un valide key,value et table.

if (!table) throw 'table needed';if (typeof key !== 'string') throw `key was not string and was ${JSON.stringify(key)} on table ${table}`;if (typeof value !== 'string') throw `value was not string and was ${JSON.stringify(value)} on table ${table}`;

Parce que nous voulons que cette méthode soit basée sur des promesses, nous devons renvoyer un fichier new Promise.

return new Promise((resolve, reject) => {})

Pour obtenir des données de Dynamo, nous devons transmettre un ensemble de paramètres au client de document. Ces paramètres doivent inclure TableNameetKey.

let params = { TableName: table, Key: {[key]: value}};

Nous transmettons ces paramètres àdocumentClientet puis rejects'il y a une erreur ouresolves'il n'y en a pas.

documentClient.get(params, function(err, data) { if (err) { console.log(`There was an error fetching the data for ${key} ${value} on table ${table}`, err); return reject(err); } return resolve(data.Item);});

Un processus similaire est effectué pour la writeméthode. Nous vérifions que les paramètres sont valides, créons les paramètres et les transmettons à documentClient.

return new Promise((resolve, reject) => { if (typeof ID !== 'string') throw `the id must be a string and not ${ID}`; if (!data) throw "data is needed"; if (!table) throw 'table name is needed';
 let params = { TableName: table, Item: { ...data, ID: ID } };
 documentClient.put(params, function(err, result) { if (err) { console.log("Err in writeForCall writing messages to dynamo:", err); console.log(params); return reject(err); } console.log('wrote data to table ', table) return resolve({ ...result.Attributes, ...params.Item }); });});

La incrementméthode est beaucoup plus simple. Pour incrémenter, nous essayons d'obtenir les données pour cette clé, augmentons le nombre de un, puis nous l'écrivons dans la base de données. Si nous ne pouvons pas obtenir les données ou s'il n'y a pas de décompte des données, nous supposons que nous devons définir le décompte sur 0.

async increment(ID, table) { if (!table) throw 'table needed'; if (!ID) throw 'ID needed'; let data; try { data = await this.get('movie-genre', ID, table); if (!data.count) throw 'no count in data' } catch (err) { data = { "movie-genre": ID, count: 0 }; }; let newData = { ...data, count: data.count + 1 }; return this.write(ID, newData, table);}

Modifier notre Lambda

Nous disposons désormais d'un moyen simple d'obtenir, d'écrire et de mettre à jour notre table Dynamo. Nous pouvons l'utiliser pour permettre à nos utilisateurs de voter. Dans «index.js»,nous devons d'abord importer notre nouvelle classe Dynamo et en créer une instance.

const DB = require('./dynamo');const Dynamo = new DB();

Maintenant, à l'intérieur de notre putMovienous pouvons ajouter la logique pour permettre aux utilisateurs de voter. Les deux choses que nous devons obtenir proviennent moviedu corps et genredes paramètres du chemin. Nous les combinons ensuite pour créer notremovie-genreID. Ceci est ensuite transmis Dynamo.incrementavec un nom de table de movie-apiet notre putMovieest terminé.

const putMovie = async event => { let { movie } = JSON.parse(event.body); let genre = event.pathParameters.genre; let ID = `${movie}-${genre}`; return Dynamo.increment(ID, 'movie-api')}

Pour que cela fonctionne lorsque nous recevons le Putrequest, nous devons modifier légèrement notre fonction de gestionnaire de base.

if (event.httpMethod === 'PUT') { let response = await putMovie(event) return done(response);}

Étant donné que nous avons ajouté AWS à notre Lambda, nous devons exécuter npm init, puis npm install — save aws-sdkdans le dossier Lambda. Cela peut être fait localement et téléchargé, ou fait à l'aide de Cloud9.

Ajout de la méthode API Gateway

Avec la nouvelle fonction, nous pouvons ajouter une nouvelle méthode à notre API. Dans API Gateway, nous pouvons sélectionner notre "movieAPI", puis sélectionner "/ movies / {genre}" . Cliquez sur « Actions » -> « Créer Meth o méthode d » et choisir d'ajouter un « PUT ».

Ce « PUT » peut être dirigé à notre « movieAPI » , et cochez « Utiliser Lambda intégration Proxy ». Une fois enregistré, nous pouvons le tester. Sur la méthode, nous pouvons cliquer sur «TEST» et entrer un genre et un corps contenant un film. Lorsque nous cliquons sur «TEST», nous obtenons une réponse contenant le film et le nouveau décompte. Comme il s'agit du premier vote, le décompte sera de 1.

Lancer le test une deuxième fois augmentera désormais les votes pour ce film de un.

Modifier la méthode GET

Maintenant que nous avons un nouveau système de vote, nous pouvons mettre à jour notre «GET»d'utiliser ces nouvelles données. Nous devons obtenir tous les films du genre demandé et les lister par ordre de votes.

Nous devons d'abord créer une nouvelle méthode dynamo. Cette méthode analysera chacune des entrées et sélectionnera celles qui correspondent à nos critères.

scan(key, value, table) { return new Promise((resolve, reject) => { let params = { TableName: table, FilterExpression: `${key} = :value`, ExpressionAttributeValues: { ':value': value } }; documentClient.scan(params, function(err, data) { if (err) reject(err); resolve(data); }); });}

Nous pouvons maintenant modifier notre getMoviefunction to use this new Dynamo method. We need to pass the genre, selected movie, and current count.

const getMovie = async event => { let genre = event.pathParameters.genre; let data = await Dynamo.scan('genre', genre, 'movie-api'); let result = data.Items.sort((a,b) => b.count - a.count); result = result.map(({count, ID, genre})=> { return {count, ID, genre}}); return data;}

The last thing to do is to add an await before out getMoviefunction so that it handles the async database scan.

let response = await getMovie(event);

Testing

When we hit this new “GET” endpoint we receive an ordered list of all of the movies in the database.

[ { "count": 2, "ID": "Desperado (1995)-action", "genre": "action" }, { "count": 1, "ID": "Team America (2004)-action", "genre": "action" }]

Summary

We’ve now built an API that can handle “GET” and “PUT” requests, storing and retrieving data from a Dynamo database. You can also reuse a lot of the Dynamo class code for other APIs that work with Dynamo.

Want some practice?

If you’ve enjoyed this, then why not try to implement a similar setup for tv shows? If you do, then let me know how it goes!

You can also improve this API by making sure that Desperado (1995) and desperado (1995) both count towards the same movie, or only allow a certain format of movie title.

If you’ve liked this, then make sure to give it a clap and subscribe for more Amazon tutorials and guides. See you in the next article and Keep Coding!