Skip to content
Merged
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
161 changes: 74 additions & 87 deletions docs/docs/clients/server-side.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import CodeBlock from '@theme/CodeBlock';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

import { JavaVersion, RustVersion, DotnetVersion, ElixirVersion } from '@site/src/components/SdkVersions.js';
import {
JavaVersion,
RustVersion,
DotnetVersion,
ElixirVersion,
NodejsVersion,
} from '@site/src/components/SdkVersions.js';

# Server Side SDKs

Expand Down Expand Up @@ -40,11 +46,10 @@ Server Side SDKs can run in 2 different modes: Local Evaluation and Remote Evalu
- Source Code: https://github.com/Flagsmith/flagsmith-dotnet-client

</TabItem>
<TabItem value="nodejs" label="NodeJS">
<TabItem value="nodejs" label="Node.js">

- Version Compatibility: **Node 14+**
- Source Code:
- https://github.com/Flagsmith/flagsmith-nodejs-client
- Version Compatibility: **Node 18+**
- Source Code: https://github.com/Flagsmith/flagsmith-nodejs-client

</TabItem>
<TabItem value="ruby" label="Ruby">
Expand Down Expand Up @@ -140,11 +145,10 @@ pip install flagsmith
</CodeBlock>

</TabItem>
<TabItem value="nodejs" label="NodeJS">
<TabItem value="nodejs" label="Node.js">

```bash
# Via NPM
npm i flagsmith-nodejs --save
npm install flagsmith-nodejs
```

</TabItem>
Expand Down Expand Up @@ -245,10 +249,10 @@ _flagsmithClient = new("FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY");
```

</TabItem>
<TabItem value="nodejs" label="NodeJS">
<TabItem value="nodejs" label="Node.js">

```javascript
const Flagsmith = require('flagsmith-nodejs');
import { Flagsmith } from 'flagsmith-nodejs';

const flagsmith = new Flagsmith({
environmentKey: 'FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY',
Expand Down Expand Up @@ -367,12 +371,12 @@ var buttonData = await flags.GetFeatureValue("secret_button");
```

</TabItem>
<TabItem value="nodejs" label="NodeJS">
<TabItem value="nodejs" label="Node.js">

```javascript
const flags = await flagsmith.getEnvironmentFlags();
var showButton = flags.isFeatureEnabled('secret_button');
var buttonData = flags.getFeatureValue('secret_button');
const showButton = flags.isFeatureEnabled('secret_button');
const buttonData = flags.getFeatureValue('secret_button');
Comment on lines +378 to +379
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're changing this here, we should also do it here for consistency.

```

</TabItem>
Expand Down Expand Up @@ -479,7 +483,7 @@ var showButton = await flags.IsFeatureEnabled("secret_button");
```

</TabItem>
<TabItem value="nodejs" label="NodeJS">
<TabItem value="nodejs" label="Node.js">

```javascript
const identifier = '[email protected]';
Expand Down Expand Up @@ -662,7 +666,7 @@ static Flag defaultFlagHandler(string featureName)
```

</TabItem>
<TabItem value="nodejs" label="NodeJS">
<TabItem value="nodejs" label="Node.js">

```javascript
const flagsmith = new Flagsmith({
Expand Down Expand Up @@ -853,18 +857,32 @@ public class MyCustomOfflineHandler: BaseOfflineHandler
```

</TabItem>
<TabItem value="nodejs" label="NodeJS">
<TabItem value="nodejs" label="Node.js">

```javascript
// Using the built-in local file handler
const localFileHandler = new LocalFileHandler('path_to_environment_file/environment_file.json');
const flagsmith = new Flagsmith({ offlineMode: true, offlineHandler: localFileHandler });
Use <a
href={`https://www.tsdocs.dev/docs/flagsmith-nodejs/${NodejsVersion()}/classes/LocalFileHandler.html`}>LocalFileHandler</a>
to read an environment file generated by the [Flagsmith CLI](/clients/CLI):

// Defining a custom offline handler
class CustomOfflineHandler extends BaseOfflineHandler {
getEnvironment(): EnvironmentModel {
return someMethodToGetTheEnvironment();
}
```typescript
import { Flagsmith, LocalFileHandler } from 'flagsmith-nodejs';

const flagsmith = new Flagsmith({
offlineMode: true,
offlineHandler: new LocalFileHandler('./flagsmith.json'),
});
```

To create your own offline handler, implement the `BaseOfflineHandler` interface. It must return an
{/* prettier-ignore */}<a target="_blank" href={`https://www.tsdocs.dev/docs/flagsmith-nodejs/${NodejsVersion()}/classes/EnvironmentModel.html`}>EnvironmentModel</a>
object:

```typescript
import type { BaseOfflineHandler, EnvironmentModel } from 'flagsmith-nodejs';

class CustomOfflineHandler implements BaseOfflineHandler {
getEnvironment(): EnvironmentModel {
// ...
}
}
```

Expand Down Expand Up @@ -1015,10 +1033,9 @@ flagsmith.close();
```

</TabItem>
<TabItem value="nodejs" label = "NodeJS">
<TabItem value="nodejs" label = "Node.js">

```javascript
// available from v2.2.1
flagsmith.close();
```

Expand Down Expand Up @@ -1413,10 +1430,11 @@ $flagsmith = Flagsmith::Client.new(
```

</TabItem>
<TabItem value="nodejs" label="NodeJS">
<TabItem value="nodejs" label="Node.js">

```typescript
import { bool, number } from 'prop-types';
import { Flagsmith } from 'flagsmith-nodejs';
import type { EnvironmentModel } from 'flagsmith-nodejs';

const flagsmith = new Flagsmith({
/*
Expand All @@ -1440,9 +1458,8 @@ const flagsmith = new Flagsmith({
See https://docs.flagsmith.com/clients/server-side#caching
*/
cache: {
has: (key: string) => bool,
get: (key: string) => string | number | null,
set: (k: string, v: Flags) => (cache[k] = v),
get: (key: string) => Promise.resolve(),
set: (k: string, v: Flags) => Promise.resolve(),
},

/*
Expand Down Expand Up @@ -1780,7 +1797,8 @@ client_configuration = Flagsmith.Client.new(

## Caching

The following SDKs have code and functionality related to caching flags.
Some SDKs support caching flags retrieved from the Flagsmith API, or calculated from your environment definition if
using Local Evaluation.

<Tabs groupId="language" queryString>
<TabItem value="java" label="Java">
Expand Down Expand Up @@ -1874,68 +1892,37 @@ final FlagsAndTraits flags = cache.getIfPresent(projectLevelCacheKey);
```

</TabItem>
<TabItem value="nodejs" label="NodeJS">
<TabItem value="nodejs" label="Node.js">

You can initialise the SDK with something like this:
The `cache` option in the `Flagsmith` constructor accepts a cache implementation. This cache must implement the
{/* prettier-ignore */}<a href={`https://www.tsdocs.dev/docs/flagsmith-nodejs/${NodejsVersion()}/interfaces/FlagsmithCache.html`}>FlagsmithCache</a>
interface.

```javascript
flagsmith.init({
cache: {
has:(key)=> return Promise.resolve(!!cache[key]) , // true | false
get: (k)=> cache[k] // return flags or flags for user
set: (k,v)=> cache[k] = v // gets called if has returns false with response from API for Identify or getFlags
}
})
```
For example, this cache implementation uses Redis as a backing store:

The core concept is that if `has` returns false, the SDK will make the required API calls under the hood. The keys are
either `flags` or `flags_traits-${identity}`.

An example of a concrete implemention is below.

```javascript
const flagsmith = require('flagsmith-nodejs');
const redis = require('redis');
```typescript
import { Flagsmith } from 'flagsmith-nodejs';
import type { BaseOfflineHandler, EnvironmentModel, Flags, FlagsmithCache } from 'flagsmith-nodejs';
import * as redis from 'redis';

const redisClient = redis.createClient({
host: 'localhost',
port: 6379,
url: 'localhost:6379',
});

flagsmith.init({
environmentID: 'FLAGSMITH_SERVER_SIDE_ENVIRONMENT_KEY',
cache: {
has: (key) =>
new Promise((resolve, reject) => {
redisClient.exists(key, (err, reply) => {
console.log('check ' + key + ' from cache', err, reply);
resolve(reply === 1);
});
}),
get: (key) =>
new Promise((resolve) => {
redisClient.get(key, (err, cacheValue) => {
console.log('get ' + key + ' from cache');
resolve(cacheValue && JSON.parse(cacheValue));
});
}),
set: (key, value) =>
new Promise((resolve) => {
// Expire the key after 60 seconds
redisClient.set(key, JSON.stringify(value), 'EX', 60, (err, reply) => {
console.log('set ' + key + ' to cache', err);
resolve();
});
}),
const redisFlagsmithCache = {
async get(key: string): Promise<Flags | undefined> {
const cachedValue = await redisClient.get(key);
return Promise.resolve(cachedValue && JSON.parse(cachedValue));
},
});
async set(key: string, value: Flags): Promise<void> {
await redisClient.set(key, JSON.stringify(value), { EX: 60 });
return Promise.resolve();
},
} satisfies FlagsmithCache;

router.get('/', function (req, res, next) {
flagsmith.getValue('background_colour').then((value) => {
res.render('index', {
title: value,
});
});
const flagsmith = new Flagsmith({
environmentKey: 'ser...',
cache: redisFlagsmithCache,
});
```

Expand Down Expand Up @@ -2037,7 +2024,7 @@ https://github.com/Flagsmith/flagsmith-java-client
https://github.com/Flagsmith/flagsmith-dotnet-client

</TabItem>
<TabItem value="nodejs" label="NodeJS">
<TabItem value="nodejs" label="Node.js">

https://github.com/Flagsmith/flagsmith-nodejs-client

Expand Down
4 changes: 3 additions & 1 deletion docs/plugins/flagsmith-versions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ export default async function fetchFlagsmithVersions(context, options) {
return {
name: 'flagsmith-versions',
async loadContent() {
const [js, java, android, swiftpm, cocoapods, dotnet, rust, elixir] = await Promise.all(
const [js, nodejs, java, android, swiftpm, cocoapods, dotnet, rust, elixir] = await Promise.all(
[
fetchNpmVersions('flagsmith'),
fetchNpmVersions('flagsmith-nodejs'),
fetchJavaVersions(),
fetchAndroidVersions(),
fetchSwiftPMVersions(),
Expand All @@ -83,6 +84,7 @@ export default async function fetchFlagsmithVersions(context, options) {
);
return {
js,
nodejs,
java,
android,
swiftpm,
Expand Down
1 change: 1 addition & 0 deletions docs/src/components/SdkVersions.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ export const DotnetVersion = ({ spec = '~5' }) => Version({ sdk: 'dotnet', spec
export const ElixirVersion = ({ spec = '~2' }) => Version({ sdk: 'elixir', spec });
export const RustVersion = ({ spec = '~2' }) => Version({ sdk: 'rust', spec });
export const JsVersion = ({ spec = '~7' }) => Version({ sdk: 'js', spec });
export const NodejsVersion = ({ spec } = { spec: '~5' }) => Version({ sdk: 'nodejs', spec });