diff --git a/dynamoClient.js b/dynamoClient.js new file mode 100644 index 0000000..d3a2b54 --- /dev/null +++ b/dynamoClient.js @@ -0,0 +1,13 @@ +const AWS = require('aws-sdk'); + +// Set the region +AWS.config.update({region: 'us-east-2'}); + +// also set local endpoint while in development +if (process.env.NODE_ENV === 'development') { + AWS.config.update({endpoint: "http://localhost:8000"}); +} + +const client = new AWS.DynamoDB.DocumentClient({}); + +module.exports = client; diff --git a/handlers/hello/get.js b/handlers/hello/get.js new file mode 100644 index 0000000..ed6be6c --- /dev/null +++ b/handlers/hello/get.js @@ -0,0 +1,14 @@ +'use strict'; + +module.exports.hello = async (event, context) => { + return { + statusCode: 200, + body: JSON.stringify({ + message: 'Go Serverless v1.0! Your function executed successfully!', + input: event, + }), + }; + + // Use this code if you don't use the http event with the LAMBDA-PROXY integration + // return { message: 'Go Serverless v1.0! Your function executed successfully!', event }; +}; diff --git a/helpers.js b/helpers.js new file mode 100644 index 0000000..116b2f5 --- /dev/null +++ b/helpers.js @@ -0,0 +1,20 @@ +const customThrow = (statusCode, message) => { + const err = new Error(); + err.statusCode = statusCode; + err.message = message; + throw err; +}; + +const createResponse = (statusCode, body) => ({ + statusCode, + headers: { + "Access-Control-Allow-Origin" : "*", // Required for CORS support to work + "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS + }, + body: JSON.stringify(body), +}); + +module.exports = { + customThrow, + createResponse +}; diff --git a/services/db.js b/services/db.js new file mode 100644 index 0000000..541125e --- /dev/null +++ b/services/db.js @@ -0,0 +1,61 @@ +const dynamoClient = require('../dynamoClient'); + +const create = async (tableName, item) => { + const fullItem = {...item, created_at: Date.now()}; + + await dynamoClient.put({ + TableName: tableName, + Item: fullItem + }).promise(); + + // put does not return saved item, just return our object + return fullItem; +}; + +const get = async (tableName, keyMap) => { + const res = await dynamoClient.get({ + TableName: tableName, + Key: keyMap + }).promise(); + + return res && res.Item; +}; + +const queryByID = async (tableName, idKeyName, id) => { + // querying by id can be used when we are querying a table + // that has a sortKey, but we don't need to use the sortKey + const res = await dynamoClient.query({ + TableName: "gt_answers", + KeyConditionExpression: "#id = :idValue", + ExpressionAttributeNames: { + "#id": idKeyName, + }, + ExpressionAttributeValues: { + ":idValue": id, + } + }).promise(); + + return res && res.Items; +}; + +const update = async (tableName, keyMap, ue, eav) => { + const res = await dynamoClient.update({ + TableName: tableName, + Key: keyMap, + UpdateExpression: ue, + ExpressionAttributeValues: eav, + ReturnValues: 'UPDATED_NEW' + }).promise(); + + console.log('update res', res); + + return res; +}; + +module.exports = { + client: dynamoClient, + create, + get, + queryByID, + update +}; diff --git a/validators/index.js b/validators/index.js new file mode 100644 index 0000000..f0bbebb --- /dev/null +++ b/validators/index.js @@ -0,0 +1,35 @@ +const Ajv = require('ajv'); +const {customThrow} = require('../helpers'); + +const parseAndValidateBody = async (schema, body) => { + let parsedBody; + + try { + parsedBody = JSON.parse(body); + } catch (err) { + customThrow(400, 'Error. Malformed event.parsedBody.'); + } + + const validation = validateBody(schema, parsedBody); + + if (!validation.isValid) { + customThrow(400, validation.error); + } + + return parsedBody; +}; + +const validateBody = (schema, body) => { + const ajv = new Ajv(); + const validate = ajv.compile(schema); + const isValid = validate(body); + + return { + isValid: isValid, + error: JSON.stringify(validate.errors) + } +}; + +module.exports = { + parseAndValidateBody, +}; diff --git a/validators/schemas.js b/validators/schemas.js new file mode 100644 index 0000000..7f7402f --- /dev/null +++ b/validators/schemas.js @@ -0,0 +1,33 @@ +const answerSchema = { + "type": "object", + "properties": { + "user_id": {"type": "string"}, + "question_id": {"type": "string"}, + "is_correct": {"type": "boolean"} + }, + "required": ["user_id", "question_id", "is_correct"] +}; + +const userSchema = { + "type": "object", + "properties": { + "id": {"type": "string"}, + "score": {"type": "number"} + }, + "required": ["user_id", "question_id", "is_correct"] +}; + +const loginFollowUpSchema = { + "type": "object", + "properties": { + "accessToken": {"type": "string"} + }, + "required": ["accessToken"] +}; + +module.exports = { + answerSchema, + userSchema, + loginFollowUpSchema +}; +