Skip to content

Commit

Permalink
feat(auth): introduce WithinBody option for AuthMode
Browse files Browse the repository at this point in the history
fixes #1035

Implementation is done by:
- adding a new auth mode
- adding data as the return type for createAuth
- expose data from transporter
- serialize transporter data
- map api key back to query parameter if GET
  • Loading branch information
Haroenv committed Aug 6, 2021
1 parent 7c8e967 commit 9281ee9
Show file tree
Hide file tree
Showing 13 changed files with 61 additions and 17 deletions.
2 changes: 2 additions & 0 deletions packages/client-analytics/src/createAnalyticsClient.ts
Expand Up @@ -29,6 +29,8 @@ export const createAnalyticsClient: CreateClient<
...auth.queryParameters(),
...options.queryParameters,
},

data: auth.data(),
});

const appId = options.appId;
Expand Down
14 changes: 13 additions & 1 deletion packages/client-common/src/createAuth.ts
Expand Up @@ -8,11 +8,23 @@ export function createAuth(authMode: AuthModeType, appId: string, apiKey: string

return {
headers(): Readonly<Record<string, string>> {
return authMode === AuthMode.WithinHeaders ? credentials : {};
if (authMode === AuthMode.WithinHeaders) {
return credentials;
} else if (authMode === AuthMode.WithinBody) {
return {
'x-algolia-application-id': appId,
};
}

return {};
},

queryParameters(): Readonly<Record<string, string>> {
return authMode === AuthMode.WithinQueryParameters ? credentials : {};
},

data(): Readonly<Record<string, string>> {
return authMode === AuthMode.WithinBody ? { apiKey } : {};
},
};
}
12 changes: 8 additions & 4 deletions packages/client-common/src/types/Auth.ts
@@ -1,13 +1,17 @@
export type Auth = {
/**
* Returns the headers related to auth. Should be
* merged to the transporter headers.
* Returns the headers related to auth. Should be merged into the headers.
*/
readonly headers: () => Readonly<Record<string, string>>;

/**
* Returns the query parameters related to auth. Should be
* merged to the query parameters headers.
* Returns the query parameters related to auth. Should be merged into the
* query parameters.
*/
readonly queryParameters: () => Readonly<Record<string, string>>;

/**
* Returns the data related to auth. Should be merged into the body.
*/
readonly data: () => Readonly<Record<string, string>>;
};
11 changes: 8 additions & 3 deletions packages/client-common/src/types/AuthModeType.ts
@@ -1,13 +1,18 @@
export const AuthMode: Readonly<Record<string, AuthModeType>> = {
/**
* If auth credentials should be in query parameters.
* Algolia credentials are sent as query parameters
*/
WithinQueryParameters: 0,

/**
* If auth credentials should be in headers.
* Algolia credentials are sent as headers
*/
WithinHeaders: 1,

/**
* Algolia credentials are sent as part of the body
*/
WithinBody: 2,
};

export type AuthModeType = 0 | 1;
export type AuthModeType = 0 | 1 | 2;
4 changes: 1 addition & 3 deletions packages/client-common/src/types/ClientTransporterOptions.ts
Expand Up @@ -2,9 +2,7 @@ import { Headers, HostOptions, QueryParameters, TransporterOptions } from '@algo

export type ClientTransporterOptions = Pick<
TransporterOptions,
Exclude<keyof TransporterOptions, 'headers'> &
Exclude<keyof TransporterOptions, 'queryParameters'> &
Exclude<keyof TransporterOptions, 'hosts'>
Exclude<keyof TransporterOptions, 'hosts' | 'headers' | 'queryParameters' | 'data'>
> & {
/**
* The hosts used by the requester.
Expand Down
Expand Up @@ -29,6 +29,8 @@ export const createPersonalizationClient: CreateClient<
...auth.queryParameters(),
...options.queryParameters,
},

data: auth.data(),
});

return addMethods({ appId: options.appId, transporter }, options.methods);
Expand Down
2 changes: 2 additions & 0 deletions packages/client-search/src/createSearchClient.ts
Expand Up @@ -44,6 +44,8 @@ export const createSearchClient: CreateClient<
...auth.queryParameters(),
...options.queryParameters,
},

data: auth.data(),
});

const base = {
Expand Down
2 changes: 2 additions & 0 deletions packages/recommend/src/createRecommendClient.ts
Expand Up @@ -44,6 +44,8 @@ export const createRecommendClient: CreateClient<
...auth.queryParameters(),
...options.queryParameters,
},

data: auth.data(),
});

const base = {
Expand Down
4 changes: 3 additions & 1 deletion packages/transporter/src/concerns/retryableRequest.ts
Expand Up @@ -31,7 +31,7 @@ export function retryableRequest<TResponse>(
/**
* First we prepare the payload that do not depend from hosts.
*/
const data = serializeData(request, requestOptions);
const data = serializeData(transporter, request, requestOptions);
const headers = serializeHeaders(transporter, requestOptions);
const method = request.method;

Expand All @@ -40,6 +40,8 @@ export function retryableRequest<TResponse>(
request.method !== MethodEnum.Get
? {}
: {
// if AuthMode.WithinData, we forcibly map apiKey back to a query param
'x-algolia-api-key': transporter.data?.apiKey,
...request.data,
...requestOptions.data,
};
Expand Down
8 changes: 5 additions & 3 deletions packages/transporter/src/createTransporter.ts
Expand Up @@ -21,6 +21,7 @@ export function createTransporter(options: TransporterOptions): Transporter {
hosts,
queryParameters,
headers,
data,
} = options;

const transporter: Transporter = {
Expand All @@ -33,14 +34,15 @@ export function createTransporter(options: TransporterOptions): Transporter {
userAgent,
headers,
queryParameters,
data,
hosts: hosts.map(host => createStatelessHost(host)),
read<TResponse>(
request: Request,
requestOptions?: RequestOptions
): Readonly<Promise<TResponse>> {
/**
* First, we compute the user request options. Now, keep in mind,
* that using request options the user is able to modified the intire
* that using request options the user is able to modified the entire
* payload of the request. Such as headers, query parameters, and others.
*/
const mappedRequestOptions = createMappedRequestOptions(
Expand Down Expand Up @@ -73,7 +75,7 @@ export function createTransporter(options: TransporterOptions): Transporter {
: request.cacheable;

/**
* If is not "cacheable", we immediatly trigger the retryable request, no
* If is not "cacheable", we immediately trigger the retryable request, no
* need to check cache implementations.
*/
if (cacheable !== true) {
Expand All @@ -96,7 +98,7 @@ export function createTransporter(options: TransporterOptions): Transporter {

/**
* With the computed key, we first ask the responses cache
* implemention if this request was been resolved before.
* implementation if this request was been resolved before.
*/
return transporter.responsesCache.get(
key,
Expand Down
7 changes: 5 additions & 2 deletions packages/transporter/src/serializer.ts
Expand Up @@ -36,19 +36,22 @@ export function serializeQueryParameters(parameters: Readonly<Record<string, any
}

export function serializeData(
transporter: Transporter,
request: Request,
requestOptions: RequestOptions
): string | undefined {
if (
request.method === MethodEnum.Get ||
(request.data === undefined && requestOptions.data === undefined)
(transporter.data === undefined &&
request.data === undefined &&
requestOptions.data === undefined)
) {
return undefined;
}

const data = Array.isArray(request.data)
? request.data
: { ...request.data, ...requestOptions.data };
: { ...transporter.data, ...request.data, ...requestOptions.data };

return JSON.stringify(data);
}
Expand Down
5 changes: 5 additions & 0 deletions packages/transporter/src/types/Transporter.ts
Expand Up @@ -68,6 +68,11 @@ export type Transporter = {
*/
readonly queryParameters: QueryParameters;

/**
* data sent on each request
*/
readonly data: Record<string, string> | undefined;

/**
* The hosts used by the retry strategy.
*
Expand Down
5 changes: 5 additions & 0 deletions packages/transporter/src/types/TransporterOptions.ts
Expand Up @@ -64,6 +64,11 @@ export type TransporterOptions = {
*/
readonly queryParameters: QueryParameters;

/**
* The data set by the requester (credentials)
*/
readonly data: Record<string, string>;

/**
* The user agent used. Sent on query parameters.
*/
Expand Down

0 comments on commit 9281ee9

Please sign in to comment.