Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added OrderDatabase(After Processed)-Joaquin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added OrderGet(Processes Orders)-Joaquin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added OrderPost-Joaquin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added OrderQueueAWS-Joaquin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ Note in Every command and URL being called there are fields that need to be repl

Example replacements (make sure to replace the curly brackets as well: don't keep curly brackets)

`{studentName}` - example `ajdewilzin` - this can be your name, independent of your login details
`joaquin` - example `ajdewilzin` - this can be your name, independent of your login details

`{region}` - example `eu-north-1`
`eu-north-1` - example `eu-north-1`

### Steps
1. Create an SNS Topic:

```bash
aws sns create-topic --name {studentName}OrderCreatedTopic
aws sns create-topic --name joaquinOrderCreatedTopic
```
If successful, you will see in your terminal a JSON response that includes `"TopicArn": "...`.

Expand All @@ -22,7 +22,7 @@ Replace `_topicArn` in your Controller code with the generated `TopicArn` value
2. Create an SQS Queue:

```bash
aws sqs create-queue --queue-name {studentName}OrderQueue
aws sqs create-queue --queue-name joaquinOrderQueue
```

If successful, you will see in your terminal a JSON response that includes `"QueueUrl": "some_aws_url`.
Expand All @@ -31,21 +31,21 @@ Replace `_queueUrl` in your Controller code with the generated `QueueUrl` from t


```bash
aws sns subscribe --topic-arn arn:aws:sns:{region}:637423341661:{studentName}OrderCreatedTopic --protocol sqs --notification-endpoint arn:aws:sqs:{region}:637423341661:{studentName}OrderQueue
aws sns subscribe --topic-arn arn:aws:sns:eu-north-1:637423341661:joaquinOrderCreatedTopic --protocol sqs --notification-endpoint arn:aws:sqs:eu-north-1:637423341661:joaquinOrderQueue
```

You don't need to save the generated SubscriptionArn.

3. Create an EventBridge Event Bus:

```bash
aws events create-event-bus --name {StudentName}CustomEventBus --region {region}
aws events create-event-bus --name joaquinCustomEventBus --region eu-north-1
```

4. Create an EventBridge Rule:

```bash
aws events put-rule --name {StudentName}OrderProcessedRule --event-pattern '{\"source\": [\"order.service\"]}' --event-bus-name {StudentName}CustomEventBus
aws events put-rule --name joaquinOrderProcessedRule --event-pattern '{\"source\": [\"order.service\"]}' --event-bus-name joaquinCustomEventBus
```

If your terminal complains about double quotes, you might need to remove the backslash `\` from the command above (and commands later on).
Expand All @@ -54,19 +54,19 @@ If your terminal complains about double quotes, you might need to remove the bac
5. Subscribe the SQS Queue to the SNS Topic

```bash
aws sqs get-queue-attributes --queue-url https://sqs.{region}.amazonaws.com/637423341661/{studentName}OrderQueue --attribute-name QueueArn --region {region}
aws sqs get-queue-attributes --queue-url https://sqs.eu-north-1.amazonaws.com/637423341661/joaquinOrderQueue --attribute-name QueueArn --region eu-north-1
```

```bash
aws sns subscribe --topic-arn arn:aws:sns:{region}:637423341661:{studentName}OrderCreatedTopic --protocol sqs --notification-endpoint arn:aws:sqs:{region}:637423341661:{studentName}OrderQueue --region {region}
aws sns subscribe --topic-arn arn:aws:sns:eu-north-1:637423341661:joaquinOrderCreatedTopic --protocol sqs --notification-endpoint arn:aws:sqs:eu-north-1:637423341661:joaquinOrderQueue --region eu-north-1
```

6. Grant SNS Permissions to SQS


In Bash/Unix terminals you can run this command:
```bash
aws sqs set-queue-attributes --queue-url https://sqs.{region}.amazonaws.com/637423341661/{studentName}OrderQueue --attributes '{"Policy":"{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":\"SQS:SendMessage\",\"Resource\":\"arn:aws:sqs:{region}:637423341661:{studentName}OrderQueue\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"arn:aws:sns:{region}:637423341661:{studentName}OrderCreatedTopic\"}}}]}"}' --region {region}
aws sqs set-queue-attributes --queue-url https://sqs.eu-north-1.amazonaws.com/637423341661/joaquinOrderQueue --attributes '{"Policy":"{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":\"SQS:SendMessage\",\"Resource\":\"arn:aws:sqs:eu-north-1:637423341661:joaquinOrderQueue\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"arn:aws:sns:eu-north-1:637423341661:joaquinOrderCreatedTopic\"}}}]}"}' --region eu-north-1
```


Expand Down
1 change: 1 addition & 0 deletions WorkshopBackend/OrderService/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
appsettings.json
12 changes: 12 additions & 0 deletions WorkshopBackend/OrderService/Context/OrderDbContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using InventoryService.Models;
using Microsoft.EntityFrameworkCore;

namespace OrderService.Context
{
public class OrderDbContext : DbContext
{
public OrderDbContext(DbContextOptions<OrderDbContext> options) : base(options) { }

public DbSet<Order> Orders { get; set; }
}
}
46 changes: 42 additions & 4 deletions WorkshopBackend/OrderService/Controllers/OrderController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using Amazon.EventBridge.Model;
using System.Text.Json;
using InventoryService.Models;
using OrderService.Context;
using Microsoft.EntityFrameworkCore;

[ApiController]
[Route("[controller]")]
Expand All @@ -15,15 +17,17 @@ public class OrderController : ControllerBase
private readonly IAmazonSQS _sqs;
private readonly IAmazonSimpleNotificationService _sns;
private readonly IAmazonEventBridge _eventBridge;
private readonly string _queueUrl = ""; // Format of https://.*
private readonly string _topicArn = ""; // Format of arn:aws.*
private OrderDbContext _db;
private readonly string _queueUrl = "https://sqs.eu-north-1.amazonaws.com/637423341661/joaquinOrderQueue"; // Format of https://.*
private readonly string _topicArn = "arn:aws:sns:eu-north-1:637423341661:joaquinOrderCreatedTopic"; // Format of arn:aws.*

public OrderController()
public OrderController(OrderDbContext db)
{
// Instantiate clients with default configuration
_sqs = new AmazonSQSClient();
_sns = new AmazonSimpleNotificationServiceClient();
_eventBridge = new AmazonEventBridgeClient();
_db = db;
}

[HttpGet]
Expand All @@ -40,12 +44,40 @@ public async Task<IActionResult> GetOrdersAndProcess()
WaitTimeSeconds = 20
};

var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};

var response = await _sqs.ReceiveMessageAsync(request);

foreach (var message in response.Messages)
{
var order = JsonSerializer.Deserialize<Order>(message.Body);
// Define the order variable
Order? order = null;
//The message we want is nested in the queue request.
using(JsonDocument document = JsonDocument.Parse(message.Body))
{
string innerMessage = document.RootElement.GetProperty("Message").GetString();

//Desereialize the inner message
order = JsonSerializer.Deserialize<Order>(innerMessage);
}

// Process order (e.g., update inventory)
if(order != null)
{
var existingOrder = await _db.Orders.FindAsync(order.OrderId);
if (existingOrder != null)
{
//Calculate the total and change processed flag to true
existingOrder.Total = existingOrder.Quantity * existingOrder.Amount;
existingOrder.Processed = true;
// Update the order on RDS
_db.Entry(existingOrder).State = EntityState.Modified;
await _db.SaveChangesAsync();
}
}

// Delete message after processing
await _sqs.DeleteMessageAsync(_queueUrl, message.ReceiptHandle);
Expand All @@ -60,6 +92,12 @@ public async Task<IActionResult> CreateOrder([FromBody] Order order)
* AmazonSimpleNotificationServiceClient
*
*/
// Save order to RDS
order.Processed = false; //Set processed to false, as we are just adding it to the database
await _db.Orders.AddAsync(order);
await _db.SaveChangesAsync();


// Publish to SNS
var message = JsonSerializer.Serialize(order);
var publishRequest = new PublishRequest
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions WorkshopBackend/OrderService/Migrations/20241016114616_first.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;

#nullable disable

namespace OrderService.Migrations
{
/// <inheritdoc />
public partial class first : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Orders",
columns: table => new
{
OrderId = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Product = table.Column<string>(type: "text", nullable: false),
Quantity = table.Column<int>(type: "integer", nullable: false),
Amount = table.Column<int>(type: "integer", nullable: false),
Processed = table.Column<bool>(type: "boolean", nullable: true),
Total = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Orders", x => x.OrderId);
});
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Orders");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using OrderService.Context;

#nullable disable

namespace OrderService.Migrations
{
[DbContext(typeof(OrderDbContext))]
partial class OrderDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.10")
.HasAnnotation("Relational:MaxIdentifierLength", 63);

NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);

modelBuilder.Entity("InventoryService.Models.Order", b =>
{
b.Property<int>("OrderId")
.ValueGeneratedOnAdd()
.HasColumnType("integer");

NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("OrderId"));

b.Property<int>("Amount")
.HasColumnType("integer");

b.Property<bool?>("Processed")
.HasColumnType("boolean");

b.Property<string>("Product")
.IsRequired()
.HasColumnType("text");

b.Property<int>("Quantity")
.HasColumnType("integer");

b.Property<int?>("Total")
.HasColumnType("integer");

b.HasKey("OrderId");

b.ToTable("Orders");
});
#pragma warning restore 612, 618
}
}
}
8 changes: 8 additions & 0 deletions WorkshopBackend/OrderService/OrderService.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
<PackageReference Include="AWSSDK.SimpleNotificationService" Version="3.7.400.34" />
<PackageReference Include="AWSSDK.SQS" Version="3.7.400.34" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Npgsql" Version="8.0.5" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.8" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>

Expand Down
6 changes: 6 additions & 0 deletions WorkshopBackend/OrderService/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;
using OrderService.Context;

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -24,6 +26,10 @@
.AllowAnyHeader()
));

// Add DbContext
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<OrderDbContext>(options => options.UseNpgsql(connectionString));

var app = builder.Build();
app.UseCors("CorsPolicy");

Expand Down
13 changes: 0 additions & 13 deletions WorkshopBackend/OrderService/appsettings.json

This file was deleted.

1 change: 1 addition & 0 deletions WorkshopBackend/WorkshopBackend.sln
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E49EF9F2-F493-4887-B8CF-FCF54A7C151D}"
ProjectSection(SolutionItems) = preProject
..\README.md = ..\README.md
set-queue-attributes.json = set-queue-attributes.json
EndProjectSection
EndProject
Global
Expand Down
4 changes: 4 additions & 0 deletions WorkshopBackend/set-queue-attributes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"*\"},\"Action\":\"SQS:SendMessage\",\"Resource\":\"arn:aws:sqs:eu-north-1:637423341661:joaquinOrderQueue\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"arn:aws:sns:eu-north-1:637423341661:joaquinOrderCreatedTopic\"}}}]}"
}