- Postman for
testing
- serverless-offline for
local api development
- Postgres as
database
in Heroku
- Sequelize as the
ORM
- Controllers: defined in files like
handler.ts
- Routers:
serverless.yml
- Models:
./src/models
- Services:
./src/services
- id: integer (
primary key
,not null
,auto-incrementing
)
- task: string
- completed: boolean(default
false
)
- created_at: date(default
today
)
- updated_at: date(default
today
)
- deleted_at: date
Sequelize with Typescript
yarn add sequelize sequelize-typescript reflect-metadata
yarn add --dev @types/validator @types/node @types/bluebird
@Table({
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
deletedAt: 'deleted_at',
paranoid: true,
underscored: true,
})
export class Todo extends Model<Todo> {
@Column({
type: DataType.STRING
})
task?: string;
@Column({
defaultValue: false,
type: DataType.BOOLEAN
})
complete?: boolean;
}
// postgres
export const sequelize = new Sequelize(config.get("POSTGRES.URI"), {
dialect: 'postgres',
dialectOptions: {
ssl: true
},
models: [Todo]
});
export const seed = async (func: Function) => {
await sequelize.sync();
const result = await func();
sequelize.close();
return result;
}
// Rreate one
seed(async () => {
await Todo.create({
task: 'wash dish',
complete: true
})
})
// Read One
seed(async () => {
const todo: Todo = await Todo.findOne({
where: { id: 2 }
})
console.log(todo.id);
})
// Read Many
seed(async () => {
const todos: Todo[] = await Todo.findAll({
where: { id: 2 }
})
console.log(todos);
})
// Update One
seed(async () => {
const todo = await Todo.findOne({
where: { id: 2 }
});
if (todo) {
await todo.update({
task: 'Happy Update'
})
}
})
// Remove One logically
seed(async () => {
const todo = await Todo.findOne({
where: { id: 2 }
})
if (todo) {
await todo.destroy();
}
})
// Remove All logically
seed(async () => {
await Todo.destroy({
where: { id: 1 }
})
})
// Remove One physically
seed(async () => {
const todo = await Todo.findOne({
where: { id: 1 }
})
if (todo) {
await todo.destroy({ force: true });
}
})
// Remove All physically
seed(async () => {
await Todo.destroy({
where: { id: 2 },
force: true
})
})
export const create: APIGatewayProxyHandler = async (event, _context) => {
try {
const todo = await Todo.create(JSON.parse(event.body));
return {
statusCode: 200,
body: JSON.stringify({
data: todo ? todo.toJSON() : null
})
}
} catch (err) {
return {
statusCode: 400,
body: "Internal Error"
}
}
}
Set Environment Variables
provider:
name: aws
stage: dev
environment:
SYSTEM_ID: jdoe
functions:
hello:
handler: handler.hello
environment:
SYSTEM_URL: http://example.com/api/v1
provider:
# ...
apiKeys:
- firstKey
# ...
functions:
create:
handler: src/controllers/todo.create
events:
- http:
method: post
path: todo
private: true
- use
x-api-key
in the header
- apiKeys will be
printed
after deployment in the console
Error: Please install pg package manually
// webpack.config.js
const nodeExternals = require('webpack-node-externals');
module.exports = {
...
externals: [nodeExternals()],
...
yarn remove serverless-webpack webpack
yarn add --dev serverless-plugin-typescript typescript
plugins:
- serverless-plugin-typescript
"compilerOptions": {
"module": "commonjs",
"strictNullChecks": false,
"pretty": true,
"skipLibCheck": false,
"lib": ["es2015"],
"moduleResolution": "node",
"noUnusedParameters": true,
"sourceMap": true,
"target": "es6",
"outDir": ".build", // mandatory
"rootDir": "./", // mandatory
"allowSyntheticDefaultImports": true,
"allowJs": true,
"strict": true,
"noImplicitAny": true,
"esModuleInterop":true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
The response is very slow using Sequelize
- Oh man, this is not becuase
Sequelize
. It's because you're far from the Database Server
.
- If you have many servers hosted in different places in the world, use
cloudfront
to help you request to the nearest server.
- By the way,
within
the API you have to do response synchronously
.
- But when you are outside the API, for instance in the frontedn, you should do call
asychronously
Should Sync before using any model
- If you don't
sync()
before using the model, you will get an error like "Todo" needs to be added to a Sequelize instance.
- One way to deal with
sync()
to do add it to every controber so required you to add sync()
a lot of times.Bad
// postgres: no seqeulize.sync() call
// in controllers
await sequelize.sync();
const todo = await Todo.create(JSON.parse(event.body));
- Another way to deal with
sync()
:
// Todo.ts add before CRUD method
sequelize.addModels([Todo]); // will synchronize with database and and models
- Automatically call
sync()
before you want to use model
// postgres.ts add
sequelize.sync().then(() => {
console.log("Synchornization Done.")
}).catch(() => console.log("Synchronization Failed."))
What is the difference between PATCH
and PUT
?
PATCH
is used to update parts of an object. Default
PUT
is used to update the whole object.