Skip to content

Commit

Permalink
feat: add chapter 5.9.2
Browse files Browse the repository at this point in the history
  • Loading branch information
wbruno committed Jun 4, 2023
1 parent f3da2e6 commit ab45be5
Show file tree
Hide file tree
Showing 15 changed files with 500 additions and 1 deletion.
2 changes: 1 addition & 1 deletion capitulo_5/5.9.1/test/handler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const event = {
it('#redirect', async () => {
const result = await redirect(event)
expect(result.statusCode).toBe(301)
expect(result.headers).toEqual({ Location: 'https://novatec.com.br/livros/nodejs-3ed/' })
expect(result.headers).toEqual({ Location: 'https://www.novatec.com.br/livros/nodejs-3ed/' })
expect(typeof result.body).toBe('string')
})
it('#redirect link non existent', async () => {
Expand Down
1 change: 1 addition & 0 deletions capitulo_5/5.9.2/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
18
7 changes: 7 additions & 0 deletions capitulo_5/5.9.2/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('jest').Config} */
const config = {
testEnvironment: 'jest-environment-node',
verbose: true,
setupFiles: ['./test/setup.js']
}
module.exports = config
28 changes: 28 additions & 0 deletions capitulo_5/5.9.2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "5.9.1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "export DEBUG=wbruno:*; npx sls dynamodb install --stage local --region sa-east-1; npx sls offline start --stage local --region sa-east-1",
"test": "jest --coverage"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@aws-sdk/client-dynamodb": "3.345.0",
"@aws-sdk/lib-dynamodb": "3.345.0",
"debug": "4.3.4",
"nanoid": "3.3.6"
},
"devDependencies": {
"aws-sdk-client-mock": "2.1.1",
"dotenv": "16.1.3",
"jest": "29.5.0",
"serverless": "3.32.2",
"serverless-domain-manager": "7.0.4",
"serverless-dynamodb-local": "0.2.40",
"serverless-offline": "12.0.4"
}
}
10 changes: 10 additions & 0 deletions capitulo_5/5.9.2/resources/db/shorts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"id": "iNxun1bg5Y",
"link": "https://www.novatec.com.br/livros/nodejs-3ed/"
},
{
"id": "typescript",
"link": "https://www.novatec.com.br/livros/aprendendo-typescript/"
}
]
23 changes: 23 additions & 0 deletions capitulo_5/5.9.2/resources/serverless.local.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
provider:
vpc:
securityGroupIds:
- sg-..
subnetIds:
- subnet-..
iam:
role:
name: serverless-${self:service}-${self:provider.stage}-role
resources:
Resources: ${file(resources/table.yml)}
apiGateway:
apiKeys:
- name: localKey
value: d41d8cd98f00b204e9800998ecf8427e
custom:
customDomain:
domainName: localhost
environment:
AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1
AWS_REGION: sa-east-1
NODE_ENV: development
DYNAMODB_ENDPOINT: http://localhost:8000
11 changes: 11 additions & 0 deletions capitulo_5/5.9.2/resources/table.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
shortenerTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: Shortener
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
116 changes: 116 additions & 0 deletions capitulo_5/5.9.2/serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
service: shortener
plugins:
- serverless-domain-manager
- serverless-dynamodb-local
- serverless-offline #needs to be last in the list
useDotenv: true
configValidationMode: warn
package:
individually: false
excludeDevDependencies: true
patterns:
- node_modules/**
- src/**
provider:
name: aws
architecture: arm64
region: ${opt:region}
stage: ${opt:stage}
runtime: nodejs18.x
versionFunctions: true
logRetentionInDays: 3
timeout: 30
stackName: serverless-${self:service}-${self:provider.stage}
memorySize: 128
tracing:
apiGateway: true
apiGateway:
apiKeys: ${file(./resources/serverless.${self:provider.stage}.yml):apiGateway.apiKeys, ''}
apiKeySourceType: HEADER
disableDefaultEndpoint: true
stackTags:
Name: ${self:service}
deploymentBucket:
name: algum-s3-${self:provider.stage}-deployment
environment: ${file(./resources/serverless.${self:provider.stage}.yml):environment}
iam: ${file(./resources/serverless.${self:provider.stage}.yml):provider.iam, ''}
logs:
restApi:
accessLogging: false
executionLogging: false
functions:
redirect:
description: redirects hash to given url
handler: src/handler.redirect
events:
- http:
path: /{id}
method: get
cors: true
private: false
byId:
description: retrieve a shortened url by its id
handler: src/shortener.byId
events:
- http:
path: /shorts/{id}
method: get
cors: true
private: true
create:
description: create a new shortened url
handler: src/shortener.create
events:
- http:
path: /shorts
method: post
cors: true
private: true
list:
description: list all shortened urls
handler: src/shortener.list
events:
- http:
path: /shorts
method: get
cors: true
private: true
update:
description: update a new shortened url
handler: src/shortener.update
events:
- http:
path: /shorts/{id}
method: put
cors: true
private: true
remove:
description: remove a new shortened url
handler: src/shortener.remove
events:
- http:
path: /shorts/{id}
method: delete
cors: true
private: true
resources: ${file(./resources/serverless.${self:provider.stage}.yml):resources, ''}
custom:
dynamodb:
stages:
- local
start:
seed: true
migrate: true
seed:
domain:
sources:
- table: Shortener
sources: [./resources/db/shorts.json]
endpoints:
dynamodb-url: 'http://localhost:8000'
customDomain:
enabled: true
domainName: ${self:service}.${self:provider.stage}.seudominio.com.br
stage: ${self:provider.stage}
createRoute53Record: false
basePath: ''
15 changes: 15 additions & 0 deletions capitulo_5/5.9.2/src/config/dynamodb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb')
const { DynamoDBDocumentClient } = require('@aws-sdk/lib-dynamodb')

const marshallOptions = {
removeUndefinedValues: true
}

const localConfig = { endpoint: process.env.DYNAMODB_ENDPOINT }
/* istanbul ignore next */
const config = process.env.DYNAMODB_ENDPOINT ? localConfig : {}

const dynamodb = new DynamoDBClient(config)
const documentClient = DynamoDBDocumentClient.from(dynamodb, { marshallOptions })

module.exports = { dynamodb, documentClient }
27 changes: 27 additions & 0 deletions capitulo_5/5.9.2/src/handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const html = `<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
</body>
</html>`
const repository = require('./repository')
const redirect = (event) => {
const params = event.pathParameters

return repository.byId(params.id)
.then(result => {
console.log({ result })
if (!result?.link) {
throw new Error('not found')
}
return result
})
.then(result => {
const headers = { Location: result.link }
return { statusCode: 301, headers, body: html }
})
.catch((err) => {
return { statusCode: 404, body: JSON.stringify(err) }
})
}
module.exports = { redirect }
74 changes: 74 additions & 0 deletions capitulo_5/5.9.2/src/repository.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const { ScanCommand, GetCommand, PutCommand, DeleteCommand } = require('@aws-sdk/lib-dynamodb')
const debug = require('debug')('wbruno:repository')
const { nanoid } = require('nanoid')
const { documentClient } = require('./config/dynamodb')
const getNextLink = (data) => {
if (data?.LastEvaluatedKey) {
const urlParams = qs.stringify(data.LastEvaluatedKey)
return {
rel: 'next',
href: `?${urlParams}`
}
}
return {}
}
const repository = {
DEFAULT_SIZE: '50',
TABLE_NAME: 'Shortener',

list(query, sizeParam) {
const size = parseInt(sizeParam || this.DEFAULT_SIZE, 10)

const config = {
TableName: this.TABLE_NAME,
Limit: size
}

if (Reflect.has(query, 'id')) {
config.ExclusiveStartKey = { id: query.id }
}
debug({ config })

const params = new ScanCommand(config)
return documentClient.send(params).then((result) => {
return {
size,
links: [getNextLink(result)],
items: result.Items || []
}
})
},

byId(id) {
debug({ id })
const params = new GetCommand({
Key: { id },
TableName: this.TABLE_NAME
})
return documentClient.send(params).then((result) => result.Item)
},

put(data, existendId) {
const id = existendId || nanoid()
const params = new PutCommand({
TableName: this.TABLE_NAME,
Item: {
id,
...data
},
ReturnValues: 'ALL_OLD'
})

return documentClient.send(params)
},

delete(id) {
const params = new DeleteCommand({
TableName: this.TABLE_NAME,
Key: { id }
})

return documentClient.send(params).then((_) => ({}))
}
}
module.exports = repository
Loading

0 comments on commit ab45be5

Please sign in to comment.