Complete swap from express and aws to express and heroku due to the much smaller learning curve needed for a herkou build

This commit is contained in:
Gregory Campbell
2021-11-23 15:01:58 -05:00
parent 58de36beb0
commit ba98c76e23
11 changed files with 1963 additions and 240 deletions
+3
View File
@@ -0,0 +1,3 @@
#ignore all env files
*.env
node_modules
+1
View File
@@ -0,0 +1 @@
web:node server.js
+85
View File
@@ -0,0 +1,85 @@
const Msg = require('../models/msg'); //import msg model
//GET all messages
const getAllMsg = (req, res) => {
Msg.find({}, (err, data)=>{
if (err){
return res.json({Error: err});
}
return res.json(data);
})
};
//POST message
const newMsg = (req, res) => {
//check if the id already exists in db
Msg.findOne({ id: req.body.id }, (err, data) => {
//if tea not in db, add it
if (!data) {
//create a new tea object using the Msg model and req.body
const newMsg = new Msg({
id:req.body.id,
message: req.body.message,
time: Date.now(),
})
// save this object to database
newMsg.save((err, data)=>{
if(err) return res.json({Error: err});
return res.json(data);
})
//if there's an error or the msg is in db, return an error message
}else{
if(err) return res.json(`Something went wrong, please try again. ${err}`);
return res.json({message:"Msg already exists"});
}
})
};
//DELETE all messages
const deleteAllMsg = (req, res) => {
Msg.deleteMany({}, err => {
if(err) {
return res.json({message: "Deletion of all messages failed"});
}
return res.json({message: "Deletion of all messages successful"});
})
};
//GET message based on id
const getOneMsg = (req, res) => {
let id = req.params.id; //get the msg id
//find the specific msg with that id
Msg.findOne({id:id}, (err, data) => {
if(err || !data) {
return res.json({message: "Message doesn't exist."});
}
else return res.json(data); //return the msg object if found
});
};
//DELETE message based on id
const deleteOneMsg = (req, res) => {
let id = req.params.id; // get the id of msg to delete
Msg.deleteOne({id:id}, (err, data) => {
//if there's nothing to delete return a message
if( data.deletedCount == 0) return res.json({message: "Message doesn't exist."});
//else if there's an error, return the err message
else if (err) return res.json(`Something went wrong, please try again. ${err}`);
//else, return the success message
else return res.json({message: "Message deleted."});
});
};
//export controller functions
module.exports = {
getAllMsg,
newMsg,
deleteAllMsg,
getOneMsg,
deleteOneMsg
};
+2
View File
@@ -0,0 +1,2 @@
<h1>Welcome to RESTapi Demo</h1>
<p>Enjoy sending messages around</p>
-69
View File
@@ -1,69 +0,0 @@
"use strict";
var AWS = require('aws-sdk');
// Get "Hello" Dynamo table name. Replace DEFAULT_VALUE
// with the actual table name from your stack.
const helloDBArn = process.env['HELLO_DB'] || 'DEFAULT_VALUE'; //'Mark-HelloTable-1234567';
const helloDBArnArr = helloDBArn.split('/');
const helloTableName = helloDBArnArr[helloDBArnArr.length - 1];
// handleHttpRequest is the entry point for Lambda requests
exports.handleHttpRequest = function(request, context, done) {
try {
const userId = request.pathParameters.userId;
let response = {
headers: {},
body: '',
statusCode: 200
};
switch (request.httpMethod) {
case 'GET': {
console.log('GET');
let dynamo = new AWS.DynamoDB();
var params = {
TableName: helloTableName,
Key: { 'user_id' : { S: userId } },
ProjectionExpression: 'email'
};
// Call DynamoDB to read the item from the table
dynamo.getItem(params, function(err, data) {
if (err) {
console.log("Error", err);
throw `Dynamo Get Error (${err})`
} else if (data.Item) {
console.log("Success", data.Item.email);
response.body = JSON.stringify({ "email": data.Item.email.S });
done(null, response);
} else {
console.log("Not found id=", userId);
response.body = "Not found"
response.statusCode = 404
done(null, response);
}
});
break;
}
case 'POST': {
console.log('POST');
let bodyJSON = JSON.parse(request.body || '{}');
let dynamo = new AWS.DynamoDB();
let params = {
TableName: helloTableName,
Item: {
'user_id': { S: userId },
'email': { S: bodyJSON['email'] }
}
};
dynamo.putItem(params, function(error, data) {
if (error) throw `Dynamo Error (${error})`;
else done(null, response);
})
break;
}
}
} catch (e) {
done(e, null);
}
}
+11
View File
@@ -0,0 +1,11 @@
const mongoose = require("mongoose"); //import mongoose
// msg schema
const MsgSchema = new mongoose.Schema({
id: {type:Number, required:true},
message: {type:String, required:true},
time: {type:Date, required:true}
})
const Msg = mongoose.model('Msg', MsgSchema); //convert to model named Msg
module.exports = Msg; //export for controller use
+1769
View File
File diff suppressed because it is too large Load Diff
+36
View File
@@ -0,0 +1,36 @@
{
"name": "restapi_demo",
"version": "1.0.0",
"description": "REST api written with express and run with heroku",
"main": "server.js",
"scripts": {
"start": "node server.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/gjcampbell777/RESTapi_demo.git"
},
"keywords": [
"js",
"express",
"node",
"heroku",
"rest",
"api"
],
"author": "Gregory Campbell",
"license": "ISC",
"bugs": {
"url": "https://github.com/gjcampbell777/RESTapi_demo/issues"
},
"homepage": "https://github.com/gjcampbell777/RESTapi_demo#readme",
"dependencies": {
"compression": "^1.7.4",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"helmet": "^4.6.0",
"mongoose": "^6.0.13",
"multer": "^1.4.3"
}
}
+19
View File
@@ -0,0 +1,19 @@
const express = require('express'); //import express
const multer = require('multer');
const upload = multer();
const router = express.Router();
const msgController = require('../controllers/msg');
router.post('/msg', upload.none(), msgController.newMsg);
router.get('/msg', msgController.getAllMsg);
router.post('/msg', msgController.newMsg);
router.delete('/msg', msgController.deleteAllMsg);
router.get('/msg/:id', msgController.getOneMsg);
//router.put('/msg/:id', msgController.updateMsg);
router.delete('/msg/:id', msgController.deleteOneMsg);
module.exports = router; //export to use in server.js
+37
View File
@@ -0,0 +1,37 @@
require('dotenv').config({ path: 'development.env' });
const express = require('express');
const routes = require('./routes/msg'); //import the routes
const mongoose = require('mongoose'); //import mongoose
const helemt = require('helmet'); //import helmet
const compression = require('compression'); //import compression
const app = express();
app.use(helmet());
app.use(compression()); //compress all routes
mongoose.connect(
process.env.MONGODB_URI,
{
server: { socketOptions: { keepAlive: 300000, connectTimeoutMS: 30000 } },
replset: { socketOptions: { keepAlive: 300000, connectTimeoutMS : 30000 } },
},
(err) => {
if (err) return console.log("Error: ", err);
console.log("MongoDB Connection -- Ready state is:", mongoose.connection.readyState);
}
);
app.use(express.json()); //parses incoming requests with JSON payloads
app.use('/', routes); //to use the routes
app.route('/')
.get(function (req, res) {
res.sendFile(process.cwd() + '/index.html');
});
const listener = app.listen(process.env.PORT || 3000, () => {
console.log('App is listening on port ' + listener.address().port)
})
-171
View File
@@ -1,171 +0,0 @@
---
AWSTemplateFormatVersion: 2010-09-09
Description: API Gateway, Lambda, and Dynamo.
Resources:
# Policy required for all lambda function roles.
BaseLambdaExecutionPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
Description: Base permissions needed by all lambda functions.
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- ec2:CreateNetworkInterface
- ec2:DescribeNetworkInterfaces
- ec2:DeleteNetworkInterface
Resource: "*"
HelloTable:
Type: AWS::DynamoDB::Table
Properties:
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
AttributeDefinitions:
- AttributeName: user_id
AttributeType: S
KeySchema:
- AttributeName: user_id
KeyType: HASH
# FIXME How to hook up custom domain?
MyApiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Sub "${AWS::StackName}-MyApiGateway"
Description: A description
FailOnWarnings: true
Body:
swagger: 2.0
info:
description: |
The account API.
version: 1.0
basePath: /
schemes:
- https
consumes:
- application/json
produces:
- application/json
paths:
/users/{userId}/hello:
get:
description: TBD
x-amazon-apigateway-integration:
uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloLambda.Arn}/invocations"
credentials: !GetAtt MyApiGatewayRole.Arn
passthroughBehavior: when_no_match
httpMethod: POST
type: aws_proxy
operationId: getHello
parameters:
- name: userId
in: path
description: TBD
required: true
type: string
format: uuid
post:
description: TBD
x-amazon-apigateway-integration:
uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloLambda.Arn}/invocations"
credentials: !GetAtt MyApiGatewayRole.Arn
passthroughBehavior: when_no_match
httpMethod: POST
type: aws_proxy
operationId: postHello
parameters:
- name: userId
in: path
description: TBD
required: true
type: string
format: uuid
- name: body
in: body
description: TBD
required: true
schema:
type: object
required:
- email
properties:
email:
type: string
MyApiGatewayDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref MyApiGateway
StageName: prod
MyApiGatewayRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: apigateway.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: InvokeLambda
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- lambda:InvokeFunction
Resource:
- !GetAtt HelloLambda.Arn
HelloLambda:
Type: AWS::Lambda::Function
Properties:
Role: !GetAtt HelloLambdaRole.Arn # TODO
Handler: index.handleHttpRequest
Runtime: nodejs12.x
Environment:
Variables:
HELLO_DB: !Sub "arn:aws:dynamodb:${AWS::Region}:*:table/${HelloTable}"
Code:
ZipFile: |
exports.handlers = function(event, context) {}
HelloLambdaRole: # -> AppAPIRole
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- !Ref BaseLambdaExecutionPolicy
Policies:
- PolicyName: getHello
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:GetItem
Resource: !Sub "arn:aws:dynamodb:${AWS::Region}:*:table/${HelloTable}"
- PolicyName: putHello
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:PutItem
Resource: !Sub "arn:aws:dynamodb:${AWS::Region}:*:table/${HelloTable}"