Skip to content

Commit b7ff3ff

Browse files
committed
feat: access to protected api with custom http header #9
1 parent 55a7d17 commit b7ff3ff

File tree

6 files changed

+54
-60
lines changed

6 files changed

+54
-60
lines changed

logo.svg

Lines changed: 5 additions & 51 deletions
Loading

readme.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,14 @@ yarn add -D apigen-ts
4141
### 1. Generate
4242

4343
```sh
44+
# From file
45+
yarn apigen-ts ./openapi.json ./api-client.ts
46+
4447
# From url
4548
yarn apigen-ts https://petstore3.swagger.io/api/v3/openapi.json ./api-client.ts
4649

47-
# From file
48-
yarn apigen-ts ./openapi.json ./api-client.ts
50+
# From protected url
51+
yarn apigen-ts https://secret-api.example.com ./api-client.ts -H "x-api-key: secret-key"
4952
```
5053

5154
Run `yarn apigen-ts --help` for more options. Examples of generated clients [here](./examples/).
@@ -181,6 +184,7 @@ await apigen({
181184
name: "MyApiClient", // default "ApiClient"
182185
parseDates: true, // default false
183186
inlineEnums: false, // default false, use string literal union instead of enum
187+
headers: { "x-api-key": "secret-key" }, // Custom HTTP headers to use when fetching schema
184188
resolveName(ctx, op, proposal) {
185189
// proposal is [string, string] which represents module.funcName
186190
if (proposal[0] === "users") return // will use default proposal

scripts/guru-check.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const loadSpecs = async () => {
2727
if (await fs.stat(out).catch(() => false)) continue
2828

2929
try {
30-
const doc = await loadSchema(spec.url, false)
30+
const doc = await loadSchema({ url: spec.url, upgrade: false })
3131
await fs.writeFile(out, JSON.stringify(doc, null, 2))
3232
console.log(`>> loaded ${spec.name} (${i} of ${specs.length})`)
3333
} catch (err) {

src/config.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type Config = {
1313
parseDates: boolean
1414
inlineEnums: boolean
1515
resolveName?: (ctx: Context, op: OpConfig, proposal: OpName) => OpName | undefined
16+
headers: Record<string, string>
1617
}
1718

1819
export type Context = Config & { doc: Oas3Definition; logTag: string; usedNames: Set<string> }
@@ -25,12 +26,23 @@ export const initCtx = (config?: Partial<Context>): Context => {
2526
doc: { openapi: "3.1.0" },
2627
parseDates: false,
2728
inlineEnums: false,
29+
headers: {},
2830
...config,
2931
logTag: "",
3032
usedNames: new Set(),
3133
}
3234
}
3335

36+
const parseHeaders = (items: string[]): Record<string, string> => {
37+
const headers: Record<string, string> = {}
38+
for (const item of items) {
39+
const [key, val] = item.split(":")
40+
if (key && val) headers[key.trim()] = val.trim()
41+
}
42+
43+
return headers
44+
}
45+
3446
export const getCliConfig = () => {
3547
const argv = cli({
3648
name,
@@ -39,19 +51,26 @@ export const getCliConfig = () => {
3951
flags: {
4052
name: {
4153
type: String,
42-
description: "api class name to export",
54+
description: "API class name to export",
4355
default: "ApiClient",
4456
},
4557
parseDates: {
4658
type: Boolean,
47-
description: "parse dates as Date objects",
59+
description: "Parse dates as Date objects",
4860
default: false,
4961
},
5062
inlineEnums: {
5163
type: Boolean,
52-
description: "use inline enums instead of enum types",
64+
description: "Use inline enums instead of enum types",
5365
default: false,
5466
},
67+
header: {
68+
type: [String],
69+
alias: "H",
70+
description:
71+
'HTTP header as key=value (e.g., -H "x-api-key: your-key"). Used only when generating code.',
72+
default: [],
73+
},
5574
},
5675
})
5776

@@ -61,6 +80,7 @@ export const getCliConfig = () => {
6180
name: argv.flags.name,
6281
parseDates: argv.flags.parseDates,
6382
inlineEnums: argv.flags.inlineEnums,
83+
headers: parseHeaders(argv.flags.header),
6484
}
6585

6686
return config

src/generator.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import redocly, { Oas3Definition } from "@redocly/openapi-core"
1+
import redocly, { BaseResolver, Oas3Definition } from "@redocly/openapi-core"
22
import { filterEmpty, filterNullable } from "array-utils-ts"
33
import { isObject, lowerFirst, sortBy, uniqBy, upperFirst } from "lodash-es"
44
import { convertObj } from "swagger2openapi"
@@ -231,13 +231,29 @@ export const generateAst = async (ctx: Context) => {
231231
return { modules, types }
232232
}
233233

234-
export const loadSchema = async (url: string, upgrade = true): Promise<Oas3Definition> => {
234+
export const loadSchema = async ({
235+
url,
236+
upgrade = true,
237+
headers = {},
238+
}: {
239+
url: string
240+
upgrade?: boolean
241+
headers?: Record<string, string>
242+
}): Promise<Oas3Definition> => {
235243
if (url.startsWith("file://")) url = url.substring(7)
236244

237245
const { bundle } = await redocly.bundle({
238246
ref: url,
239247
config: await redocly.createConfig({}),
240248
removeUnusedComponents: false,
249+
externalRefResolver: new BaseResolver({
250+
http: {
251+
headers: Object.entries(headers).map(([name, value]) => {
252+
// https://github.com/isaacs/minimatch?tab=readme-ov-file#noglobstar
253+
return { name, value, matches: "**" }
254+
}),
255+
},
256+
}),
241257
})
242258

243259
if (bundle.parsed.swagger && upgrade) {

src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { generateAst, loadSchema } from "./generator"
77
import { formatCode, printCode } from "./printer"
88

99
export const apigen = async (config: Partial<Config> & Pick<Config, "source" | "output">) => {
10-
const doc = await loadSchema(config.source)
10+
const doc = await loadSchema({ url: config.source, headers: config.headers })
1111
const ctx = initCtx({ ...config, doc })
1212
const { modules, types } = await generateAst(ctx)
1313

0 commit comments

Comments
 (0)