Skip to content

Commit

Permalink
Merge branch 'main' into poc/new-checkout-interface
Browse files Browse the repository at this point in the history
  • Loading branch information
sharonsheah authored Nov 14, 2023
2 parents f3e0662 + a618da5 commit bffadc2
Show file tree
Hide file tree
Showing 20 changed files with 1,247 additions and 818 deletions.
50 changes: 40 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Table of contents
- [Link packages to each other](#link-packages-to-each-other)
- [Generate OpenAPI clients](#generate-openapi-clients)
- [Building](#building)
- [API key and Publishable key](#API-key-and-Publishable-key)
- [Linting](#linting)
- [ESLint Tooling](#eslint-tooling)
- [Exclude Lists](#exclude-lists)
Expand Down Expand Up @@ -121,22 +122,51 @@ If you run out of memory, set NODE_OPTIONS to limit Node's use of memory (this a
export NODE_OPTIONS=--max-old-space-size=14366
```

### API keys and Client App Id
### API key and Publishable key

You can mark the API key and/or publishable key as required fields or remove them from your SDK configuration:
```ts
// We use checkout sdk as an example.
export interface CheckoutOverrides {
// The below marks CheckoutModuleConfiguration to have publishableKey field required and apiKey field omitted.
apiKey: "omit";
publishableKey: "required";
}
export interface CheckoutModuleConfiguration extends ModuleConfiguration<CheckoutOverrides> {}
```

API keys and Client App ID are used to authenticate and track usage respectively per partner/project/environment.
`Api key` and `Publishable key` are meant to be added to request headers.

Once created from hub, they can be optionally passed into base config as followed:
For `Api key`, it's done automatically by generated client. No action required.
```
import { config } from '@imtbl/sdk';
For `Publishable key`, we can do the following:
```ts
export class Checkout {
constructor(
config: CheckoutModuleConfiguration,
) {
// imported from '@imtbl/config', addPublishableKeyToAxiosHeader
// adds x-immutable-publishable-key header to all axios requests
addPublishableKeyToAxiosHeader(config.baseConfig.publishableKey);
// You can also remove these headers.
axios.defaults.headers.common['x-immutable-publishable-key'] = undefined;
const baseConfig = new config.ImmutableConfiguration({
environment: config.Environment.PRODUCTION,
clientAppId: '....',
apiKey: '....',
});
// Or apply them to particular request methods
axios.defaults.headers.delete['x-immutable-publishable-key'] = undefined;
// Or you can save the config in the instance of this class and reference them in individual methods.
}
}
```
> **Warning**
> Please make sure your sdk still works properly after the step above. Because extra headers may make your request invalid in the infrastructure you use. e.g. cloudfront.
#### Publishable key usage data
Publishable key usage will be available in segment under event source `Onboarding - API - ${Dev|Sandbox|Prod}`. You can set up event destination (data lake/looker) together with appropriate filters to surface endpoint usages called by your sdk.
### Linting
#### ESLint Tooling
Expand Down
63 changes: 39 additions & 24 deletions packages/config/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,50 @@ export class ImmutableConfiguration {

readonly apiKey?: string;

readonly clientAppId?: string;
readonly publishableKey?: string;

constructor(options: { environment: Environment; rateLimitingKey?: string; apiKey?: string; clientAppId?: string }) {
constructor(options: {
environment: Environment;
}) {
this.environment = options.environment;

if (options.rateLimitingKey) {
this.rateLimitingKey = options.rateLimitingKey;
axios.defaults.headers.common['x-api-key'] = this.rateLimitingKey;
}

if (options.apiKey) {
if (!options.apiKey.startsWith('sk_imapik-')) {
throw new Error('Invalid API key');
}
this.apiKey = options.apiKey;
axios.defaults.headers.common['x-immutable-api-key'] = this.apiKey;
}

if (options.clientAppId) {
if (!options.clientAppId.startsWith('cai_imapik-')) {
throw new Error('Invalid Client App Id');
}
this.clientAppId = options.clientAppId;
axios.defaults.headers.common['x-immutable-client-app-id'] = this.clientAppId;
}
}
}

const API_KEY_PREFIX = 'sk_imapik-';
const PUBLISHABLE_KEY_PREFIX = 'pk_imapik-';
const PUBLISHABLE_KEY_LENGTH = 30;

export const addApiKeyToAxiosHeader = (apiKey: string) => {
if (!apiKey.startsWith(API_KEY_PREFIX)) {
throw new Error('Invalid API key. Create your api key in Immutable developer hub. https://hub.immutable.com');
}
axios.defaults.headers.common['x-immutable-api-key'] = apiKey;
};

export const addPublishableKeyToAxiosHeader = (publishableKey: string) => {
if (!publishableKey.startsWith(PUBLISHABLE_KEY_PREFIX) || publishableKey.length !== PUBLISHABLE_KEY_LENGTH) {
throw new Error(
'Invalid Publishable key. Create your Publishable key in Immutable developer hub.'
+ ' https://hub.immutable.com',
);
}
axios.defaults.headers.common['x-immutable-publishable-key'] = publishableKey;
};

export const addRateLimitingKeyToAxiosHeader = (rateLimitingKey: string) => {
axios.defaults.headers.common['x-api-key'] = rateLimitingKey;
};

type ImmutableConfigurationWithRequireableFields<T> = ImmutableConfiguration &
(T extends { apiKey: 'required'; } ? Required<{ apiKey: string; }> : {}) &
(T extends { publishableKey: 'required'; } ? Required<{ publishableKey: string; }> : {});

type ImmutableConfigurationWithOmitableFields<T> =
(T extends { apiKey: 'omit'; } ?
Omit<ImmutableConfigurationWithRequireableFields<T>, 'apiKey'> :
ImmutableConfigurationWithRequireableFields<T>);

export interface ModuleConfiguration<T> {
baseConfig: ImmutableConfiguration;
baseConfig: ImmutableConfigurationWithOmitableFields<T>;
overrides?: T;
}
Loading

0 comments on commit bffadc2

Please sign in to comment.