Skip to content

Commit

Permalink
chore(website): resolver docs touchups (#1538)
Browse files Browse the repository at this point in the history
- Resolver interface name was wrong. Left over from its previous name
- Replace the example resolver with a slightly more realistic one
- Remove explanation about invocation patterns, its kind of overwhelming and un-necessary now that the example contains a real implementation
  • Loading branch information
iliapolo authored Oct 3, 2023
1 parent fbbb695 commit e62fb16
Showing 1 changed file with 21 additions and 41 deletions.
62 changes: 21 additions & 41 deletions docs/basics/app.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,31 @@ app.synth();
## Resolvers

Resolvers are a mechanism to inject custom logic into the cdk8s value resolution process.
It allows to transform any value just before being written to the Kubernetes manifest. To define a
custom resolver, first create a class that implements the `IValueResolver` interface:
It allows to transform any value just before being written to the Kubernetes manifest.

For example, lets create a resolver that adds a prefix to every resource in our application.
To define a custom resolver, create a class that implements the `IResolver` interface:

```ts
import { IResolver, ResolutionContext } from 'cdk8s';

export class MyCustomResolver implements IValueResolver {
export class AddNamePrefixResolver implements IResolver {

constructor(private readonly prefix: string) {}

public resolve(context: ResolutionContext): void {

// check if we are resolving the name property
const isNameProperty = context.key.includes('metadata') && context.key.includes('name') && context.key.length === 2;

// check we haven't already added a prefix. this is important because
// resolution is recursive, so we need to avoid infinite recursion.
const isPrefixed = typeof(context.value) === 'string' && context.value.startsWith(this.prefix);

public resolve(context: ResolutionContext): any {
const newValue = ... // run some custom logic
context.replaceValue(newValue);
if (isNameProperty && !isPrefixed) {
// replace the value with a new one
context.replaceValue(`${this.prefix}${context.value}`);
}
}

}
Expand All @@ -62,7 +76,7 @@ When you create a cdk8s `App`, pass the resolver instance to it via the `resolve
```ts
import { App, Chart } from 'cdk8s'

const app = new App({ resolvers: [new MyCustomResolver()] });
const app = new App({ resolvers: [new AddNamePrefixResolver('custom-prefix')] });
new Chart(app, 'Chart');
```

Expand All @@ -71,40 +85,6 @@ original value.

> When passing multiple resolvers, the first one (by natural order of the array) that invokes `replaceValue` is considered, and others are ignored.
The resolver is invoked on every value of cdk8s resource, including complex ones. For example, if you define a Kubernetes `Service` like so:

```ts
new KubeService(this, 'Service', {
spec: {
type: 'LoadBalancer',
}
});
```

Your resolver will be invoked like so:

1. Invoked on the entire spec:
- *obj*: The `KubeService` instance.
- *key*: `['spec']`
- *value*: `{ type: 'LoadBalancer' }`

2. Invoked on the primitive value:
- *obj*: The `KubeService` instance.
- *key*: `['spec', 'type']`
- *value*: `LoadBalancer`

This is why you should always implement a type-check on the value before deciding to replace it or not.
For example:

```ts
public resolve(context: ResolutionContext): any {
if (context.key.includes('type') && typeof(context.value) === 'string') {
const newValue = ... // run some custom logic
context.replaceValue(newValue);
}
}
```

One common use-case for resolvers is to fetch values from deployed infrastructure.
This allows authoring cdk8s applications that natively leverage managed cloud resources.
To that end, two specific resolvers are available that allow you to integrate cdk8s with other CDK frameworks:
Expand Down

0 comments on commit e62fb16

Please sign in to comment.