Skip to content

Commit

Permalink
feat(sdk): aws.QueueRef (#6001)
Browse files Browse the repository at this point in the history
Introduce `aws.QueueRef` as a way to add an external queue reference to an application:

```js
bring aws;
bring cloud;

let myQueue = new aws.QueueRef("arn:aws:sqs:...."); // <-- ARN of an existing SQS queue

new cloud.Function(inflight () => {
  myQueue.push("new message");
});
```

This works both when running in the simulator and when running on AWS.

The Wing Console also includes some metadata about the queue such as the queue URL and the AWS Console URL:

![image](https://github.com/winglang/wing/assets/598796/fec3a609-6f7e-42c9-93ec-1768c197ca07)

### Issues

* Related to #5879 (only implements queue and we need additional resources).
* Related to #5170


### Misc

Added an option `link: bool` to `ui.FIeld` to indicate that the value returned is a link. We should make this a clickable link in the Wing Console.

## Checklist

- [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [x] Description explains motivation and solution
- [x] Tests added (always)
- [x] Docs updated (only required for features)
- [x] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
eladb authored Mar 19, 2024
1 parent 691fd52 commit c396ff4
Show file tree
Hide file tree
Showing 19 changed files with 1,746 additions and 23 deletions.
2 changes: 1 addition & 1 deletion apps/jsii-docgen/src/docgen/view/api-reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class ApiReference {
this.constructs = new Constructs(
transpile,
classes,
this.searchableInterfaces(interfaces)
this.searchableInterfaces([...assembly.allInterfaces])
);
this.classes = new Classes(transpile, classes);
this.structs = new Structs(transpile, interfaces);
Expand Down
149 changes: 149 additions & 0 deletions docs/docs/04-standard-library/aws/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,155 @@ The IAM certificate identifier value.
---


### QueueRef <a name="QueueRef" id="@winglang/sdk.aws.QueueRef"></a>

A reference to an external SQS queue.

#### Initializers <a name="Initializers" id="@winglang/sdk.aws.QueueRef.Initializer"></a>

```wing
bring aws;
new aws.QueueRef(queueArn: str);
```

| **Name** | **Type** | **Description** |
| --- | --- | --- |
| <code><a href="#@winglang/sdk.aws.QueueRef.Initializer.parameter.queueArn">queueArn</a></code> | <code>str</code> | *No description.* |

---

##### `queueArn`<sup>Required</sup> <a name="queueArn" id="@winglang/sdk.aws.QueueRef.Initializer.parameter.queueArn"></a>

- *Type:* str

---

#### Methods <a name="Methods" id="Methods"></a>

##### Inflight Methods

| **Name** | **Description** |
| --- | --- |
| <code><a href="#@winglang/sdk.cloud.IQueueClient.approxSize">approxSize</a></code> | Retrieve the approximate number of messages in the queue. |
| <code><a href="#@winglang/sdk.cloud.IQueueClient.pop">pop</a></code> | Pop a message from the queue. |
| <code><a href="#@winglang/sdk.cloud.IQueueClient.purge">purge</a></code> | Purge all of the messages in the queue. |
| <code><a href="#@winglang/sdk.cloud.IQueueClient.push">push</a></code> | Push one or more messages to the queue. |

---

##### `approxSize` <a name="approxSize" id="@winglang/sdk.cloud.IQueueClient.approxSize"></a>

```wing
inflight approxSize(): num
```

Retrieve the approximate number of messages in the queue.

##### `pop` <a name="pop" id="@winglang/sdk.cloud.IQueueClient.pop"></a>

```wing
inflight pop(): str
```

Pop a message from the queue.

##### `purge` <a name="purge" id="@winglang/sdk.cloud.IQueueClient.purge"></a>

```wing
inflight purge(): void
```

Purge all of the messages in the queue.

##### `push` <a name="push" id="@winglang/sdk.cloud.IQueueClient.push"></a>

```wing
inflight push(...messages: Array<str>): void
```

Push one or more messages to the queue.

###### `messages`<sup>Required</sup> <a name="messages" id="@winglang/sdk.cloud.IQueueClient.push.parameter.messages"></a>

- *Type:* str

Payload to send to the queue.

Each message must be non-empty.

---

#### Static Functions <a name="Static Functions" id="Static Functions"></a>

| **Name** | **Description** |
| --- | --- |
| <code><a href="#@winglang/sdk.aws.QueueRef.onLiftType">onLiftType</a></code> | A hook called by the Wing compiler once for each inflight host that needs to use this type inflight. |

---

##### `onLiftType` <a name="onLiftType" id="@winglang/sdk.aws.QueueRef.onLiftType"></a>

```wing
bring aws;
aws.QueueRef.onLiftType(host: IInflightHost, ops: MutArray<str>);
```

A hook called by the Wing compiler once for each inflight host that needs to use this type inflight.

The list of requested inflight methods
needed by the inflight host are given by `ops`.

This method is commonly used for adding permissions, environment variables, or
other capabilities to the inflight host.

###### `host`<sup>Required</sup> <a name="host" id="@winglang/sdk.aws.QueueRef.onLiftType.parameter.host"></a>

- *Type:* <a href="#@winglang/sdk.std.IInflightHost">IInflightHost</a>

---

###### `ops`<sup>Required</sup> <a name="ops" id="@winglang/sdk.aws.QueueRef.onLiftType.parameter.ops"></a>

- *Type:* MutArray&lt;str&gt;

---

#### Properties <a name="Properties" id="Properties"></a>

| **Name** | **Type** | **Description** |
| --- | --- | --- |
| <code><a href="#@winglang/sdk.aws.QueueRef.property.node">node</a></code> | <code>constructs.Node</code> | The tree node. |
| <code><a href="#@winglang/sdk.aws.QueueRef.property.queueArn">queueArn</a></code> | <code>str</code> | The ARN of this queue. |

---

##### `node`<sup>Required</sup> <a name="node" id="@winglang/sdk.aws.QueueRef.property.node"></a>

```wing
node: Node;
```

- *Type:* constructs.Node

The tree node.

---

##### `queueArn`<sup>Required</sup> <a name="queueArn" id="@winglang/sdk.aws.QueueRef.property.queueArn"></a>

```wing
queueArn: str;
```

- *Type:* str

The ARN of this queue.

---


## Classes <a name="Classes" id="Classes"></a>

### Api <a name="Api" id="@winglang/sdk.aws.Api"></a>
Expand Down
26 changes: 25 additions & 1 deletion docs/docs/04-standard-library/cloud/queue.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ new cloud.Function(inflight () => {

### Using Queue inflight api

Pusing messages, popping them, and purge
Pushing messages, popping them, and purging.

```ts playground
bring cloud;
Expand All @@ -62,6 +62,30 @@ new cloud.Function(inflight () => {
});
```

### Referencing an external queue

If you would like to reference an existing queue from within your application you can use the
`QueueRef` classes in the target-specific namespaces.

> This is currently only supported for `aws`.
The following example defines a reference to an Amazon SQS queue with a specific ARN and sends a
message to the queue from the function:

```js
bring aws;

let outbox = new aws.QueueRef("arn:aws:sqs:us-east-1:111111111111:Outbox");

new cloud.Function(inflight () => {
outbox.push("send an email");
});
```

This works both when running in the simulator (requires AWS credentials on the developer's machine)
and when deployed to AWS. When this is deployed to AWS, the AWS Lambda IAM policy will include the
needed permissions.

## Target-specific details

### Simulator (`sim`)
Expand Down
14 changes: 14 additions & 0 deletions docs/docs/04-standard-library/ui/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -519,10 +519,24 @@ let FieldProps = ui.FieldProps{ ... };

| **Name** | **Type** | **Description** |
| --- | --- | --- |
| <code><a href="#@winglang/sdk.ui.FieldProps.property.link">link</a></code> | <code>bool</code> | Indicates that this field is a link. |
| <code><a href="#@winglang/sdk.ui.FieldProps.property.refreshRate">refreshRate</a></code> | <code><a href="#@winglang/sdk.std.Duration">duration</a></code> | How often the field should be refreshed. |

---

##### `link`<sup>Optional</sup> <a name="link" id="@winglang/sdk.ui.FieldProps.property.link"></a>

```wing
link: bool;
```

- *Type:* bool
- *Default:* false

Indicates that this field is a link.

---

##### `refreshRate`<sup>Optional</sup> <a name="refreshRate" id="@winglang/sdk.ui.FieldProps.property.refreshRate"></a>

```wing
Expand Down
54 changes: 54 additions & 0 deletions examples/tests/sdk_tests/queue/queue-ref.test.w
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
bring cloud;
bring aws;
bring util;

// a really cool way to test a "ref" resource: basically, we define a cloud.Queue
// and then we define a `QueueRef` that references it's ARN. nice, ha?

let c = new cloud.Counter();
let q = new cloud.Queue();

q.setConsumer(inflight () => {
c.inc();
});

// this will only work if we are testing on tf-aws
if let arn = aws.Queue.from(q)?.queueArn {
let qref = new aws.QueueRef(arn);

new cloud.Function(inflight () => {
qref.push("hello");
qref.pop();
});

test "can push to an external queue (QueueRef)" {
qref.push("m1");
qref.push("m2");
qref.push("m3");
util.waitUntil(() => {
return c.peek() == 3;
});
}
}

if util.env("WING_TARGET") == "sim" {
bring expect;

let dummyArn = "arn:aws:sqs:us-east-1:111111111111:Queue-11111111";
let qr = new aws.QueueRef(dummyArn);

test "queueArn returns the arn" {
expect.equal(dummyArn, qr.queueArn);
}

test "push() sends a request to aws, fails because we are using a dummy queue" {
let var err = false;
try {
qr.push("foo");
} catch e {
err = true;
}

assert(err);
}
}
26 changes: 25 additions & 1 deletion libs/wingsdk/src/cloud/queue.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ new cloud.Function(inflight () => {

### Using Queue inflight api

Pusing messages, popping them, and purge
Pushing messages, popping them, and purging.

```ts playground
bring cloud;
Expand All @@ -62,6 +62,30 @@ new cloud.Function(inflight () => {
});
```

### Referencing an external queue

If you would like to reference an existing queue from within your application you can use the
`QueueRef` classes in the target-specific namespaces.

> This is currently only supported for `aws`.
The following example defines a reference to an Amazon SQS queue with a specific ARN and sends a
message to the queue from the function:

```js
bring aws;

let outbox = new aws.QueueRef("arn:aws:sqs:us-east-1:111111111111:Outbox");

new cloud.Function(inflight () => {
outbox.push("send an email");
});
```

This works both when running in the simulator (requires AWS credentials on the developer's machine)
and when deployed to AWS. When this is deployed to AWS, the AWS Lambda IAM policy will include the
needed permissions.

## Target-specific details

### Simulator (`sim`)
Expand Down
1 change: 1 addition & 0 deletions libs/wingsdk/src/core/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export interface UIField {
/** The construct path to a cloud.Function */
readonly handler: string;
readonly refreshRate: number | undefined;
readonly link?: boolean;
}

/** @internal */
Expand Down
6 changes: 6 additions & 0 deletions libs/wingsdk/src/shared-aws/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ export function calculateQueuePermissions(
): PolicyStatement[] {
const policies: PolicyStatement[] = [];

// this is always needed in order to resolve URL from ARN/name
policies.push({
actions: ["sqs:GetQueueUrl"],
resources: [arn],
});

if (ops.includes(cloud.QueueInflightMethods.PUSH)) {
policies.push({
actions: ["sqs:SendMessage"],
Expand Down
Loading

0 comments on commit c396ff4

Please sign in to comment.