-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
187 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
--- | ||
title: ContextData - Sharing Request Data | ||
sidebar_label: ContextData | ||
--- | ||
|
||
It is often useful to store data throughout the life of a single request. This | ||
data could be used on multiple policies, handlers, or for logging. However, | ||
because the Zuplo runtime is asynchronous, you cannot simply create global | ||
variables and reference them in other modules if the value is unique accross | ||
requests. Additionally, using a traditional data structure like a `Map` is also | ||
not recommended as it can build up memory over time. | ||
|
||
## ContextData | ||
|
||
The `ContextData` utility allows safely storing data that is tied to a specific | ||
request. Additionally, this utility ensures that data stored is properly garbage | ||
collected (removed from memory) when the request is complete. | ||
|
||
**`ContextData.set`** | ||
|
||
```ts | ||
ContextData.set(context, "my-data", { prop1: "hello world" }); | ||
``` | ||
|
||
**`ContextData.get`** | ||
|
||
```ts | ||
const data = ContextData.get(context, "my-data"); | ||
``` | ||
|
||
**`set` (instance function)** | ||
|
||
```ts | ||
const myData = new ContextData("my-data"); | ||
myData.set(context, { prop1: "hello world" }); | ||
``` | ||
|
||
**`get` (instance function)** | ||
|
||
```ts | ||
const myData = new ContextData("my-data"); | ||
const data = myData.get(context); | ||
``` | ||
|
||
### Typing | ||
|
||
The methods of `CustomData` support generics in order to support typing. | ||
|
||
```ts | ||
const myData = new ContextData<{ key: string }>("my-data"); | ||
ContextData.get<{ key: string }>(context, "my-data"); | ||
ContextData.set<{ key: string }>(context, "my-data", { key: "hello" }); | ||
``` | ||
|
||
## How NOT to Share Data | ||
|
||
Below are a few examples of how **NOT** to share data in your API. | ||
|
||
::: danger | ||
|
||
Do NOT write code like this in your API. It will not work reliably. These are | ||
examples of what NOT to do. See the next section for best practices. | ||
|
||
::: | ||
|
||
The first example uses a simple shared global variable called `currentRequestId` | ||
to store the current requestId. On the surface this looks straightforward. | ||
However, because the gateway is being shared among many requests who are all | ||
running at the same time, the value of `currentRequestId` is completely | ||
unpredictable when your API is under load. | ||
|
||
```ts title="/modules/policies.ts" | ||
let currentRequestId: string | undefined; | ||
|
||
export function myFirstPolicy(request: ZuploRequest, context: ZuploContext) { | ||
currentRequestId = context.requestId; | ||
context.log.info(`The current requestId is: ${currentRequestId}`); | ||
} | ||
|
||
export function mySecondPolicy(request: ZuploRequest, context: ZuploContext) { | ||
currentRequestId = context.requestId; | ||
context.log.info(`The current requestId is: ${currentRequestId}`); | ||
} | ||
``` | ||
|
||
## Using ContextData | ||
|
||
Below you will find examples of how to use `ContextData` to safely share data | ||
throughout the lifecycle of a request. | ||
|
||
### Using static methods | ||
|
||
```ts | ||
import { CustomData, ZuploContext, ZuploRequest } from "@zuplo/runtime"; | ||
|
||
export function myFirstPolicy(request: ZuploRequest, context: ZuploContext) { | ||
CustomData.set(context, "currentRequestId", context.requestId; | ||
|
||
const currentRequestId = ContextData.get(context, "currentRequestId"); | ||
context.log.info(`The current requestId is: ${currentRequestId}`); | ||
} | ||
``` | ||
### Using Shared Variable | ||
Reusable class shared across modules The shared module allows other modules to | ||
access the same storage without passing the string name or type around. | ||
```ts | ||
export const myData = new ContextData<{ prop1: string }>("my-data"); | ||
``` | ||
Then use the class in another module. | ||
```ts | ||
import { myData } from "./my-module"; | ||
const data = myData.get(context); | ||
myData.set(context, data); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
--- | ||
title: Route Custom Data | ||
--- | ||
|
||
Each route in your OpenAPI file allows for specifying custom properties on your | ||
route that can be referenced in code. Because the OpenAPI document allows | ||
extensibility by adding `x-` properties, you can add custom data as needed to | ||
your operations and then read that data in code. | ||
|
||
## Custom Data in OpenAPI File | ||
|
||
The example below shows how to add custom data and operation with a property | ||
`x-custom`. | ||
|
||
```json title="/config/routes.oas.json" | ||
{ | ||
"/my-route": { | ||
"get": { | ||
// highlight-start | ||
"x-custom": { | ||
"hello": "world" | ||
}, | ||
// highlight-end | ||
"operationId": "c18da63b-bd4d-433f-a634-1da9913958c0", | ||
"x-zuplo-route": { | ||
"handler": { | ||
"module": "$import(@zuplo/runtime)", | ||
"export": "urlForwardHandler", | ||
"options": { | ||
"baseUrl": "https://echo.zuplo.io", | ||
"forwardSearch": true | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Custom Data in Code | ||
|
||
Custom data can be accessed through the `context.route.raw()` function. This | ||
gives you full access to the underlying data of the OpenAPI operation. By | ||
default this function returns `unknown`, but you can pass it a custom object or | ||
for the full OpenAPI operation, use `OpenAPIV3_1.OperationObject` exported from | ||
`openapi-types` | ||
|
||
```ts | ||
import { ZuploContext, ZuploRequest } from "@zuplo/runtime"; | ||
|
||
export async function echo(request: ZuploRequest, context: ZuploContext) { | ||
const data = context.route.raw<{ "x-custom": { hello: string } }>(); | ||
context.log.info(`My custom data: ${data["x-custom"].hello}`); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters