Skip to content

Commit

Permalink
fix: add in the IR endpoint identifier (optionally) to have a more un…
Browse files Browse the repository at this point in the history
…ique id (#881)
  • Loading branch information
armandobelardo authored May 17, 2024
1 parent 1854968 commit cb0d2d2
Show file tree
Hide file tree
Showing 30 changed files with 592 additions and 92 deletions.
1 change: 1 addition & 0 deletions fern/apis/fdr/definition/api/v1/db/endpoint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ types:
environments: optional<list<readEndpoint.Environment>>
method: readEndpoint.HttpMethod
id: readEndpoint.EndpointId
originalEndpointId: optional<string>
urlSlug: string
migratedFromUrlSlugs: optional<list<string>>
name: optional<string>
Expand Down
3 changes: 2 additions & 1 deletion fern/apis/fdr/definition/api/v1/read/endpoint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ types:
environments: list<Environment>
method: HttpMethod
id: EndpointId
originalEndpointId: optional<string>
urlSlug: string
migratedFromUrlSlugs: optional<list<string>>
name: optional<string>
Expand Down Expand Up @@ -112,7 +113,7 @@ types:
extends: commons.WithDescription
properties:
type: HttpResponseBodyShape
statusCode:
statusCode:
type: optional<integer>
docs: Defaults to 200

Expand Down
10 changes: 9 additions & 1 deletion fern/apis/fdr/definition/api/v1/register/endpoint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,15 @@ types:
defaultEnvironment: optional<EnvironmentId>
environments: optional<list<Environment>>
method: HttpMethod
id: EndpointId
id:
type: EndpointId
docs: This is the name of the endpoint.
originalEndpointId:
type: optional<string>
docs: |
The ID for the endpoint as declared within the IR, this is a unique name for the endpoint, whereas
path and method are not (specifically for the fern definition, consider chat and chat stream).
This is optional to remain backcompat with old definitions of yore.
name: optional<string>
path: EndpointPath
queryParameters: list<QueryParameter>
Expand Down
8 changes: 7 additions & 1 deletion fern/apis/fdr/definition/commons.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ types:
DocsConfigId:
type: string
docs: The ID of a particular docs config.

EndpointIdentifier:
properties:
path: EndpointPath
method: EndpointMethod
identifierOverride:
type: optional<string>
docs: |
The ID for the endpoint as declared within the IR, this is a unique name for the endpoint, whereas path and
method are not (specifically for the fern definition, consider chat and chat stream). This is optional to
remain backcompat with old snippets of yore.
EndpointPath:
type: string
Expand Down
2 changes: 1 addition & 1 deletion fern/fern.config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"organization": "fern",
"version": "0.26.7"
"version": "0.26.9"
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface DbEndpointDefinition extends FernRegistry.api.v1.read.WithDescr
environments?: FernRegistry.api.v1.read.Environment[];
method: FernRegistry.api.v1.read.HttpMethod;
id: FernRegistry.api.v1.read.EndpointId;
originalEndpointId?: string;
urlSlug: string;
migratedFromUrlSlugs?: string[];
name?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface EndpointDefinition extends FernRegistry.api.v1.read.WithDescrip
environments: FernRegistry.api.v1.read.Environment[];
method: FernRegistry.api.v1.read.HttpMethod;
id: FernRegistry.api.v1.read.EndpointId;
originalEndpointId?: string;
urlSlug: string;
migratedFromUrlSlugs?: string[];
name?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ export interface EndpointDefinition
defaultEnvironment?: FernRegistry.api.v1.register.EnvironmentId;
environments?: FernRegistry.api.v1.register.Environment[];
method: FernRegistry.api.v1.register.HttpMethod;
/** This is the name of the endpoint. */
id: FernRegistry.api.v1.register.EndpointId;
/**
* The ID for the endpoint as declared within the IR, this is a unique name for the endpoint, whereas
* path and method are not (specifically for the fern definition, consider chat and chat stream).
* This is optional to remain backcompat with old definitions of yore.
*/
originalEndpointId?: string;
name?: string;
path: FernRegistry.api.v1.register.EndpointPath;
queryParameters: FernRegistry.api.v1.register.QueryParameter[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@ import * as FernRegistry from "../../..";
export interface EndpointIdentifier {
path: FernRegistry.EndpointPath;
method: FernRegistry.EndpointMethod;
/**
* The ID for the endpoint as declared within the IR, this is a unique name for the endpoint, whereas path and
* method are not (specifically for the fern definition, consider chat and chat stream). This is optional to
* remain backcompat with old snippets of yore.
*/
identifierOverride?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ function transformEndpoint({
// const htmlDescription = getHtmlDescription(writeShape.description);
const urlSlug = kebabCase(writeShape.id);
const oldUrlSlug = kebabCase(writeShape.name ?? writeShape.id);

return {
availability: writeShape.availability,
environments: writeShape.environments,
Expand All @@ -192,6 +193,7 @@ function transformEndpoint({
migratedFromUrlSlugs: !isEqual(oldUrlSlug, urlSlug) ? [oldUrlSlug] : undefined,
method: writeShape.method,
id: writeShape.id,
originalEndpointId: writeShape.originalEndpointId,
name: writeShape.name,
path: writeShape.path,
queryParameters: writeShape.queryParameters,
Expand Down Expand Up @@ -220,6 +222,7 @@ function transformEndpoint({
snippetTemplates: snippets.getSnippetTemplateForEndpoint({
endpointPath: getEndpointPathAsString(writeShape),
endpointMethod: writeShape.method,
identifierOverride: writeShape.originalEndpointId,
}),
};
}
Expand Down Expand Up @@ -501,18 +504,22 @@ function transformCodeExamples({
const maybePythonSnippet = snippets.getPythonCodeSnippetForEndpoint({
endpointMethod: endpointDefinition.method,
endpointPath: getEndpointPathAsString(endpointDefinition),
identifierOverride: endpointDefinition.originalEndpointId,
});
const maybeTypescriptSnippet = snippets.getTypeScriptCodeSnippetForEndpoint({
endpointMethod: endpointDefinition.method,
endpointPath: getEndpointPathAsString(endpointDefinition),
identifierOverride: endpointDefinition.originalEndpointId,
});
const maybeGoSnippet = snippets.getGoCodeSnippetForEndpoint({
endpointMethod: endpointDefinition.method,
endpointPath: getEndpointPathAsString(endpointDefinition),
identifierOverride: endpointDefinition.originalEndpointId,
});
const maybeRubySnippet = snippets.getRubyCodeSnippetForEndpoint({
endpointMethod: endpointDefinition.method,
endpointPath: getEndpointPathAsString(endpointDefinition),
identifierOverride: endpointDefinition.originalEndpointId,
});
return {
nodeAxios: "",
Expand Down
80 changes: 74 additions & 6 deletions packages/fdr-sdk/src/converters/db/snippets/SDKSnippetHolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,65 @@ export interface SnippetsConfigWithSdkId {
}

export interface SdkSnippetHolderArgs {
// Legacy format for snippets leveraging path and method (which is not unique enough for some cases)
snippetsBySdkId: Record<string, Record<FdrAPI.EndpointPath, FdrAPI.SnippetsByEndpointMethod>>;
// If these are present for the SDK ID, use these, otherwise use snippetsBySdkId
snippetsBySdkIdAndEndpointId: Record<string, Record<string, FdrAPI.Snippet[]>>;
snippetsConfigWithSdkId: SnippetsConfigWithSdkId;
snippetTemplatesByEndpoint: Record<
FdrAPI.EndpointPath,
Record<FdrAPI.EndpointMethod, APIV1Read.EndpointSnippetTemplates>
>;
snippetTemplatesByEndpointId: Record<string, APIV1Read.EndpointSnippetTemplates>;
}

export class SDKSnippetHolder {
private snippetsBySdkId: Record<string, Record<FdrAPI.EndpointPath, FdrAPI.SnippetsByEndpointMethod>>;
private snippetsBySdkIdAndEndpointId: Record<string, Record<string, FdrAPI.Snippet[]>>;
private snippetsConfigWithSdkId: SnippetsConfigWithSdkId;
private snippetTemplatesByEndpoint: Record<
FdrAPI.EndpointPath,
Record<FdrAPI.EndpointMethod, APIV1Read.EndpointSnippetTemplates>
>;
private snippetTemplatesByEndpointId: Record<string, APIV1Read.EndpointSnippetTemplates>;

constructor({ snippetsBySdkId, snippetsConfigWithSdkId, snippetTemplatesByEndpoint }: SdkSnippetHolderArgs) {
constructor({
snippetsBySdkId,
snippetsConfigWithSdkId,
snippetTemplatesByEndpoint,
snippetsBySdkIdAndEndpointId,
snippetTemplatesByEndpointId,
}: SdkSnippetHolderArgs) {
this.snippetsBySdkId = snippetsBySdkId;
this.snippetsConfigWithSdkId = snippetsConfigWithSdkId;
this.snippetTemplatesByEndpoint = snippetTemplatesByEndpoint;
this.snippetsBySdkIdAndEndpointId = snippetsBySdkIdAndEndpointId;
this.snippetTemplatesByEndpointId = snippetTemplatesByEndpointId;
}

public getPythonCodeSnippetForEndpoint({
endpointPath,
endpointMethod,
identifierOverride,
}: {
endpointPath: string;
endpointMethod: FdrAPI.EndpointMethod;
identifierOverride: string | undefined;
}): APIV1Read.PythonSnippet | undefined {
if (this.snippetsConfigWithSdkId.pythonSdk == null) {
return undefined;
}

const sdkId = this.snippetsConfigWithSdkId.pythonSdk.sdkId;
const snippetsForEndpoint = this.snippetsBySdkId[sdkId]?.[endpointPath]?.[endpointMethod];
let snippetsForEndpoint;
if (identifierOverride != null) {
snippetsForEndpoint = this.snippetsBySdkIdAndEndpointId[sdkId]?.[identifierOverride];
}

if (identifierOverride == null || this.snippetsBySdkIdAndEndpointId[sdkId] == null) {
snippetsForEndpoint = this.snippetsBySdkId[sdkId]?.[endpointPath]?.[endpointMethod];
}

// if no snippets for this endpoint or multiple snippets just return undefined
if (snippetsForEndpoint == null || snippetsForEndpoint.length > 1) {
return undefined;
Expand All @@ -60,15 +85,26 @@ export class SDKSnippetHolder {
public getTypeScriptCodeSnippetForEndpoint({
endpointPath,
endpointMethod,
identifierOverride,
}: {
endpointPath: string;
endpointMethod: FdrAPI.EndpointMethod;
identifierOverride: string | undefined;
}): APIV1Read.TypescriptSnippet | undefined {
if (this.snippetsConfigWithSdkId.typescriptSdk == null) {
return undefined;
}

const sdkId = this.snippetsConfigWithSdkId.typescriptSdk.sdkId;
const snippetsForEndpoint = this.snippetsBySdkId[sdkId]?.[endpointPath]?.[endpointMethod];
let snippetsForEndpoint;
if (identifierOverride != null) {
snippetsForEndpoint = this.snippetsBySdkIdAndEndpointId[sdkId]?.[identifierOverride];
}

if (identifierOverride == null || this.snippetsBySdkIdAndEndpointId[sdkId] == null) {
snippetsForEndpoint = this.snippetsBySdkId[sdkId]?.[endpointPath]?.[endpointMethod];
}

// if no snippets for this endpoint or multiple snippets just return undefined
if (snippetsForEndpoint == null || snippetsForEndpoint.length > 1) {
return undefined;
Expand All @@ -85,15 +121,26 @@ export class SDKSnippetHolder {
public getGoCodeSnippetForEndpoint({
endpointPath,
endpointMethod,
identifierOverride,
}: {
endpointPath: string;
endpointMethod: FdrAPI.EndpointMethod;
identifierOverride: string | undefined;
}): APIV1Read.GoSnippet | undefined {
if (this.snippetsConfigWithSdkId.goSdk == null) {
return undefined;
}

const sdkId = this.snippetsConfigWithSdkId.goSdk.sdkId;
const snippetsForEndpoint = this.snippetsBySdkId[sdkId]?.[endpointPath]?.[endpointMethod];
let snippetsForEndpoint;
if (identifierOverride != null) {
snippetsForEndpoint = this.snippetsBySdkIdAndEndpointId[sdkId]?.[identifierOverride];
}

if (identifierOverride == null || this.snippetsBySdkIdAndEndpointId[sdkId] == null) {
snippetsForEndpoint = this.snippetsBySdkId[sdkId]?.[endpointPath]?.[endpointMethod];
}

// if no snippets for this endpoint or multiple snippets just return undefined
if (snippetsForEndpoint == null || snippetsForEndpoint.length > 1) {
return undefined;
Expand All @@ -110,15 +157,26 @@ export class SDKSnippetHolder {
public getRubyCodeSnippetForEndpoint({
endpointPath,
endpointMethod,
identifierOverride,
}: {
endpointPath: string;
endpointMethod: FdrAPI.EndpointMethod;
identifierOverride: string | undefined;
}): APIV1Read.RubySnippet | undefined {
if (this.snippetsConfigWithSdkId.rubySdk == null) {
return undefined;
}

const sdkId = this.snippetsConfigWithSdkId.rubySdk.sdkId;
const snippetsForEndpoint = this.snippetsBySdkId[sdkId]?.[endpointPath]?.[endpointMethod];
let snippetsForEndpoint;
if (identifierOverride != null) {
snippetsForEndpoint = this.snippetsBySdkIdAndEndpointId[sdkId]?.[identifierOverride];
}

if (identifierOverride == null || this.snippetsBySdkIdAndEndpointId[sdkId] == null) {
snippetsForEndpoint = this.snippetsBySdkId[sdkId]?.[endpointPath]?.[endpointMethod];
}

// if no snippets for this endpoint or multiple snippets just return undefined
if (snippetsForEndpoint == null || snippetsForEndpoint.length > 1) {
return undefined;
Expand All @@ -135,10 +193,20 @@ export class SDKSnippetHolder {
public getSnippetTemplateForEndpoint({
endpointPath,
endpointMethod,
identifierOverride,
}: {
endpointPath: string;
endpointMethod: FdrAPI.EndpointMethod;
identifierOverride: string | undefined;
}): APIV1Read.EndpointSnippetTemplates | undefined {
return this.snippetTemplatesByEndpoint[endpointPath]?.[endpointMethod];
let snippetsForEndpoint;
if (identifierOverride != null) {
snippetsForEndpoint = this.snippetTemplatesByEndpointId[identifierOverride];
}

if (identifierOverride == null || this.snippetTemplatesByEndpointId[identifierOverride] == null) {
snippetsForEndpoint = this.snippetTemplatesByEndpoint[endpointPath]?.[endpointMethod];
}
return snippetsForEndpoint;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ function transformEndpoint({
migratedFromUrlSlugs: dbShape.migratedFromUrlSlugs,
method: dbShape.method,
id: dbShape.id,
originalEndpointId: dbShape.originalEndpointId,
name: dbShape.name,
path: dbShape.path,
queryParameters: dbShape.queryParameters,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "Snippet" ADD COLUMN "identifierOverride" TEXT;

-- AlterTable
ALTER TABLE "SnippetTemplate" ADD COLUMN "identifierOverride" TEXT;
40 changes: 21 additions & 19 deletions servers/fdr/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -84,31 +84,33 @@ model OverwrittenAlgoliaIndex {
}

model SnippetTemplate {
id String @id
orgId String
apiName String
apiDefinitionId String
endpointPath String
endpointMethod HttpMethod
sdkId String
id String @id
orgId String
apiName String
apiDefinitionId String
endpointPath String
endpointMethod HttpMethod
identifierOverride String?
sdkId String
// sdk Sdk @relation(fields: [sdkId], references: [id], onDelete: Cascade)
version SnippetTemplateSemanticVersion
version SnippetTemplateSemanticVersion
// The actual templates themselves held as binary data to save encoding the schema, which may change
functionInvocation Bytes
clientInstantiation Bytes
functionInvocation Bytes
clientInstantiation Bytes
}

model Snippet {
id String @id
orgId String
apiName String
endpointPath String
endpointMethod HttpMethod
sdkId String
sdk Sdk @relation(fields: [sdkId], references: [id], onDelete: Cascade)
snippet Bytes
createdAt DateTime @default(now())
id String @id
orgId String
apiName String
endpointPath String
endpointMethod HttpMethod
identifierOverride String?
sdkId String
sdk Sdk @relation(fields: [sdkId], references: [id], onDelete: Cascade)
snippet Bytes
createdAt DateTime @default(now())
}

model Sdk {
Expand Down
Loading

0 comments on commit cb0d2d2

Please sign in to comment.