Skip to content

Commit

Permalink
fix(cli): support override openapi auth schemes (#4546)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsinghvi authored Sep 5, 2024
1 parent 97758ac commit 9f3a3a4
Show file tree
Hide file tree
Showing 18 changed files with 518 additions and 28 deletions.
25 changes: 25 additions & 0 deletions packages/cli/cli/versions.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
- changelog_entry:
- summary: |
Fixes an issue introduced in `0.41.1` that ignored server urls for docs generation.
type: fix
- summary: |
Adds a `auth-schemes` and `auth` block where you can override auth for an existing spec.
See below:
```generators.yml
auth-schemes:
Oauth:
scheme: oauth
type: client-credentials
get-token:
endpoint: auth.get-token
api:
auth: Oauth # overrides auth scheme
specs:
- openapi: path/to/openapi
```
type: feat
created_at: '2024-09-05'
ir_version: 53
version: 0.41.2

- changelog_entry:
- summary: |
Adds a V2 configuration for the `api` block that is more flexible and allows
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ export interface GeneratorsConfiguration {

export type APIDefinition = SingleNamespaceAPIDefinition | MultiNamespaceAPIDefinition;

export interface SingleNamespaceAPIDefinition extends RawSchemas.WithEnvironmentsSchema {
export interface SingleNamespaceAPIDefinition extends RawSchemas.WithEnvironmentsSchema, RawSchemas.WithAuthSchema {
type: "singleNamespace";
definitions: APIDefinitionLocation[];
}

export interface MultiNamespaceAPIDefinition extends RawSchemas.WithEnvironmentsSchema {
export interface MultiNamespaceAPIDefinition extends RawSchemas.WithEnvironmentsSchema, RawSchemas.WithAuthSchema {
type: "multiNamespace";
definitions: Record<string, APIDefinitionLocation[]>;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { OutputMetadataSchema } from "./schemas/OutputMetadataSchema";
import { PypiOutputMetadataSchema } from "./schemas/PypiOutputMetadataSchema";
import { ReadmeSchema } from "./schemas/ReadmeSchema";
import { ReviewersSchema } from "./schemas/ReviewersSchema";
import { visitRawApiAuth } from "@fern-api/fern-definition-schema";

export async function convertGeneratorsConfiguration({
absolutePathToGeneratorsConfiguration,
Expand Down Expand Up @@ -247,6 +248,24 @@ async function parseAPIConfiguration(
if (apiConfiguration != null && isApiConfigurationV2Schema(apiConfiguration)) {
return {
type: "singleNamespace",
"auth-schemes":
apiConfiguration.auth != null
? Object.fromEntries(
Object.entries(rawGeneratorsConfiguration["auth-schemes"] ?? {}).filter(([name, _]) => {
if (apiConfiguration.auth == null) {
return false;
}
return visitRawApiAuth(apiConfiguration.auth, {
any: (any) => {
return any.any.includes(name);
},
single: (single) => {
return single === name;
}
});
})
)
: undefined,
...apiConfiguration,
definitions: apiConfiguration.specs
.map((spec): APIDefinitionLocation | undefined => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ export const SpecSchema = z.union([OpenAPISpecSchema, AsyncAPISchema]);
export type SpecSchema = z.infer<typeof SpecSchema>;

export const APIConfigurationV2Schema = RawSchemas.WithEnvironmentsSchema.extend({
auth: z.optional(RawSchemas.ApiAuthSchema),
specs: z.array(SpecSchema)
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { RawSchemas } from "@fern-api/fern-definition-schema";
import { z } from "zod";
import { APIConfigurationSchema, APIDefinitionSettingsSchema } from "./APIConfigurationSchema";
import { GeneratorGroupSchema } from "./GeneratorGroupSchema";
Expand All @@ -15,6 +16,8 @@ export const ASYNC_API_LOCATION_KEY = "async-api";
export const API_SETTINGS_KEY = "api-settings";

export const GeneratorsConfigurationSchema = z.strictObject({
"auth-schemes": z.optional(z.record(RawSchemas.AuthSchemeDeclarationSchema)),

api: z.optional(APIConfigurationSchema),

whitelabel: z.optional(WhitelabelConfigurationSchema),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ exports[`validate > petstore 1`] = `
error-discrimination:
strategy: status-code
display-name: Swagger Petstore
environments:
Default: http://petstore.swagger.io/v1
default-environment: Default
",
"name": "api.yml",
"type": "file",
Expand Down Expand Up @@ -188,6 +191,9 @@ errors:
error-discrimination:
strategy: status-code
display-name: Train Travel API
default-environment: Production
environments:
Production: https://api.example.com
auth-schemes:
BearerAuthScheme:
scheme: bearer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name: api
error-discrimination:
strategy: status-code
display-name: Train Travel API
default-environment: Production
environments:
Production: https://api.example.com
auth-schemes:
BearerAuthScheme:
scheme: bearer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ name: api
error-discrimination:
strategy: status-code
display-name: Swagger Petstore
environments:
Default: http://petstore.swagger.io/v1
default-environment: Default
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,31 @@ export const WithEnvironmentsSchema = z.strictObject({

export type WithEnvironmentsSchema = z.infer<typeof WithEnvironmentsSchema>;

export const RootApiFileSchema = WithEnvironmentsSchema.extend({
name: z.string(), // TODO: should this be migrated to id?
"display-name": z.optional(z.string()),
imports: z.optional(z.record(z.string())),
export const WithAuthSchema = z.strictObject({
auth: z.optional(ApiAuthSchema),
"auth-schemes": z.optional(z.record(AuthSchemeDeclarationSchema)),
headers: z.optional(z.record(z.string(), HttpHeaderSchema)),
"error-discrimination": z.optional(ErrorDiscriminationSchema),
audiences: z.optional(z.array(z.string())),
docs: z.optional(z.string()),
errors: z.optional(z.array(z.string())),
"base-path": z.optional(z.string()),
"path-parameters": z.optional(z.record(HttpPathParameterSchema)),
"idempotency-headers": z.optional(z.record(z.string(), HttpHeaderSchema)),
variables: z.optional(z.record(VariableDeclarationSchema)),
pagination: z.optional(PaginationSchema),
version: z.optional(VersionDeclarationSchema)
"auth-schemes": z.optional(z.record(AuthSchemeDeclarationSchema))
});

export type WithAuthSchema = z.infer<typeof WithAuthSchema>;

export const RootApiFileSchema = z
.strictObject({
name: z.string(), // TODO: should this be migrated to id?
"display-name": z.optional(z.string()),
imports: z.optional(z.record(z.string())),
headers: z.optional(z.record(z.string(), HttpHeaderSchema)),
"error-discrimination": z.optional(ErrorDiscriminationSchema),
audiences: z.optional(z.array(z.string())),
docs: z.optional(z.string()),
errors: z.optional(z.array(z.string())),
"base-path": z.optional(z.string()),
"path-parameters": z.optional(z.record(HttpPathParameterSchema)),
"idempotency-headers": z.optional(z.record(z.string(), HttpHeaderSchema)),
variables: z.optional(z.record(VariableDeclarationSchema)),
pagination: z.optional(PaginationSchema),
version: z.optional(VersionDeclarationSchema)
})
.extend(WithEnvironmentsSchema.shape)
.extend(WithAuthSchema.shape);

export type RootApiFileSchema = z.infer<typeof RootApiFileSchema>;
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { DefinitionFileSchema } from "./DefinitionFileSchema";
export { PackageMarkerFileSchema } from "./PackageMarkerFileSchema";
export { RootApiFileSchema, WithEnvironmentsSchema } from "./RootApiFileSchema";
export { RootApiFileSchema, WithEnvironmentsSchema, WithAuthSchema } from "./RootApiFileSchema";
6 changes: 3 additions & 3 deletions packages/cli/openapi-ir-to-fern/src/FernDefnitionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface FernDefinitionBuilder {

addAuthScheme({ name, schema }: { name: string; schema: RawSchemas.AuthSchemeDeclarationSchema }): void;

setAuth(name: string): void;
setAuth(name: RawSchemas.ApiAuthSchema): void;

getGlobalHeaderNames(): Set<string>;

Expand Down Expand Up @@ -138,8 +138,8 @@ export class FernDefinitionBuilderImpl implements FernDefinitionBuilder {
this.rootApiFile.audiences.push(name);
}

public setAuth(name: string): void {
this.rootApiFile.auth = name;
public setAuth(auth: RawSchemas.ApiAuthSchema): void {
this.rootApiFile.auth = auth;
}

public addAuthScheme({ name, schema }: { name: string; schema: RawSchemas.AuthSchemeDeclarationSchema }): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export interface OpenApiIrConverterContextOpts {
*/
detectGlobalHeaders: boolean;

authOverrides?: RawSchemas.WithAuthSchema;

environmentOverrides?: RawSchemas.WithEnvironmentsSchema;
}

Expand All @@ -29,6 +31,7 @@ export class OpenApiIrConverterContext {
public ir: OpenApiIntermediateRepresentation;
public builder: FernDefinitionBuilder;
public environmentOverrides: RawSchemas.WithEnvironmentsSchema | undefined;
public authOverrides: RawSchemas.WithAuthSchema | undefined;
public detectGlobalHeaders: boolean;
private defaultServerName: string | undefined = undefined;

Expand All @@ -37,14 +40,16 @@ export class OpenApiIrConverterContext {
ir,
enableUniqueErrorsPerEndpoint,
detectGlobalHeaders,
environmentOverrides
environmentOverrides,
authOverrides
}: OpenApiIrConverterContextOpts) {
this.logger = taskContext.logger;
this.taskContext = taskContext;
this.ir = ir;
this.builder = new FernDefinitionBuilderImpl(ir, false, enableUniqueErrorsPerEndpoint);
this.detectGlobalHeaders = detectGlobalHeaders;
this.environmentOverrides = environmentOverrides;
this.authOverrides = authOverrides;
}

public getSchema(id: SchemaId): Schema | undefined {
Expand Down
Loading

0 comments on commit 9f3a3a4

Please sign in to comment.