Skip to content

Instantly share code, notes, and snippets.

@yoonhoGo
Last active July 23, 2019 23:29
Show Gist options
  • Save yoonhoGo/8d7e914ba558375642e311ff723e5732 to your computer and use it in GitHub Desktop.
Save yoonhoGo/8d7e914ba558375642e311ff723e5732 to your computer and use it in GitHub Desktop.
Node.js 서버리스 프레임웍을 사용하여 싱글페이지 포트폴리오 제작하기 7
const AWS = require('aws-sdk')
const express = require('express')
const bodyParser = require('body-parser')
/**
* 만약 profile을 쓰고 싶다면?
*/
// if (process.env.STAGE === 'local') {
// const credentials = new AWS.SharedIniFileCredentials({profile: 'isMe'});
// AWS.config.credentials = credentials;
// }
const dynamodb = new AWS.DynamoDB.DocumentClient({
region: 'ap-northeast-2',
})
const app = express()
app.use(bodyParser())
app.post('/api/contact', (req, res, next) => {
if (!req.body.name) {
throw new Error('please give a param `name`.')
} else if (!req.body.subject) {
throw new Error('please give a param `subject`.')
}
next()
}, async (req, res) => {
const portfolioContect = await dynamodb.put({
TableName: 'portfolio-contact',
Item: {
createdAt: Date.now(),
name: req.body.name,
email: req.body.email || undefined,
tel: req.body.tel || undefined,
subject: req.body.subject,
question: req.body.question || undefined,
},
// ReturnValues: 'ALL_NEW',
}).promise()
res.json(req.body)
})
module.exports = app
'use strict';
const serverless = require('serverless-http')
const app = require('./api')
module.exports.handler = serverless(app)
<!DOCTYPE html>
<html class="has-navbar-fixed-top">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hello AUSG!</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css">
<script defer src="https://use.fontawesome.com/releases/v5.1.0/js/all.js"></script>
</head>
<body>
<nav class="navbar is-black is-fixed-top" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="#main">
<img src="./static/images/AUSG_Branding-07.png" alt="AUSG: AWSKRUG University Student Group!">
&nbsp; AUSG
</a>
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu">
<div class="navbar-start">
<!-- navbar items -->
<a class="navbar-item" href="#main">
Home
</a>
<a class="navbar-item" href="#about">
About
</a>
<a class="navbar-item" href="#contact">
Contact
</a>
</div>
<div class="navbar-end">
<!-- navbar items -->
<a class="navbar-item has-text-warning" href="http://www.awskr.org/">
<span class="icon">
<i class="fas fa-home"></i>
</span>
</a>
<a class="navbar-item has-text-white" href="https://github.com/AUSG">
<span class="icon">
<i class="fab fa-github"></i>
</span>
</a>
</div>
</div>
</nav>
<section class="hero is-fullheight is-warning" id="main">
<div class="hero-body">
<div class="container">
<h1 class="title">
Hello AUSG!
</h1>
<h2 class="subtitle">
My first website with <strong>Bulma</strong>!
</h2>
</div>
</div>
</section>
<section class="hero is-fullheight is-dark" id="about">
<div class="hero-body">
<div class="container">
<h1 class="title">
About
</h1>
<h2 class="subtitle">
안녕하세요. 저는 이번 발표를 맡은 고윤호라고 합니다.<br />
AUSG 세미나에 오신걸 환영합니다. 부디 오신 기대만큼 가져가시는 시간 되시기 바랍니다.
</h2>
</div>
</div>
</section>
<section class="section" id="contact">
<div class="container">
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">From</label>
</div>
<div class="field-body">
<div class="field">
<p class="control is-expanded has-icons-left">
<input class="input is-danger" type="text" placeholder="Name" id="name">
<span class="icon is-small is-left">
<i class="fas fa-user"></i>
</span>
</p>
<p class="help is-danger">
This field is required
</p>
</div>
<div class="field">
<p class="control is-expanded has-icons-left has-icons-right">
<input class="input" type="email" placeholder="Email" id="email">
<span class="icon is-small is-left">
<i class="fas fa-envelope"></i>
</span>
</p>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label"></div>
<div class="field-body">
<div class="field is-expanded">
<div class="field has-addons">
<p class="control">
<a class="button is-static">
+82
</a>
</p>
<p class="control is-expanded">
<input class="input" type="tel" placeholder="Your phone number" id="tel">
</p>
</div>
<p class="help">Do not enter the first zero</p>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">Subject</label>
</div>
<div class="field-body">
<div class="field">
<div class="control">
<input class="input is-danger" type="text" placeholder="e.g. Partnership opportunity" id="subject">
</div>
<p class="help is-danger">
This field is required
</p>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">Question</label>
</div>
<div class="field-body">
<div class="field">
<div class="control">
<textarea class="textarea" placeholder="Explain how we can help you" id="question"></textarea>
</div>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label">
<!-- Left empty for spacing -->
</div>
<div class="field-body">
<div class="field">
<div class="control">
<button class="button is-primary" type="submit" onclick="onContact()">
Send message
</button>
</div>
</div>
</div>
</div>
</div>
</section>
<footer class="footer">
<div class="content has-text-centered">
<p>
AUSG is Awesome Ultra Special Group.
</p>
</div>
</footer>
<script>
async function onContact() {
const data = JSON.stringify({
name: document.getElementById('name').value,
email: document.getElementById('email').value,
tel: document.getElementById('tel').value,
subject: document.getElementById('subject').value,
question: document.getElementById('question').value,
})
fetch('./api/contact', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: data,
}).then(response => alert('메시지 감사해요! 😄'))
.catch(error => alert('전송 실패했어요 😂'))
}
</script>
</body>
</html>
service: MyPortfolio
provider:
name: aws
runtime: nodejs8.10
stage: ${opt:stage, 'dev'}
region: ap-northeast-2
environment:
STAGE: ${self:provider.stage}
functions:
web:
handler: webHandler.handler
events:
- http:
path: /
method: ANY
cors: true
- http:
path: /{proxy+}
method: ANY
cors: true
api:
handler: apiHandler.handler
events:
- http:
path: /api
method: ANY
cors: true
- http:
path: /api/{proxy+}
method: ANY
cors: true
role: apiRole
resources:
Resources:
portfolioContactTable: # dynamodb table logicalName
Type: AWS::DynamoDB::Table
Properties:
TableName: portfolio-contact
AttributeDefinitions:
- AttributeName: createdAt
AttributeType: N
KeySchema:
- AttributeName: createdAt
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
apiRole:
Type: AWS::IAM::Role
Properties:
RoleName: ApiRole
Path: "/portfolio/api/"
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: root
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: arn:aws:logs:*:*:*
- PolicyName: forDynamo
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:PutItem
Resource:
Fn::GetAtt: portfolioContactTable.Arn # dynamodb table logicalName
plugins:
- serverless-offline
const express = require('express')
const app = express()
app.use('/static', (req, res) => {
const staticURI = 'https://raw.githubusercontent.com/yoonhoGo/serverless-spa-portfolio/master/static'
res.redirect(`${staticURI}${req.path}`)
})
app.get('/', (req, res) => {
res.type('html').sendFile(__dirname + '/index.html')
})
module.exports = app
'use strict';
const serverless = require('serverless-http')
const app = require('./web')
module.exports.handler = serverless(app)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment