Skip to content

Conversation

@kinyoklion
Copy link
Member

@kinyoklion kinyoklion commented Aug 25, 2022

This PR creates a basic provider with is compatible with open feature.

A large amount of the change is just adding the scaffolding (README, CONTRIBUTING, tsconfig, eslint, package.json, etc.)

If it is problematic for review I could make a scaffold PR first.

This is an example script to demonstrate use.

import { OpenFeature } from '@openfeature/nodejs-sdk';
import { init } from 'launchdarkly-node-server-sdk';
import { LaunchDarklyProvider } from 'open-feature-node';


async function main() {
  const ldClient = init('your_key');
  await ldClient.waitForInitialization();
  OpenFeature.setProvider(new LaunchDarklyProvider(ldClient));
  
  const client = OpenFeature.getClient();
  const detail = await client.getBooleanDetails('app-enabled', false, {targetingKey: 'potato'});
  console.log("The value %s", JSON.stringify(detail));

  const unspecifiedUserValue = await client.getBooleanDetails('app-enabled', false);
  console.log("The value for an unspecified user was %s", JSON.stringify(unspecifiedUserValue));

  const wrongType = await client.getStringDetails('app-enabled', "defaultValue", {targetingKey: 'potato'});
  console.log("The value for the wrong type was", JSON.stringify(wrongType));
}

main();

After the release of the TS re-write of the server SDK I can probably de-node this. But with the current version throwing node in there makes sense.

@kinyoklion kinyoklion marked this pull request as ready for review August 26, 2022 23:22
@@ -0,0 +1,76 @@
# LaunchDarkly OpenFeature provider for the Server-Side SDK for Node.js

This provider allows for using LaunchDarkly with the OpenFeature Node SDK.
Copy link
Member Author

Choose a reason for hiding this comment

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

It would probably be nice to have some boilerplate about what open feature is and why someone should care.

@@ -0,0 +1,43 @@
# Contributing to the LaunchDarkly OpenFeature provider for the Server-Side SDK for Node.js

LaunchDarkly has published an [SDK contributor's guide](https://docs.launchdarkly.com/sdk/concepts/contributors-guide) that provides a detailed explanation of how our SDKs work. See below for additional information on how to contribute to this provider.
Copy link
Member Author

Choose a reason for hiding this comment

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

Should be close enough as far as a contribution guide goes.

*
* @internal
*/
export default function translateContext(evalContext: EvaluationContext): LDUser {
Copy link
Member Author

Choose a reason for hiding this comment

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

In some ways this will get much simpler with the U2C version.

```
npm install @openfeature/nodejs-sdk
npm install launchdarkly-node-server-sdk
npm install @launchdarkly/open-feature-node
Copy link
Member Author

Choose a reason for hiding this comment

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

This is, of course, dirty lies at the moment.

CONTRIBUTING.md Outdated
npm test
```

### Auditing package dependencies

Choose a reason for hiding this comment

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

I'm not 100% sure this stuff is still relevant or the best way to do things. The problem I was trying to solve at the time was that we only had npm audit for finding vulnerabilities, and it would constantly flag dev dependencies of jest/babel/etc. If we can do better now with Dependabot or something else, then we could probably ditch this script.

Copy link
Member Author

Choose a reason for hiding this comment

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

I can remove it. I think dependabot is generally reasonable. (Though it still probably flags more than needed, this project doesn't have a great deal of dependencies.)

],
"license": "Apache-2.0",
"peerDependencies": {
"@openfeature/nodejs-sdk": "^0.3.2",
Copy link
Member Author

Choose a reason for hiding this comment

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

I think doing these as peer dependencies should give us the best compatibility experience. I am open to change though if there is some reason not to do this.

Choose a reason for hiding this comment

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

I think that that is exactly the intended use of peer dependencies. Our library is a thing that's meant to be used with the same instance of the OF SDK that the application is using; there isn't any case in which we would want npm to give us a different one, if we specified a different version.

Copy link

@eli-darkly eli-darkly left a comment

Choose a reason for hiding this comment

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

Fairly minor comments.

case 'FLAG_NOT_FOUND':
return 'FLAG_NOT_FOUND';
// General errors.
case 'USER_NOT_SPECIFIED':

Choose a reason for hiding this comment

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

What's the intention with this line? It looks like it's not doing anything default isn't doing.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is just habit of including all the known values. For me this makes it clear that USER_NOT_SPECIFIED was considered, and does the same as default. Versus it just being forgotten about.

I could use a comment to accomplish the same thing if you prefer.

Choose a reason for hiding this comment

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

A comment would make it a little clearer that this isn't just a mistake. Some other languages don't allow fallthroughs in switch at all because it's so easy to make such mistakes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, true, though I am more accustomed to C# for instance, where empty cases specifically are allowed to fallthrough, but not ones with code, because that is more likely to be a mistake.

Regardless I can add a comment.

],
"license": "Apache-2.0",
"peerDependencies": {
"@openfeature/nodejs-sdk": "^0.3.2",

Choose a reason for hiding this comment

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

I think that that is exactly the intended use of peer dependencies. Our library is a thing that's meant to be used with the same instance of the OF SDK that the application is using; there isn't any case in which we would want npm to give us a different one, if we specified a different version.

defaultValue: boolean,
context: EvaluationContext,
): Promise<ResolutionDetails<boolean>> {
const res = await this.client.variationDetail(flagKey, translateContext(context), defaultValue);

Choose a reason for hiding this comment

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

Am I right that in OpenFeature, every flag evaluation by a provider is "with detail"— i.e. even though the facade also has "value only" methods, those are always implemented by calling a method like this and then throwing away everything but the value?

If so, there is one slight possibly unintended consequence that probably no one will care about, but we might want to document it anyway. The LD SDKs will include reason data in evaluation events if either an experiment was involved... or you called variationDetail. Now, probably no one will care about that because individual evaluation events aren't normally sent; it would only really make a difference if full event tracking is turned on for a flag, and data export is being used. And maybe this has already been discussed, but I just wanted to bring it up for the record if not.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, thank you. I considered this, and I thought I brought it up in the open feature discussion, but likely before we recorded and while your internet was being crazy.

I wonder what the appropriate documentation for this would be. Maybe I could add something to the readme along the lines of evaluations operating as if you were using variationDetail, which will include reasons.

Copy link

@eli-darkly eli-darkly Sep 14, 2022

Choose a reason for hiding this comment

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

It used to be more of an important distinction than it is now, because the SDKs used to send an individual event for every evaluation no matter what. Now it's more of an edge case, and I'm not really sure of the best way to explain it without confusing the vast majority of customers to whom it doesn't apply. I mean, the explanation I wrote above kind of assumes that you're familiar with lower-level SDK implementation details.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok. I will leave this out of the readme for now. Though I probably need to make an internal open feature FAQ or something to contain it.

@kinyoklion kinyoklion merged commit bfc30ba into main Sep 14, 2022
@kinyoklion kinyoklion deleted the rlamb/implement-initial-client branch September 14, 2022 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants