Skip to content

Commit

Permalink
wip: experimenting with c4 diagrams
Browse files Browse the repository at this point in the history
  • Loading branch information
raksiv committed Jan 13, 2025
1 parent bafa7a6 commit 5cb12dc
Show file tree
Hide file tree
Showing 12 changed files with 1,688 additions and 0 deletions.
151 changes: 151 additions & 0 deletions docs/guides/c4/c4-api.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
description: 'C4 Api'
tags:
- C4
published_at: 2024-07-25
---

# Nitric 'API' Architecture

## 1. System Context (Level 1)

- A **Developer** uses Nitric to create and manage APIs within their application.
- App code interacts with the **API resource** through defined endpoints.
- Developers define API specifications and implement backend logic to handle requests.
- **Operations** use default or overridden Terraform modules to provision the necessary AWS API Gateway resources.
- **AWS API Gateway v2** serves as the HTTP API management service.
- **AWS Lambda** functions are deployed to handle API requests.
- **AWS IAM** (implicitly assumed) provides roles and policies for secure interaction between API Gateway and Lambda functions.
- **AWS ACM** manages SSL/TLS certificates for custom domain names.

```mermaid
flowchart TD
Developer["Developer"]
Operations["Operations"]
App["nitric up"]
APIGateway["AWS API Gateway v2<br>(HTTP API)"]
Lambda["AWS Lambda Functions"]
IAM["AWS IAM"]
ACM["AWS ACM<br>(Certificates)"]
Developer -->|Define API| App
Operations -->|Terraform| App
App -->|Create API Gateway| APIGateway
App -->|Deploy Lambda Functions| Lambda
App -->|Configure Permissions| IAM
APIGateway -->|Invoke| Lambda
ACM -->|Provide Certificates| APIGateway
IAM -->|Manage Access| APIGateway
App -->ACM
classDef default line-height:1;
classDef edgeLabel line-height:2;
```

## 2. Container (Level 2)

Each **API** is managed through AWS API Gateway v2 and interacts with backend Lambda functions to process HTTP requests.

```mermaid
flowchart TD
Nitric["Nitric Application"]
Nitric -->B(API 1)
Nitric -->C(API 2)
Nitric -->D(...)
B(API 1) -->E(HTTP GET)
B(API 1) -->F(HTTP POST)
B(API 1) -->G(...)
classDef default line-height:1;
classDef edgeLabel line-height:2;
```

## 3. Component (Level 3)

### API Module

- **aws_apigatewayv2_api.api_gateway**
- Creates an AWS API Gateway v2 HTTP API.
- Configures the API name, protocol type, API specification (`body`), and tags for identification and management.
- **aws_apigatewayv2_stage.stage**
- Creates a stage for the API Gateway.
- Sets the stage name to `$default` and enables automatic deployment of changes.
- **aws_lambda_permission.apigw_lambda**
- Grants API Gateway permission to invoke the specified Lambda functions.
- Iterates over `var.target_lambda_functions` to set permissions for each target function.
- **data.aws_acm_certificate.cert**
- Looks up existing ACM certificates for the specified domains.
- Iterates over `var.domains` to retrieve certificate details for each domain.
- **aws_apigatewayv2_domain_name.domain**

- Creates custom domain names for the API Gateway using the retrieved ACM certificates.
- Configures domain name settings, including the certificate ARN, endpoint type, and security policy.

## 4. Code (Level 4)

**Developers** write application code that imports the 'api' resource from the SDK, configures the api, and implements HTTP routes, implement middleware, etc.

```typescript
import { api } from '@nitric/sdk'

const publicApi = api('public')

api('public').get('/customers', (ctx) => {
// construct response for the GET: /customers request...
const responseBody = {}
ctx.res.json(responseBody)
})

const authMiddleware = async (ctx, next) => {
// Perform auth validation.
return await next(ctx)
}

const privateApi = api('private', { middleware: authMiddleware })
```

**Operations** will use the provided Terraform module to create and manage the AWS API Gateway as defined.

```hcl
resource "aws_apigatewayv2_api" "api_gateway" {
name = var.name
protocol_type = "HTTP"
body = var.spec
tags = {
"x-nitric-${var.stack_id}-name" = var.name,
"x-nitric-${var.stack_id}-type" = "api",
}
}
resource "aws_apigatewayv2_stage" "stage" {
api_id = aws_apigatewayv2_api.api_gateway.id
name = "$default"
auto_deploy = true
}
# deploy lambda permissions for execution
resource "aws_lambda_permission" "apigw_lambda" {
for_each = var.target_lambda_functions
action = "lambda:InvokeFunction"
function_name = each.value
principal = "apigateway.amazonaws.com"
source_arn = "${aws_apigatewayv2_api.api_gateway.execution_arn}/*/*/*"
}
# look up existing certificate for domains
data "aws_acm_certificate" "cert" {
for_each = var.domains
domain = each.value
}
# deploy custom domain names
resource "aws_apigatewayv2_domain_name" "domain" {
for_each = var.domains
domain_name = each.value
domain_name_configuration {
certificate_arn = data.aws_acm_certificate.cert[each.key].arn
endpoint_type = "REGIONAL"
security_policy = "TLS_1_2"
}
}
```
92 changes: 92 additions & 0 deletions docs/guides/c4/c4-big-picture.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
description: 'C4 Nitric High-Level Architecture'
tags:
- C4
published_at: 2024-07-25
---

# Nitric High-Level Architecture

Nitric allows your team to work together to build an application:

- **Developer**: Writes application code with built-in support for APIs, file storage (bucket), secrets, key‑value store, and RDS, leveraging the Nitric SDK.
- **Operations**: Customize, extend or use Nitric's generated IaC (Terraform or Pulumi) to provision and manage the resources that the developer needs for their application.
- **SRE**: Configure environment/region/policy specific details, they also are heavily involved in overseeing that the Terraform modules themselves adhere to governance standards.

The roles above may overlap depending on your organization structure, for example, it is not abnormal Developers to assume all roles, or for Operations and SRE responsibilities to be handled by the same team.

```mermaid
flowchart TD
Developer[Developer]
Operations[Operations]
SRE[Site Reliablility Engineer]
App[Nitric App - 'nitric up']
Repo[Code Repository]
API[API Gateway]
Bucket[Bucket - AWS S3]
Secrets[Secrets - AWS Secrets Manager\n]
KVStore[Key-Value Store - AWS DynamoDB]
RDS[Relational Database - AWS RDS/Aurora]
Other[Other resources]
SRE -->|Deployment Config| Repo
Developer -->|Code| Repo
Operations -->|Extend/Customize Terraform| Repo
Repo-->App
App -->|Exposes REST/HTTP Routes| API
App -->|Stores/Retrieves Files| Bucket
App -->|Manages Sensitive Data| Secrets
App -->|Reads/Writes Data| KVStore
App -->|Executes SQL Queries| RDS
App -->|1..n|Other
classDef default line-height:1;
classDef edgeLabel line-height:2;
```

Nitric applications can have any number of APIs, Secrets, Buckets etc. Providers can also be extended to further support new resources, many which will work across all cloud providers and some that are cloud specific.

## Example: Handling HTTP requests.

Interaction with services that have been exposed as HTTP routes within an API gateway, Scheduled tasks, Event subscriptions, WebSocket handlers and more.

```mermaid
flowchart TD
%% Actors
Browser[Client Browser]
%% Nitric Application Containers
API[HTTP API - API Gateway]
Service[GET Route]
Service2[POST Route]
Service3[...]
%% Backend Services / Resources
Bucket[AWS S3 Bucket]
Secrets[AWS Secrets Manager]
KVStore[AWS DynamoDB - Key-Value Store]
RDS[AWS RDS/Aurora]
%% Interactions
Browser -->|Sends HTTP Request| API
API -->|Triggers Service| Service
API -->|Triggers Service| Service2
API -->|Triggers Service| Service3
Service -->|Manage/Uploads/Downloads files| Bucket
Service -->|Retrieves credentials/config data| Secrets
Service -->|Reads/Writes key data| KVStore
Service -->|Queries/Updates relational data| RDS
classDef default line-height:1;
classDef edgeLabel line-height:2;
```

- The **Client Browser** sends an HTTP request to the **API Gateway**.
- The **API Gateway** acts as a proxy, forwarding the request to the appropriate **Services**.
- The **Services** process the request by coordinating with different backend services, this is done through :
- They interact with one or more **AWS S3 Bucket** to manage files.
- They retrieve credentials or configuration from **AWS Secrets Manager**.
- They use **AWS DynamoDB** for fast key-value operations.
- They query or update structured data in **AWS RDS/Aurora**.
135 changes: 135 additions & 0 deletions docs/guides/c4/c4-buckets.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
---
description: 'C4 Buckets'
tags:
- C4
published_at: 2024-07-25
---

# Nitric 'Bucket' Architecture

## 1. System Context (Level 1)

- A **Developer** uses Nitric to manage S3 buckets within their application.
- App code imports the **Bucket resource** from the Nitric SDK.
- Developers configure buckets and implement application logic to securely access and manipulate bucket data.
- Developers can also implement hanlders for on events like on read, write or delete.
- **Operations** use default or overridden Terraform modules to provision the necessary AWS S3 resources.
- **AWS S3** serves as the storage backend.
- **AWS Lambda** functions are used to process events triggered by S3.
- **AWS IAM** provides roles and policies for secure access to S3 buckets and Lambda functions.
- **Random ID** resource is used to generate unique bucket names.

```mermaid
flowchart TD
Developer["Developer"]
Operations["Operations"]
App["nitric up"]
S3Bucket["AWS S3 Bucket"]
Lambda["AWS Lambda Functions"]
IAM["AWS IAM"]
Developer -->|Code| App
Operations -->|Terraform| App
App -->|Create S3 Bucket| S3Bucket
App -->|Configure Notifications| S3Bucket
App -->|Allow Lambda Invocation| Lambda
S3Bucket -->|Store/Retrieve Data| App
Lambda -->|Process Events| App
App -->|Provide Access| IAM
IAM -->S3Bucket
classDef default line-height:1;
classDef edgeLabel line-height:2;
```

## 2. Container (Level 2)

Each **Bucket** is managed through AWS S3 and accessed by the application through securely configured mechanisms provided by Nitric.

```mermaid
flowchart TD
Nitric["Nitric Application"]
Nitric -->B(Bucket 1)
Nitric -->C(Bucket 2)
Nitric -->D(...)
B(BUCKET 1) -->E(ON Read)
B(BUCKET 1) -->F(ON Write)
B(BUCKET 1) -->G(ON Delete)
```

## 3. Component (Level 3)

### Bucket Module

- **random_id.bucket_id**
- Generates a random ID for the S3 bucket to ensure unique naming.
- **aws_s3_bucket.bucket**
- Creates an AWS S3 bucket with a unique name by appending the generated random ID.
- Configures tags for identification and management.
- **aws_lambda_permission.allow_bucket**
- Grants AWS S3 permission to invoke the specified Lambda functions.
- Iterates over `var.notification_targets` to set permissions for each target.
- **aws_s3_bucket_notification.bucket_notification**
- Configures S3 bucket notifications to trigger Lambda functions based on specified events.
- Uses dynamic blocks to handle multiple Lambda function notifications.

## 4. Code (Level 4)

**Developers** write application code that imports the 'bucket' resource from the SDK, configures the bucket, and implements the application logic to read, write and delete files.

```typescript
import { bucket } from '@nitric/sdk'

const profiles = bucket('profiles').allow('read')

const image = await profiles.file('users/bruce-wayne/profile.png').read()
```

**Operations** will use the provided Terraform module to create and manage the AWS S3 Buckets as defined.

```hcl
# Generate a random id for the bucket
resource "random_id" "bucket_id" {
byte_length = 8
keepers = {
# Generate a new id each time we switch to a new AMI id
bucket_name = var.bucket_name
}
}
# AWS S3 bucket
resource "aws_s3_bucket" "bucket" {
bucket = "${var.bucket_name}-${random_id.bucket_id.hex}"
tags = {
"x-nitric-${var.stack_id}-name" = var.bucket_name
"x-nitric-${var.stack_id}-type" = "bucket"
}
}
# Deploy bucket lambda invocation permissions
resource "aws_lambda_permission" "allow_bucket" {
for_each = var.notification_targets
action = "lambda:InvokeFunction"
function_name = each.value.arn
principal = "s3.amazonaws.com"
source_arn = aws_s3_bucket.bucket.arn
}
# Deploy lambda notifications
resource "aws_s3_bucket_notification" "bucket_notification" {
bucket = aws_s3_bucket.bucket.id
// make dynamic blocks for lambda function
dynamic "lambda_function" {
for_each = var.notification_targets
content {
lambda_function_arn = lambda_function.value.arn
events = lambda_function.value.events
filter_prefix = lambda_function.value.prefix
}
}
}
```
Loading

0 comments on commit 5cb12dc

Please sign in to comment.