IaC serverless v4
- Ejecutar en terminal
serverless
y seleccionar plantilla ❯ AWS / Node.js / HTTP API npm init
serverless.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
org: jrcoding
service: iac-serverless
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
memorySize: 128
stage: ${opt:stage, 'dev'}
functions:
hello:
handler: handler.hello
events:
- httpApi:
path: /
method: get
sls deploy --verbose
- probar endpoint
sls remove --verbose
Cambiar la ubicación de la función inicial
src/handlers/postProduct.mjs
1
2
3
4
5
6
7
8
exports.handler = async (event) => {
return {
statusCode: 200,
body: JSON.stringify({
message: "Lambda Post Product!",
}),
};
};
serverless.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
org: jrcoding
service: iac-serverless
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
memorySize: 128
stage: ${opt:stage, 'dev'}
functions:
postProduct:
handler: src/handlers/postProduct.handler
events:
- httpApi:
path: /product
method: GET
sls deploy --verbose
- probar endpoint
DynamoDB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
org: jrcoding
service: iac-serverless
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
memorySize: 128
stage: ${opt:stage, 'dev'}
resources:
Resources:
InventoryTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: inventory
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
functions:
postProduct:
handler: src/handlers/postProduct.handler
events:
- httpApi:
path: /producto
method: POST
sls deploy --verbose
- verificar que la tabla fue creada
Crear producto
npm i uuid
npm install @aws-sdk/client-dynamodb
npm install @aws-sdk/lib-dynamodb
- Modificar
src/handlers/postProduct.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, PutCommand } from "@aws-sdk/lib-dynamodb";
import { v4 as uuid } from "uuid";
const dynamo = DynamoDBDocumentClient.from(new DynamoDBClient({}));
export const handler = async (event, context) => {
try {
const product = JSON.parse(event.body);
const newProduct = {
...product,
id: uuid(),
created_at: new Date().toLocaleString('es-SV'),
};
const headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
};
await dynamo.send(new PutCommand({
TableName: "inventory",
Item: newProduct,
}));
return {
statusCode: 201,
headers: headers,
body: JSON.stringify(newProduct),
};
}
catch (error) {
console.log(error);
return {
statusCode: 500,
body: JSON.stringify({ message: error.message }),
};
}
};
- Modificar
serverless.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
org: jrcoding
service: iac-serverless
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
memorySize: 128
stage: ${opt:stage, 'dev'}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:PutItem
Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/inventory"
resources:
Resources:
InventoryTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: inventory
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
functions:
postProduct:
handler: src/handlers/postProduct.handler
events:
- httpApi:
path: /product
method: POST
sls deploy --verbose
- probar endpoint en postman e ingresar los datos:
1
2
3
4
5
6
7
{
"name" :"PS5",
"brand" : "SONY",
"price" : 699.99,
"comments" : "Consola de videojuegos",
"stock" : 45
}
Listar Productos
- Crear
src/handlers/getProducts.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, ScanCommand } from "@aws-sdk/lib-dynamodb";
const dynamo = DynamoDBDocumentClient.from(new DynamoDBClient({}));
export const handler = async (event, context) => {
try {
let products;
const result = await dynamo.send(new ScanCommand({
TableName: "inventory",
}));
products = result.Items;
const headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
};
return {
statusCode: 200,
headers: headers,
body: JSON.stringify(products),
};
}
catch (error) {
console.log(error);
return {
statusCode: 500,
body: JSON.stringify({ message: error.message }),
};
}
};
- Modificar
serverless.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
org: jrcoding
service: iac-serverless
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
memorySize: 128
stage: ${opt:stage, 'dev'}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:Scan
Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/inventory"
resources:
Resources:
InventoryTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: inventory
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
functions:
postProduct:
handler: src/handlers/postProduct.handler
events:
- httpApi:
path: /product
method: POST
getProducts:
handler: src/handlers/getProducts.handler
events:
- httpApi:
path: /products
method: GET
sls deploy --verbose
- Probar endpoint en Postman
Obtener Producto
- Crear
src/handlers/getProduct.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, GetCommand } from "@aws-sdk/lib-dynamodb";
const dynamo = DynamoDBDocumentClient.from(new DynamoDBClient({}));
export const handler = async (event, context) => {
let product;
const { id } = event.pathParameters;
const headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
};
try {
const result = await dynamo.send(new GetCommand({
TableName: "inventory",
Key: { id }
}));
product = result.Item;
}
catch (error) {
console.log(error);
return {
statusCode: 500,
body: JSON.stringify({ message: error.message }),
};
}
if (!product) {
return {
statusCode: 404,
headers: headers,
body: JSON.stringify({ message: "Producto no encontrado" }),
};
}
return {
statusCode: 200,
headers: headers,
body: JSON.stringify(product),
};
};
- Modificar
serverless.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
org: jrcoding
service: iac-serverless
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
memorySize: 128
stage: ${opt:stage, 'dev'}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:Scan
- dynamodb:GetItem
Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/inventory"
resources:
Resources:
InventoryTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: inventory
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
functions:
postProduct:
handler: src/handlers/postProduct.handler
events:
- httpApi:
path: /product
method: POST
getProducts:
handler: src/handlers/getProducts.handler
events:
- httpApi:
path: /products
method: GET
getProduct:
handler: src/handlers/getProduct.handler
events:
- httpApi:
path: /product/{id}
method: GET
sls deploy --verbose
- Probar endpoint en Postman
Modificar Producto
- Crear
src/handlers/putProduct.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, GetCommand, UpdateCommand } from "@aws-sdk/lib-dynamodb";
const dynamo = DynamoDBDocumentClient.from(new DynamoDBClient({}));
export const handler = async (event, context) => {
try {
const id = event.pathParameters?.id;
const { name, brand, price, comments, stock } = JSON.parse(event.body);
// Verificar si el registro existe antes de actualizarlo
const result = await dynamo.send(new GetCommand({
TableName: "inventory",
Key: { id: id },
}));
if (!result.Item) {
return {
statusCode: 404,
body: JSON.stringify({ message: "Registro no encontrado" }),
};
}
const headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
};
// Actualizar el registro existente
await dynamo.send(new UpdateCommand({
TableName: "inventory",
Key: { id: id },
UpdateExpression: "SET #name = :name, brand = :brand, price = :price, comments = :comments, stock = :stock",
ExpressionAttributeNames: {
"#name": "name",
},
ExpressionAttributeValues: {
":name": name,
":brand": brand,
":price": price,
":comments": comments,
":stock": stock,
},
ReturnValues: "ALL_NEW",
}));
}
catch (error) {
console.log(error);
return {
statusCode: 500,
body: JSON.stringify({ message: error.message }),
};
}
return {
statusCode: 200,
body: JSON.stringify({ message: "Registro actualizado exitosamente" }),
};
};
- Modificar
serverless.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
org: jrcoding
service: iac-serverless
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
memorySize: 128
stage: ${opt:stage, 'dev'}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:UpdateItem
Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/inventory"
resources:
Resources:
InventoryTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: inventory
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
functions:
postProduct:
handler: src/handlers/postProduct.handler
events:
- httpApi:
path: /product
method: POST
getProducts:
handler: src/handlers/getProducts.handler
events:
- httpApi:
path: /products
method: GET
getProduct:
handler: src/handlers/getProduct.handler
events:
- httpApi:
path: /product/{id}
method: GET
putProduct:
handler: src/handlers/putProduct.handler
events:
- httpApi:
path: /product/{id}
method: PUT
sls deploy --verbose
- Probar endpoint en Postman
Elmininar Producto
- Crear
src/handlers/deleteProduct.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, DeleteCommand, GetCommand } from "@aws-sdk/lib-dynamodb";
const dynamo = DynamoDBDocumentClient.from(new DynamoDBClient({}));
export const handler = async (event) => {
try {
const id = event.pathParameters?.id;
// Verificar si el registro existe antes de eliminarlo
const result = await dynamo.send(new GetCommand({
TableName: "inventory",
Key: { id: id },
}));
if (!result.Item) {
return {
statusCode: 404,
body: JSON.stringify({ message: "Registro no encontrado" }),
};
}
const headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
};
// Eliminar el registro si existe
await dynamo.send(new DeleteCommand({
TableName: "inventory",
Key: { id: id },
}));
return {
statusCode: 200,
headers: headers,
body: JSON.stringify({ message: "Registro eliminado exitosamente" }),
};
} catch (error) {
console.log(error);
return {
statusCode: 500,
body: JSON.stringify({ message: error.message }),
};
}
};
- Modificar
serverless.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
org: jrcoding
service: iac-serverless
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
memorySize: 128
stage: ${opt:stage, 'dev'}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/inventory"
resources:
Resources:
InventoryTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: inventory
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
functions:
postProduct:
handler: src/handlers/postProduct.handler
events:
- httpApi:
path: /product
method: POST
getProducts:
handler: src/handlers/getProducts.handler
events:
- httpApi:
path: /products
method: GET
getProduct:
handler: src/handlers/getProduct.handler
events:
- httpApi:
path: /product/{id}
method: GET
putProduct:
handler: src/handlers/putProduct.handler
events:
- httpApi:
path: /product/{id}
method: PUT
deleteProduct:
handler: src/handlers/deleteProduct.handler
events:
- httpApi:
path: /product/{id}
method: DELETE
sls deploy --verbose
- Probar endpoint en Postman
- Remover stack de aws con
sls remove --verbose