Skip to content

Commit c05666e

Browse files
Alberto RizziAlberto Rizzi
authored andcommitted
add assets and presentation, add code
1 parent 8513408 commit c05666e

16 files changed

+549
-195
lines changed

README.md

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,33 @@
1-
# Ecommerce Orchestration Microservice
1+
# e-Commerce Saga Orchestration Implementation
2+
Il presente progetto ha lo scopo di implementare un prototipo di flusso di un e-Commerce attraverso alcune tecnologie di Amazon AWS previste nel pattern della Saga Orchestration.
23

3-
Lorenzo Marcolli (mat. 08302A) <br />
4-
Alberto Rizzi (mart. 08303A)
4+
## Autori
5+
- Lorenzo Marcolli (mat. 08302A)
6+
- Alberto Rizzi (mart. 08303A)
57

68
## Diagram flow
7-
[Draw.io](https://drive.google.com/file/d/14FBuOeF2dJOKJoST7JyEinbuRB0JBPWc/view?usp=sharing)
9+
<div align="center">
10+
<img src="assets/schema_high.jpg" width="95%" style="border-radius: 5px; padding: 10px; background-color: white"></img>
11+
</div>
812

9-
## Technologies
13+
[ 🔗 Draw.io](https://drive.google.com/file/d/14FBuOeF2dJOKJoST7JyEinbuRB0JBPWc/view?usp=sharing)
14+
15+
## Relazione
16+
[ 🔗 Relazione](/assets/relazione.pdf)
17+
18+
## Presentazione
1019

11-
### Client
12-
- Next.js
13-
- Typescript
14-
- Tailwind.css
1520

21+
## Tecnologie usate
1622
### Cloud
1723
- AWS Lambda
1824
- AWS SQS
1925
- AWS Step Function
20-
- AWS API Gateway
26+
- AWS API Gateway
27+
- AWS DynamoDB
28+
29+
### Client
30+
- Next.js
31+
- Typescript
32+
- Tailwind.css
33+

assets/relazione.pdf

1.14 MB
Binary file not shown.

assets/schema_high.jpg

789 KB
Loading

lambda/CheckInventory.js

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,43 @@
1-
import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb";
1+
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';
2+
import { DynamoDBClient, GetItemCommand, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
23

34
const dynamoDBClient = new DynamoDBClient();
45

6+
57
export const handler = async (event, context, callback) => {
68
let response;
79
const basket = event.basket;
810

11+
const orderId = event.orderId;
12+
13+
console.log(orderId)
14+
15+
try {
16+
const lambda = new LambdaClient({ region: 'eu-central-1' });
17+
18+
const params = {
19+
FunctionName: 'SendWebsocketMessage',
20+
InvocationType: 'RequestResponse',
21+
Payload: JSON.stringify({ orderId: orderId, messageObj: { status: "pending", message: "Controllo disponibilità prodotti" } }) // Input payload for the target Lambda function
22+
};
23+
24+
const command = new InvokeCommand(params);
25+
const data = await lambda.send(command);
26+
27+
console.log(data)
28+
29+
if (data.StatusCode === 200) {
30+
console.log(data.Payload)
31+
}
32+
else {
33+
throw new Error("Errore invio WS message")
34+
}
35+
}
36+
catch (error) {
37+
console.error('Error:', error);
38+
throw error;
39+
}
40+
941
try {
1042
const hasInvalidQuantity = await Promise.all(
1143
basket.map(async (product) => {
@@ -17,26 +49,19 @@ export const handler = async (event, context, callback) => {
1749
'productId': { N: product.id.toString() }
1850
}
1951
};
20-
21-
console.log(params)
2252

23-
const command = new GetItemCommand(params);
2453

25-
console.log(command);
2654

55+
const command = new GetItemCommand(params);
2756
const data = await dynamoDBClient.send(command);
2857

29-
console.log(data);
30-
3158
// Check if the item exists
3259
if (!data.Item) {
3360
throw new Error(`Product with ID ${product.id} not found in the inventory.`);
3461
}
3562

3663
const retrievedItem = data.Item;
3764

38-
console.log(retrievedItem);
39-
4065
const availability = parseInt(retrievedItem.quantity.N);
4166

4267
if (product.quantity > availability) {
@@ -46,22 +71,64 @@ export const handler = async (event, context, callback) => {
4671
return false;
4772
})
4873
);
49-
74+
5075
console.log(hasInvalidQuantity)
5176

5277
if (hasInvalidQuantity.some(Boolean)) {
53-
throw new Error("error_quantity");
54-
} else {
78+
try {
79+
const updateItemParams = {
80+
TableName: 'Order',
81+
Key: {
82+
orderId: { S: orderId }
83+
},
84+
UpdateExpression: 'SET orderStatus = :statusString',
85+
ExpressionAttributeValues: {
86+
':statusString': { S: 'cancelled' }
87+
}
88+
};
89+
90+
const command = new UpdateItemCommand(updateItemParams);
91+
const data = await dynamoDBClient.send(command);
92+
}
93+
catch (error) {
94+
console.error('Error:', error);
95+
throw error;
96+
}
97+
throw new Error("Quantità non disponibile");
98+
}
99+
else {
100+
basket.map(async (product) => {
101+
console.log(typeof product.id);
102+
103+
const updateItemParams = {
104+
TableName: 'Inventory',
105+
Key: {
106+
productId: { N: product.id.toString() }
107+
},
108+
UpdateExpression: 'SET quantity = quantity - :decreaseAmount',
109+
ExpressionAttributeValues: {
110+
':decreaseAmount': { N: product.quantity.toString() }, // Specify the amount to decrease
111+
':quantityitem': { N: '0' }
112+
},
113+
ConditionExpression: 'quantity > :quantityitem',
114+
};
115+
116+
const command = new UpdateItemCommand(updateItemParams);
117+
const data = await dynamoDBClient.send(command);
118+
})
119+
55120
response = {
56121
statusCode: 200,
57122
body: event,
58123
};
59124
}
60125

61126
return response;
62-
} catch (error) {
127+
}
128+
catch (error) {
63129
const myErrorObj = {
64130
message: error.message,
131+
orderId: orderId,
65132
errorType: "InternalServerError",
66133
httpStatus: 500,
67134
requestId: context.awsRequestId,

lambda/CompleteOrder.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';
2+
import { DynamoDBClient, GetItemCommand, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
3+
4+
const dynamoDBClient = new DynamoDBClient();
5+
6+
export const handler = async (event, context, callback) => {
7+
const orderId = event.body.orderId
8+
9+
try {
10+
const updateItemParams = {
11+
TableName: 'Order',
12+
Key: {
13+
orderId: { S: orderId }
14+
},
15+
UpdateExpression: 'SET orderStatus = :statusString',
16+
ExpressionAttributeValues: {
17+
':statusString': { S: 'completed' }
18+
}
19+
};
20+
21+
const command = new UpdateItemCommand(updateItemParams);
22+
const data = await dynamoDBClient.send(command);
23+
}
24+
catch (error) {
25+
console.error('Error:', error);
26+
27+
const myErrorObj = {
28+
message: error.message,
29+
orderId: orderId,
30+
errorType: "InternalServerError",
31+
httpStatus: 500,
32+
requestId: context.awsRequestId,
33+
};
34+
callback(JSON.stringify(myErrorObj));
35+
}
36+
37+
38+
39+
try {
40+
const lambda = new LambdaClient({ region: 'eu-central-1' });
41+
42+
const params = {
43+
FunctionName: 'SendWebsocketMessage',
44+
InvocationType: 'RequestResponse',
45+
Payload: JSON.stringify({ orderId: orderId, messageObj: { status: "completed", message: "Ordine avvenuto con successo" } }) // Input payload for the target Lambda function
46+
};
47+
48+
const command = new InvokeCommand(params);
49+
const data = await lambda.send(command);
50+
51+
if (data.StatusCode === 200) {
52+
console.log(data.Payload)
53+
54+
const response = {
55+
statusCode: 200,
56+
body: JSON.stringify('Ordine avvenuto con successo!'),
57+
};
58+
return response;
59+
}
60+
else {
61+
throw new Error("Errore invio WS message")
62+
}
63+
}
64+
catch (error) {
65+
const myErrorObj = {
66+
message: error.message,
67+
orderId: orderId,
68+
errorType: "InternalServerError",
69+
httpStatus: 500,
70+
requestId: context.awsRequestId,
71+
};
72+
callback(JSON.stringify(myErrorObj));
73+
}
74+
};

lambda/GetAllProducts.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { DynamoDBClient, ScanCommand } from "@aws-sdk/client-dynamodb";
2+
3+
const client = new DynamoDBClient()
4+
5+
6+
function getItemValue(attribute) {
7+
const dataType = Object.keys(attribute)[0];
8+
const value = attribute[dataType];
9+
10+
switch (dataType) {
11+
case "N":
12+
return parseFloat(value);
13+
case "S":
14+
return value;
15+
case "BOOL":
16+
return value === "true";
17+
// Handle other data types as needed
18+
default:
19+
return null;
20+
}
21+
}
22+
23+
24+
export const handler = async (event) => {
25+
try {
26+
27+
const scanCommand = new ScanCommand({ TableName: 'Inventory', ConsistentRead: true });
28+
const scanResult = await client.send(scanCommand);
29+
30+
if (!scanResult.Items) {
31+
return {
32+
statusCode: 404,
33+
body: JSON.stringify('no_items_found'),
34+
headers: {
35+
"Access-Control-Allow-Headers": "Content-Type",
36+
"Access-Control-Allow-Origin": "*",
37+
"Access-Control-Allow-Methods": "GET"
38+
},
39+
};
40+
}
41+
42+
// create array of product
43+
const items = scanResult.Items.map((item) => {
44+
const formattedItem = {};
45+
Object.keys(item).forEach((key) => {
46+
formattedItem[key] = getItemValue(item[key]);
47+
});
48+
return formattedItem;
49+
});
50+
51+
console.log(items)
52+
53+
return {
54+
statusCode: 200,
55+
error: false,
56+
body: JSON.stringify(items),
57+
headers: {
58+
"Access-Control-Allow-Headers": "Content-Type",
59+
"Access-Control-Allow-Origin": "*",
60+
"Access-Control-Allow-Methods": "GET"
61+
},
62+
};
63+
}
64+
catch (error) {
65+
console.log(error);
66+
return {
67+
statusCode: 500,
68+
error: true,
69+
body: JSON.stringify('no_items_found'),
70+
headers: {
71+
"Access-Control-Allow-Headers": "Content-Type",
72+
"Access-Control-Allow-Origin": "*",
73+
"Access-Control-Allow-Methods": "GET"
74+
},
75+
};
76+
}
77+
};

lambda/GetProductCost.js

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)