Skip to content

Commit

Permalink
Merge pull request #88 from thomashacker/feature/handle-scheme-in-host
Browse files Browse the repository at this point in the history
Handle existing scheme in host
  • Loading branch information
tsmith023 authored Sep 25, 2023
2 parents 4513685 + e01bd61 commit 5c60264
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 9 deletions.
7 changes: 4 additions & 3 deletions src/connection/gqlClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ export interface GraphQLClient {
}

export const gqlClient = (config: ConnectionParams): GraphQLClient => {
const scheme = config.scheme;
const host = config.host;
const defaultHeaders = config.headers;
const version = '/v1/graphql';
const baseUri = `${config.host}${version}`;

return {
// for backward compatibility with replaced graphql-client lib,
// results are wrapped into { data: data }
query: (query: TQuery, variables?: Variables, headers?: HeadersInit) => {
return new Client(`${scheme}://${host}/v1/graphql`, {
return new Client(baseUri, {
headers: {
...defaultHeaders,
...headers,
Expand Down
3 changes: 2 additions & 1 deletion src/connection/httpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export interface HttpClient {
}

export const httpClient = (config: ConnectionParams): HttpClient => {
const baseUri = `${config.scheme}://${config.host}/v1`;
const version = '/v1';
const baseUri = `${config.host}${version}`;
const url = makeUrl(baseUri);

return {
Expand Down
24 changes: 24 additions & 0 deletions src/connection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ export default class Connection {
private apiKey?: string;
private authEnabled: boolean;
private gql: GraphQLClient;
public readonly host: string;
public readonly http: HttpClient;
public oidcAuth?: OidcAuthenticator;

constructor(params: ConnectionParams) {
params = this.sanitizeParams(params);
this.host = params.host;
this.http = httpClient(params);
this.gql = gqlClient(params);
this.authEnabled = this.parseAuthParams(params);
Expand All @@ -36,10 +38,32 @@ export default class Connection {
}

private sanitizeParams(params: ConnectionParams) {
// Remove trailing slashes from the host
while (params.host.endsWith('/')) {
params.host = params.host.slice(0, -1);
}

const protocolPattern = /^(https?|ftp|file)(?::\/\/)/;
const extractedSchemeMatch = params.host.match(protocolPattern);

// Check for the existence of scheme in params
if (params.scheme) {
// If the host contains a scheme different than provided scheme, replace it and throw a warning
if (extractedSchemeMatch && extractedSchemeMatch[1] !== `${params.scheme}`) {
throw new Error(
`The host contains a different protocol than specified in the scheme (scheme: ${params.scheme} != host: ${extractedSchemeMatch[1]})`
);
} else if (!extractedSchemeMatch) {
// If no scheme in the host, simply prefix with the provided scheme
params.host = `${params.scheme}://${params.host}`;
}
// If there's no scheme in params, ensure the host starts with a recognized protocol
} else if (!extractedSchemeMatch) {
throw new Error(
'The host must start with a recognized protocol (e.g., http or https) if no scheme is provided.'
);
}

return params;
}

Expand Down
69 changes: 69 additions & 0 deletions src/connection/unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,75 @@ describe('mock server auth tests', () => {
await conn.login().then((key) => expect(key).toEqual(apiKey));
});

it('should construct the correct url when host contains scheme', () => {
const apiKey = 'abcd123';

const conn = new Connection({
scheme: 'http',
host: 'http://localhost:' + server.port,
apiKey: new ApiKey(apiKey),
});
const expectedPath = 'http://localhost:' + server.port;

expect(conn.host).toEqual(expectedPath);
});

it('should construct the correct url when scheme specified and host does not contain scheme', () => {
const apiKey = 'abcd123';

const conn = new Connection({
scheme: 'http',
host: 'localhost:' + server.port,
apiKey: new ApiKey(apiKey),
});
const expectedPath = 'http://localhost:' + server.port;

expect(conn.host).toEqual(expectedPath);
});

it('should construct the correct url when no scheme is specified but host contains scheme', () => {
const apiKey = 'abcd123';

const conn = new Connection({
host: 'http://localhost:' + server.port,
apiKey: new ApiKey(apiKey),
});
const expectedPath = 'http://localhost:' + server.port;

expect(conn.host).toEqual(expectedPath);
});

it('should throw error when host contains different scheme than specified', () => {
const apiKey = 'abcd123';

const createConnection = () => {
return new Connection({
scheme: 'https',
host: 'http://localhost:' + server.port,
apiKey: new ApiKey(apiKey),
});
};

expect(createConnection).toThrow(
'The host contains a different protocol than specified in the scheme (scheme: https != host: http)'
);
});

it('should throw error when scheme not specified and included in host', () => {
const apiKey = 'abcd123';

const createConnection = () => {
return new Connection({
host: 'localhost:' + server.port,
apiKey: new ApiKey(apiKey),
});
};

expect(createConnection).toThrow(
'The host must start with a recognized protocol (e.g., http or https) if no scheme is provided.'
);
});

it('shuts down the server', () => {
return server.close();
});
Expand Down
5 changes: 1 addition & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface ConnectionParams {
authClientSecret?: AuthClientCredentials | AuthAccessTokenCredentials | AuthUserPasswordCredentials;
apiKey?: ApiKey;
host: string;
scheme: string;
scheme?: string;
headers?: HeadersInit;
}

Expand All @@ -44,9 +44,6 @@ const app = {
// check if the URL is set
if (!params.host) throw new Error('Missing `host` parameter');

// check if the scheme is set
if (!params.scheme) throw new Error('Missing `scheme` parameter');

// check if headers are set
if (!params.headers) params.headers = {};

Expand Down
24 changes: 23 additions & 1 deletion test/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function testServer() {
lastRequest = ctx.request;
return next();
});
app.use(getLocalOidcConfig, getRemoteOidcConfig, issueToken);
app.use(getLocalOidcConfig, getRemoteOidcConfig, issueToken, mockGetEndpoint, mockGraphQLResponse);
const server = app.listen(port);

serverCache = {
Expand All @@ -46,6 +46,28 @@ export function testServer() {
return serverCache;
}

const mockGetEndpoint = (ctx: any, next: any) => {
if (ctx.path !== '/v1/testEndpoint') {
return next();
}

ctx.response.status = 200;
ctx.response.body = { message: 'test endpoint' };
};

const mockGraphQLResponse = (ctx: any, next: any) => {
if (ctx.path !== '/v1/graphql') {
return next();
}

ctx.response.status = 200;
ctx.response.body = {
data: {
someField: 'someValue',
},
};
};

const getLocalOidcConfig = (ctx: any, next: any) => {
if (ctx.path !== '/v1/.well-known/openid-configuration') {
return next();
Expand Down

0 comments on commit 5c60264

Please sign in to comment.