Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FAI-9741: Remove v1 support from FarosClient #258

Merged
merged 2 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 1 addition & 8 deletions src/adapter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,14 +305,7 @@ export class QueryAdapter {
constructor(
private readonly faros: FarosClient,
private readonly v1Schema: gql.GraphQLSchema
) {
if (faros.graphVersion !== 'v2') {
throw new VError(
'query adapter only works with v2 clients. found version: %s',
faros.graphVersion
);
}
}
) {}

/** Converts a V2 field value into a V1 field value */
private v1Value(v2Value: any, type: LeafValueType): any {
Expand Down
74 changes: 4 additions & 70 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {get as traverse, isEmpty, unset} from 'lodash';
import pino, {Logger} from 'pino';
import {Dictionary} from 'ts-essentials';
import {promisify} from 'util';
import VError from 'verror';
import * as zlib from 'zlib';

import {makeAxiosInstanceWithRetry} from './axios';
Expand All @@ -17,7 +16,6 @@ import {
FarosClientConfig,
GraphVersion,
Location,
Model,
NamedQuery,
Phantom,
SecretName,
Expand All @@ -36,7 +34,6 @@ export const GRAPH_VERSION_HEADER = 'x-faros-graph-version';
/** Faros API client **/
export class FarosClient {
private readonly api: AxiosInstance;
readonly graphVersion: GraphVersion;
readonly phantoms: Phantom;

constructor(
Expand All @@ -46,24 +43,21 @@ export class FarosClient {
) {
const url = Utils.urlWithoutTrailingSlashes(cfg.url);

const useGraphQLV2 = cfg.useGraphQLV2 ?? true;

this.api = makeAxiosInstanceWithRetry(
{
...axiosConfig,
baseURL: url,
headers: {
...axiosConfig?.headers,
authorization: cfg.apiKey,
...(useGraphQLV2 && {[GRAPH_VERSION_HEADER]: 'v2'}),
[GRAPH_VERSION_HEADER]: GraphVersion.V2,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Retain this explicit header for safety. Clio with v2 default is not necessarily rolled out everywhere yet.

},
maxBodyLength: Infinity, // rely on server to enforce request body size
maxContentLength: Infinity, // accept any response size
},
logger
);

this.graphVersion = useGraphQLV2 ? GraphVersion.V2 : GraphVersion.V1;
this.phantoms = cfg.phantoms || Phantom.IncludeNestedOnly;
}

Expand Down Expand Up @@ -137,47 +131,6 @@ export class FarosClient {
}
}

async models(graph: string): Promise<ReadonlyArray<Model>> {
if (this.graphVersion !== GraphVersion.V1) {
throw new VError(
`listing models is not supported for ${this.graphVersion} graphs`
);
}

try {
const {data} = await this.api.get(`/graphs/${graph}/models`);
return data.models;
} catch (err: any) {
throw wrapApiError(err, `unable to list models: ${graph}`);
}
}

async addModels(
graph: string,
models: string,
schema?: string
): Promise<void> {
if (this.graphVersion !== GraphVersion.V1) {
throw new VError(
`Adding models is not supported for ${this.graphVersion} graphs`
);
}
try {
await this.api.post(`/graphs/${graph}/models`, models, {
headers: {'content-type': 'application/graphql'},
params: {
...(schema && {schema}),
},
});
} catch (err: any) {
throw wrapApiError(err, `failed to add models to graph: ${graph}`);
}
}

async addCanonicalModels(graph: string): Promise<void> {
return await this.addModels(graph, '', 'canonical');
}

async namedQuery(name: string): Promise<NamedQuery | undefined> {
try {
const {data} = await this.api.get(`/queries/${name}`);
Expand All @@ -190,29 +143,11 @@ export class FarosClient {
}
}

async entrySchema(graph: string): Promise<any> {
if (this.graphVersion !== GraphVersion.V1) {
throw new VError(
`entry schema is not supported for ${this.graphVersion} graphs`
);
}

try {
const {data} = await this.api.get(
`/graphs/${graph}/revisions/entries/schema`
);
return data.schema;
} catch (err: any) {
throw wrapApiError(err, `unable to load entry schema of graph: ${graph}`);
}
}

queryParameters(): Dictionary<any> {
const result: Dictionary<any> = {};
if (this.graphVersion === GraphVersion.V2) {
result.phantoms = this.phantoms;
}
return result;
return {
phantoms: this.phantoms,
};
}

private async doGql(
Expand All @@ -223,7 +158,6 @@ export class FarosClient {
try {
let req: any = variables ? {query, variables} : {query};
let doCompression =
this.graphVersion === GraphVersion.V2 &&
Buffer.byteLength(query, 'utf8') > 10 * 1024; // 10KB
if (doCompression) {
try {
Expand Down
2 changes: 0 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
export interface FarosClientConfig {
readonly url: string;
readonly apiKey: string;
readonly useGraphQLV2?: boolean;
readonly phantoms?: Phantom;
}

export enum GraphVersion {
V1 = 'v1',
V2 = 'v2',
}

Expand Down
50 changes: 5 additions & 45 deletions test/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import nock from 'nock';

import {FarosClient, FarosClientConfig, Schema} from '../src';
import {GRAPH_VERSION_HEADER} from '../src/client';
import {Phantom, WebhookEvent, WebhookEventStatus} from '../src/types';

const apiUrl = 'https://test.faros.ai';
const clientConfig = {url: apiUrl, apiKey: 'test-key', useGraphQLV2: false};
const clientConfig = {url: apiUrl, apiKey: 'test-key'};
const client = new FarosClient(clientConfig);

describe('client', () => {
Expand Down Expand Up @@ -67,23 +66,6 @@ describe('client', () => {
expect(res).toBe(false);
});

test('get models', async () => {
const mock = nock(apiUrl)
.get('/graphs/g1/models')
.reply(200, {
models: [
{name: 'model1', key: ['key1A', 'key1B']},
{name: 'model2', key: ['key2A', 'key2B']},
],
});
const res = await client.models('g1');
mock.done();
expect(res).toEqual([
{name: 'model1', key: ['key1A', 'key1B']},
{name: 'model2', key: ['key2A', 'key2B']},
]);
});

test('get query', async () => {
const mock = nock(apiUrl)
.get('/queries/my-query')
Expand All @@ -96,15 +78,6 @@ describe('client', () => {
});
});

test('get entry schema', async () => {
const mock = nock(apiUrl)
.get('/graphs/g1/revisions/entries/schema')
.reply(200, {schema: []});
const res = await client.entrySchema('g1');
mock.done();
expect(res).toEqual([]);
});

test('gql', async () => {
const query = `{
tms {
Expand All @@ -118,6 +91,7 @@ describe('client', () => {

const mock = nock(apiUrl)
.post('/graphs/g1/graphql', JSON.stringify({query}))
.query({phantoms: Phantom.IncludeNestedOnly})
.reply(200, {data: {tms: {tasks: {nodes: [{uid: '1'}, {uid: '2'}]}}}});

const res = await client.gql('g1', query);
Expand Down Expand Up @@ -167,23 +141,11 @@ describe('client', () => {
expect(res).toStrictEqual(gqlSchema);
});

test('use v2 off by default', async () => {
const mock = nock(apiUrl, {
badheaders: [GRAPH_VERSION_HEADER],
})
.get('/graphs/foobar/graphql/schema')
.reply(200, gqlSchema);

await client.gqlSchema('foobar');
mock.done();
});

test('check v2 header value', async () => {
await expectV2Request(
{
url: apiUrl,
apiKey: 'test-key',
useGraphQLV2: true,
},
true
);
Expand All @@ -193,7 +155,6 @@ describe('client', () => {
cfg: FarosClientConfig,
expected: true | URLSearchParams
) {
expect(cfg.useGraphQLV2).toBeTruthy();
const mock = nock(apiUrl, {
reqheaders: {
// use literal to be sure as variable requires []'s
Expand All @@ -215,7 +176,6 @@ describe('client', () => {
const clientConfig = {
url: apiUrl,
apiKey: 'test-key',
useGraphQLV2: true,
};
await expectV2Request(clientConfig, expected);
});
Expand All @@ -227,7 +187,6 @@ describe('client', () => {
const clientConfig = {
url: apiUrl,
apiKey: 'test-key',
useGraphQLV2: true,
phantoms: Phantom.Exclude,
};
await expectV2Request(clientConfig, expected);
Expand All @@ -245,7 +204,7 @@ describe('client', () => {
.query({phantoms: Phantom.IncludeNestedOnly})
.reply(200, {data: {result: 'ok'}});

const clientConfig = {url: apiUrl, apiKey: 'test-key', useGraphQLV2: true};
const clientConfig = {url: apiUrl, apiKey: 'test-key'};
const client = new FarosClient(clientConfig);

const res = await client.gql('g1', query);
Expand All @@ -269,7 +228,6 @@ describe('client', () => {
const clientConfig = {
url: apiUrl,
apiKey: 'test-key',
useGraphQLV2: true,
};
const client = new FarosClient(clientConfig);
// baseline test
Expand Down Expand Up @@ -314,6 +272,7 @@ describe('client', () => {
'/graphs/g1/graphql',
JSON.stringify({query, variables: {pageSize: 100, after: 'abc'}})
)
.query({phantoms: Phantom.IncludeNestedOnly})
.reply(200, {
data: {tms: {tasks: {edges: [{node: {uid: '1'}}, {node: {uid: '2'}}]}}},
});
Expand All @@ -328,6 +287,7 @@ describe('client', () => {
test('introspect', async () => {
const mock = nock(apiUrl)
.post('/graphs/g1/graphql')
.query({phantoms: Phantom.IncludeNestedOnly})
.reply(200, {
data: {
__schema: {
Expand Down
Loading