Skip to content

Instantly share code, notes, and snippets.

@azendal
Last active February 28, 2024 01:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azendal/795eb211e0b4c4243159dbafd872da4f to your computer and use it in GitHub Desktop.
Save azendal/795eb211e0b4c4243159dbafd872da4f to your computer and use it in GitHub Desktop.
//npm install aws-sdk aws-sdk-mock --save-dev
/*
if (process.env.NODE_ENV === 'development') {
require('./mockDynamoDB');
}
*/
/*
4. Running Your Server
Now, when you run your server locally with NODE_ENV=development, it will use the mocked DynamoDB, allowing you to test your application without connecting to an actual DynamoDB instance.
5. Resetting or Removing the Mock
If you're writing tests, you might want to reset or remove the mock between tests to ensure test isolation. You can use the restore method provided in mockDynamoDB.js:
javascript
const mockDynamoDB = require('./mockDynamoDB');
afterEach(() => {
mockDynamoDB.restore();
});
*/
const AWSMock = require('aws-sdk-mock');
const AWS = require('aws-sdk');
// Mocked data storage
let dataStore = {};
AWSMock.setSDKInstance(AWS);
// Mock DynamoDB query
AWSMock.mock('DynamoDB.DocumentClient', 'query', (params, callback) => {
// Simplified example: filter items by userId
const items = Object.values(dataStore).filter(item => item.userId === params.ExpressionAttributeValues[':userId']);
callback(null, { Items: items });
});
// Mock DynamoDB put
AWSMock.mock('DynamoDB.DocumentClient', 'put', (params, callback) => {
dataStore[`${params.Item.userId}_${params.Item.searchId}`] = params.Item;
callback(null, {});
});
// Mock DynamoDB update
AWSMock.mock('DynamoDB.DocumentClient', 'update', (params, callback) => {
const key = `${params.Key.userId}_${params.Key.searchId}`;
if (dataStore[key]) {
for (let attr in params.ExpressionAttributeValues) {
const attrName = attr.slice(1); // Removing ':' prefix
dataStore[key][attrName] = params.ExpressionAttributeValues[attr];
}
callback(null, {});
} else {
callback(new Error("Item not found"));
}
});
// Mock DynamoDB delete
AWSMock.mock('DynamoDB.DocumentClient', 'delete', (params, callback) => {
const key = `${params.Key.userId}_${params.Key.searchId}`;
if (dataStore[key]) {
delete dataStore[key];
callback(null, {});
} else {
callback(new Error("Item not found"));
}
});
module.exports = {
restore: () => {
AWSMock.restore('DynamoDB.DocumentClient');
dataStore = {}; // Reset data store
}
};
/*
mkdir saved-searches-service
cd saved-searches-service
npm init -y
npm install aws-sdk express body-parser dotenv
*/
const express = require('express');
const bodyParser = require('body-parser');
const AWS = require('aws-sdk');
require('dotenv').config();
const app = express();
const port = 3000;
AWS.config.update({
region: 'your-region',
});
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const TABLE_NAME = process.env.DYNAMODB_TABLE_NAME;
const MAX_SAVED_SEARCHES = 5;
app.use(bodyParser.json());
// Create a new saved search
app.post('/savedsearches', async (req, res) => {
const { userId, searchstring, locationid, minsalary, maxsalary, categoryid, subcategoryid, tlalocid } = req.body;
const searchId = Date.now().toString(); // Use timestamp as a simple unique ID
// Check existing saved searches for the user
try {
const existingSearches = await dynamoDb.query({
TableName: TABLE_NAME,
KeyConditionExpression: 'userId = :userId',
ExpressionAttributeValues: {
':userId': userId,
},
}).promise();
if (existingSearches.Items.length >= MAX_SAVED_SEARCHES) {
return res.status(400).send({ error: 'Maximum number of saved searches reached.' });
}
} catch (error) {
return res.status(500).send({ error: 'Failed to retrieve saved searches.' });
}
// Proceed with creating a new saved search
const params = {
TableName: TABLE_NAME,
Item: {
userId,
searchId,
searchstring,
locationid,
minsalary,
maxsalary,
categoryid,
subcategoryid,
tlalocid,
lastChecked: new Date().toISOString(),
},
};
try {
await dynamoDb.put(params).promise();
res.status(201).send({ message: 'Saved search created successfully.' });
} catch (error) {
res.status(500).send({ error: 'Failed to create saved search.' });
}
});
// List all saved searches for a user
app.get('/savedsearches/:userId', async (req, res) => {
const { userId } = req.params;
try {
const data = await dynamoDb.query({
TableName: TABLE_NAME,
KeyConditionExpression: 'userId = :userId',
ExpressionAttributeValues: {
':userId': userId,
},
}).promise();
res.status(200).send(data.Items);
} catch (error) {
res.status(500).send({ error: 'Failed to fetch saved searches.' });
}
});
// Update a saved search
app.put('/savedsearches/:userId/:searchId', async (req, res) => {
const { userId, searchId } = req.params;
const { searchstring, locationid, minsalary, maxsalary, categoryid, subcategoryid, tlalocid } = req.body;
const params = {
TableName: TABLE_NAME,
Key: {
userId,
searchId,
},
UpdateExpression: 'set searchstring = :ss, locationid = :li, minsalary = :min, maxsalary = :max, categoryid = :ci, subcategoryid = :sci, tlalocid = :ti',
ExpressionAttributeValues: {
':ss': searchstring,
':li': locationid,
':min': minsalary,
':max': maxsalary,
':ci': categoryid,
':sci': subcategoryid,
':ti': tlalocid,
},
ReturnValues: 'UPDATED_NEW',
};
try {
await dynamoDb.update(params).promise();
res.status(200).send({ message: 'Saved search updated successfully.' });
} catch (error) {
res.status(500).send({ error: 'Failed to update saved search.' });
}
});
// Delete a saved search
app.delete('/savedsearches/:userId/:searchId', async (req, res) => {
const { userId, searchId } = req.params;
const params = {
TableName: TABLE_NAME,
Key: {
userId,
searchId,
},
};
try {
await dynamoDb.delete(params).promise();
res.status(200).send({ message: 'Saved search deleted successfully.' });
} catch (error) {
res.status(500).send({ error: 'Failed to delete saved search.' });
}
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
const express = require('express');
const bodyParser = require('body-parser');
const AWS = require('aws-sdk');
const Joi = require('joi');
const { v4: uuidv4 } = require('uuid'); // For generating unique IDs
require('dotenv').config();
const app = express();
const port = 3000;
AWS.config.update({
region: 'your-region',
});
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const TABLE_NAME = process.env.DYNAMODB_TABLE_NAME;
const MAX_SAVED_SEARCHES = 5;
app.use(bodyParser.json());
// Adjusted schema to include ID (not required for creation as it's generated server-side)
const searchSchema = Joi.object({
id: Joi.string(), // ID is not required for creation
searchstring: Joi.string().required(),
locationid: Joi.number().integer().required(),
minsalary: Joi.number().integer().min(0),
maxsalary: Joi.number().integer().min(Joi.ref('minsalary')),
categoryid: Joi.number().integer().required(),
subcategoryid: Joi.number().integer().required(),
tlalocid: Joi.number().integer().required(),
});
// Endpoint to add a new saved search for a user
app.post('/users/:userId/savedsearches', async (req, res) => {
const userId = req.params.userId;
const searchDetails = req.body;
// Validate the new search data without the ID
const { error } = searchSchema.validate(searchDetails);
if (error) {
return res.status(400).send({ error: error.details[0].message });
}
// Generate a unique ID for the new search
const searchId = uuidv4();
const newSearch = { ...searchDetails, id: searchId };
try {
const getResult = await dynamoDb.get({
TableName: TABLE_NAME,
Key: { userId },
}).promise();
let savedSearches = getResult.Item ? getResult.Item.savedSearches : [];
if (savedSearches.length >= MAX_SAVED_SEARCHES) {
return res.status(400).send({ error: 'Maximum number of saved searches reached.' });
}
// Add the new search with ID to the list
savedSearches.push(newSearch);
await dynamoDb.put({
TableName: TABLE_NAME,
Item: { userId, savedSearches },
}).promise();
res.status(201).send({ message: 'Saved search added successfully.', id: searchId });
} catch (error) {
res.status(500).send({ error: 'Failed to add saved search.' });
}
});
// Endpoint to retrieve all saved searches for a user
app.get('/users/:userId/savedsearches', async (req, res) => {
const userId = req.params.userId;
try {
const result = await dynamoDb.get({
TableName: TABLE_NAME,
Key: { userId },
}).promise();
if (!result.Item) {
return res.status(404).send({ error: 'User not found.' });
}
res.status(200).send(result.Item.savedSearches);
} catch (error) {
res.status(500).send({ error: 'Failed to retrieve saved searches.' });
}
});
// Endpoint to delete a specific saved search for a user using the search ID
app.delete('/users/:userId/savedsearches/:searchId', async (req, res) => {
const userId = req.params.userId;
const searchId = req.params.searchId;
try {
const getResult = await dynamoDb.get({
TableName: TABLE_NAME,
Key: { userId },
}).promise();
if (!getResult.Item) {
return res.status(404).send({ error: 'User not found.' });
}
// Filter out the search to delete by ID
const updatedSearches = getResult.Item.savedSearches.filter(search => search.id !== searchId);
// Update the item with the filtered searches
await dynamoDb.put({
TableName: TABLE_NAME,
Item: { userId, savedSearches: updatedSearches },
}).promise();
res.status(200).send({ message: 'Saved search deleted successfully.' });
} catch (error) {
res.status(500).send({ error: 'Failed to delete saved search.' });
}
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment