diff --git a/README.md b/README.md index f852aa4..8bd077f 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ Options: -o, --output <./myClient> output directory -e, --endpoint GraphQL endpoint -p, --post use POST for introspection query + -H, --header <'header: value'> headers to use in fetch -s, --schema <./*.graphql> glob pattern to match GraphQL schema definition files -f, --fetcher <./schemaFetcher.js> path to introspection query fetcher file -c, --config <./myConfig.js> path to config file diff --git a/src/cli.ts b/src/cli.ts index 45086f4..6920fb0 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -9,10 +9,15 @@ import { validateConfigs } from './cliHelpers/validateConfigs' import { Config } from './config' import { requireModuleFromPath } from './helpers/files' +function collect(value: string, previous: string[]) { + return previous.concat([value]) +} + program .option('-o, --output <./myClient>', 'output directory') .option('-e, --endpoint ', 'GraphQL endpoint') .option('-p, --post', 'use POST for introspection query') + .option("-H, --header <'header: value'>", 'headers to use in fetch', collect, []) .option('-s, --schema <./mySchema.graphql>', 'path to GraphQL schema definition file') .option('-f, --fetcher <./schemaFetcher.js>', 'path to introspection query fetcher file') .option('-c, --config <./myConfig.js>', 'path to config file') @@ -27,6 +32,7 @@ const configs: Config[] = program.config { endpoint: program.endpoint, post: program.post, + headers: program.header, schema: program.schema, output: program.output, fetcher: program.fetcher, @@ -35,7 +41,12 @@ const configs: Config[] = program.config if (!validateConfigs(configs)) program.help() -new Listr(configs.map(config => task(config)), { renderer: program.verbose ? 'verbose' : 'default' }).run().catch(e => { - console.log(chalk.red(e.stack)) - process.exit(1) -}) +new Listr( + configs.map(config => task(config)), + { renderer: program.verbose ? 'verbose' : 'default' }, +) + .run() + .catch(e => { + console.log(chalk.red(e.stack)) + process.exit(1) + }) diff --git a/src/cliHelpers/schemaTask.ts b/src/cliHelpers/schemaTask.ts index 3afab8e..7cd7daa 100644 --- a/src/cliHelpers/schemaTask.ts +++ b/src/cliHelpers/schemaTask.ts @@ -12,7 +12,7 @@ export const schemaTask = (config: Config): ListrTask => { return { title: `fetching schema using ${config.post ? 'POST' : 'GET'} ${endpoint}`, task: async ctx => { - ctx.schema = await fetchSchema(endpoint, config.post) + ctx.schema = await fetchSchema(endpoint, config.post, undefined, config.headers) }, } } else if (config.fetcher) { diff --git a/src/cliHelpers/validateConfigs.ts b/src/cliHelpers/validateConfigs.ts index e0317a4..ca1043d 100644 --- a/src/cliHelpers/validateConfigs.ts +++ b/src/cliHelpers/validateConfigs.ts @@ -18,6 +18,12 @@ export const validateConfigs = (configs: Config[]) => { ) if (!config.output) errors.push(`you didn't provide an \`output\` option in ${whichConfig}`) + + if (config.headers) { + config.headers.forEach(header => { + if (!header.includes(':')) errors.push(`header options is invalid in ${whichConfig}`) + }) + } }) errors.forEach(error => console.log(chalk.red(`Error: ${error}`))) diff --git a/src/config.ts b/src/config.ts index 18ef84f..d302a40 100644 --- a/src/config.ts +++ b/src/config.ts @@ -13,6 +13,7 @@ export interface Options { export interface Config { endpoint?: string post?: boolean + headers?: string[] schema?: string output?: string fetcher?: string | SchemaFetcher diff --git a/src/schema/fetchSchema.ts b/src/schema/fetchSchema.ts index 0ad1965..0715841 100644 --- a/src/schema/fetchSchema.ts +++ b/src/schema/fetchSchema.ts @@ -7,20 +7,41 @@ export interface SchemaFetcher { (query: string, fetchImpl: typeof fetch, qsImpl: typeof qs): Promise> } -export const get = (uri: string, query: { [arg: string]: any }): Promise => - fetch(`${uri}?${qs.stringify(query)}`).then(r => r.json()) +export const get = (uri: string, query: { [arg: string]: any }, headers: HeadersInit = {}): Promise => + fetch(`${uri}?${qs.stringify(query)}`, { + headers: { ...headers }, + }).then(r => r.json()) -export const post = (uri: string, body: { [arg: string]: any }): Promise => +export const post = (uri: string, body: { [arg: string]: any }, headers: HeadersInit = {}): Promise => fetch(uri, { method: 'POST', body: JSON.stringify(body), - headers: { 'Content-Type': 'application/json' }, + headers: { 'Content-Type': 'application/json', ...headers }, }).then(r => r.json()) -export const fetchSchema = async (endpoint: string, usePost = false, options?: GraphQLSchemaValidationOptions) => { +export const fetchSchema = async ( + endpoint: string, + usePost = false, + options?: GraphQLSchemaValidationOptions, + headers?: string[], +) => { + const jsonHeaders = headers + ? headers.reduce( + (retval, header) => { + const split = header.split(':') + if (split.length > 1) { + retval[split[0].trim()] = split[1].trim() + } + return retval + }, + {} as { + [key: string]: string + }, + ) + : undefined const result = usePost - ? await post>(endpoint, { query: getIntrospectionQuery() }) - : await get>(endpoint, { query: getIntrospectionQuery() }) + ? await post>(endpoint, { query: getIntrospectionQuery() }, jsonHeaders) + : await get>(endpoint, { query: getIntrospectionQuery() }, jsonHeaders) if (!result.data) { throw new Error('introspection request did not receive a valid response')