Skip to content

Commit

Permalink
(feat): introduce api diffing api for changelogs (#743)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsinghvi authored Apr 30, 2024
1 parent 88f41ae commit 636da28
Show file tree
Hide file tree
Showing 75 changed files with 662 additions and 37 deletions.
17 changes: 17 additions & 0 deletions fern/apis/fdr/definition/commons.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ types:
DocsConfigId:
type: string
docs: The ID of a particular docs config.

EndpointIdentifier:
properties:
path: EndpointPath
method: EndpointMethod

EndpointPath:
type: string
docs: The relative path for an endpont (e.g. `/users/{userId}`)

EndpointMethod:
enum:
- PUT
- POST
- GET
- PATCH
- DELETE

errors:
BadRequestError:
Expand Down
71 changes: 71 additions & 0 deletions fern/apis/fdr/definition/diff.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
imports:
commons: commons.yml

types:
APIDiff:
properties:
endpointDiffs: list<EndpointDiff>

EndpointDiff:
properties:
id: commons.EndpointIdentifier
pathParameterDiff: PathParameterDiff
queryParameterDiff: QueryParameterDiff
requestBodyDiff: RequestBodyDiff
responseBodyDiff: ResponseBodyDiff

PathParameterDiff:
properties:
added: list<PathParameter>
removed: list<PathParameter>

PathParameter:
properties:
wireKey: string

QueryParameterDiff:
properties:
added: list<QueryParameter>
removed: list<QueryParameter>

QueryParameter:
properties:
wireKey: string

RequestBodyDiff:
properties:
added: list<RequestBodyParameter>
removed: list<RequestBodyParameter>

RequestBodyParameter:
properties:
wireKey: string

ResponseBodyDiff:
properties:
added: list<ResponseBodyParameter>
removed: list<ResponseBodyParameter>

ResponseBodyParameter:
properties:
wireKey: string

service:
base-path: /registry
auth: true
endpoints:
diff:
method: GET
path: /diff
request:
name: APIDiffRequest
query-parameters:
previousApiDefinitionId:
type: commons.ApiDefinitionId
docs: The id of the previous version of the api definition
currentApiDefinitionId:
type: commons.ApiDefinitionId
docs: The id of the current version of the api definition
response:
type: APIDiff
docs: The diff between the previous and current api definitions
10 changes: 5 additions & 5 deletions fern/apis/fdr/definition/snippets-factory.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,27 +72,27 @@ types:

SingleTypescriptSnippetCreate:
properties:
endpoint: snippets.EndpointIdentifier
endpoint: commons.EndpointIdentifier
snippet: TypeScriptSnippetCode

SinglePythonSnippetCreate:
properties:
endpoint: snippets.EndpointIdentifier
endpoint: commons.EndpointIdentifier
snippet: PythonSnippetCode

SingleGoSnippetCreate:
properties:
endpoint: snippets.EndpointIdentifier
endpoint: commons.EndpointIdentifier
snippet: GoSnippetCode

SingleRubySnippetCreate:
properties:
endpoint: snippets.EndpointIdentifier
endpoint: commons.EndpointIdentifier
snippet: RubySnippetCode

SingleJavaSnippetCreate:
properties:
endpoint: snippets.EndpointIdentifier
endpoint: commons.EndpointIdentifier
snippet: JavaSnippetCode

# Snippet Code
Expand Down
23 changes: 3 additions & 20 deletions fern/apis/fdr/definition/snippets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ service:
docs: |
The SDKs for which to load snippets. If unspecified,
snippets for the latest published SDKs will be returned.
endpoint: EndpointIdentifier
endpoint: commons.EndpointIdentifier
# TODO: Nice to have, allow client variable name to be configurable
# clientName:
# type: optional<string>
Expand Down Expand Up @@ -206,23 +206,6 @@ service:
})
types:
EndpointIdentifier:
properties:
path: EndpointPath
method: EndpointMethod

EndpointPath:
type: string
docs: The relative path for an endpont (e.g. `/users/{userId}`)

EndpointMethod:
enum:
- PUT
- POST
- GET
- PATCH
- DELETE

SDK:
union:
typescript: TypeScriptSDK
Expand Down Expand Up @@ -281,13 +264,13 @@ types:
type: optional<integer>
docs: If present, pass this into the `page` query parameter to load the next page.
snippets:
type: map<EndpointPath, SnippetsByEndpointMethod>
type: map<commons.EndpointPath, SnippetsByEndpointMethod>
docs: |
The snippets are returned as a map of endpoint path (e.g. `/api/users`)
to a map of endpoint method (e.g. `POST`) to snippets.
SnippetsByEndpointMethod:
type: map<EndpointMethod, list<Snippet>>
type: map<commons.EndpointMethod, list<Snippet>>

# TODO: we should transition snippets to a more user friendly API like below to allow for more flexibility on the consumer side:
# Snippet:
Expand Down
6 changes: 3 additions & 3 deletions fern/apis/fdr/definition/templates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ service:
docs: |
The API name.
sdk: snippets.SDK
endpointId: snippets.EndpointIdentifier
endpointId: commons.EndpointIdentifier
response: EndpointSnippetTemplate

types:
Expand Down Expand Up @@ -212,13 +212,13 @@ types:
SnippetRegistryEntry:
properties:
sdk: snippets.SDK
endpointId: snippets.EndpointIdentifier
endpointId: commons.EndpointIdentifier
snippetTemplate: VersionedSnippetTemplate

EndpointSnippetTemplate:
properties:
sdk: snippets.SDK
endpointId: snippets.EndpointIdentifier
endpointId: commons.EndpointIdentifier
snippetTemplate: VersionedSnippetTemplate

errors:
Expand Down
7 changes: 7 additions & 0 deletions packages/fdr-sdk/src/client/generated/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as environments from "./environments";
import * as core from "./core";
import { Api } from "./api/resources/api/client/Client";
import { Docs } from "./api/resources/docs/client/Client";
import { Diff } from "./api/resources/diff/client/Client";
import { SnippetsFactory } from "./api/resources/snippetsFactory/client/Client";
import { Snippets } from "./api/resources/snippets/client/Client";
import { Templates } from "./api/resources/templates/client/Client";
Expand Down Expand Up @@ -37,6 +38,12 @@ export class FernRegistryClient {
return (this._docs ??= new Docs(this._options));
}

protected _diff: Diff | undefined;

public get diff(): Diff {
return (this._diff ??= new Diff(this._options));
}

protected _snippetsFactory: SnippetsFactory | undefined;

public get snippetsFactory(): SnippetsFactory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ export * from "./ApiDefinitionId";
export * from "./OrgId";
export * from "./ApiId";
export * from "./DocsConfigId";
export * from "./EndpointIdentifier";
export * from "./EndpointPath";
export * from "./EndpointMethod";
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* This file was auto-generated by Fern from our API Definition.
*/

import * as environments from "../../../../environments";
import * as core from "../../../../core";
import * as FernRegistry from "../../..";
import urlJoin from "url-join";

export declare namespace Diff {
interface Options {
environment?: core.Supplier<environments.FernRegistryEnvironment | string>;
token?: core.Supplier<core.BearerToken | undefined>;
}

interface RequestOptions {
timeoutInSeconds?: number;
maxRetries?: number;
}
}

export class Diff {
constructor(protected readonly _options: Diff.Options = {}) {}

public async diff(
request: FernRegistry.ApiDiffRequest,
requestOptions?: Diff.RequestOptions
): Promise<core.APIResponse<FernRegistry.ApiDiff, FernRegistry.diff.diff.Error>> {
const { previousApiDefinitionId, currentApiDefinitionId } = request;
const _queryParams: Record<string, string | string[] | object | object[]> = {};
_queryParams["previousApiDefinitionId"] = previousApiDefinitionId;
_queryParams["currentApiDefinitionId"] = currentApiDefinitionId;
const _response = await core.fetcher({
url: urlJoin(
(await core.Supplier.get(this._options.environment)) ?? environments.FernRegistryEnvironment.Dev,
"/registry/diff"
),
method: "GET",
headers: {
Authorization: await this._getAuthorizationHeader(),
"X-Fern-Language": "JavaScript",
"X-Fern-Runtime": core.RUNTIME.type,
"X-Fern-Runtime-Version": core.RUNTIME.version,
},
contentType: "application/json",
queryParameters: _queryParams,
timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : undefined,
maxRetries: requestOptions?.maxRetries,
});
if (_response.ok) {
return {
ok: true,
body: _response.body as FernRegistry.ApiDiff,
};
}

return {
ok: false,
error: FernRegistry.diff.diff.Error._unknown(_response.error),
};
}

protected async _getAuthorizationHeader() {
const bearer = await core.Supplier.get(this._options.token);
if (bearer != null) {
return `Bearer ${bearer}`;
}

return undefined;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* This file was auto-generated by Fern from our API Definition.
*/

import * as FernRegistry from "../../..";
import * as core from "../../../../core";

export type Error = FernRegistry.diff.diff.Error._Unknown;

export declare namespace Error {
interface _Unknown {
error: void;
content: core.Fetcher.Error;
}

interface _Visitor<_Result> {
_other: (value: core.Fetcher.Error) => _Result;
}
}

export const Error = {
_unknown: (fetcherError: core.Fetcher.Error): FernRegistry.diff.diff.Error._Unknown => {
return {
error: undefined,
content: fetcherError,
};
},

_visit: <_Result>(
value: FernRegistry.diff.diff.Error,
visitor: FernRegistry.diff.diff.Error._Visitor<_Result>
): _Result => {
switch (value.error) {
default:
return visitor._other(value as any);
}
},
} as const;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./requests";
export * as diff from "./diff";
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* This file was auto-generated by Fern from our API Definition.
*/

import * as FernRegistry from "../../../..";

export interface ApiDiffRequest {
/**
* The id of the previous version of the api definition
*/
previousApiDefinitionId: FernRegistry.ApiDefinitionId;
/**
* The id of the current version of the api definition
*/
currentApiDefinitionId: FernRegistry.ApiDefinitionId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ApiDiffRequest } from "./ApiDiffRequest";
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./types";
export * from "./client";
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* This file was auto-generated by Fern from our API Definition.
*/

import * as FernRegistry from "../../..";

export interface ApiDiff {
endpointDiffs: FernRegistry.EndpointDiff[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* This file was auto-generated by Fern from our API Definition.
*/

import * as FernRegistry from "../../..";

export interface EndpointDiff {
id: FernRegistry.EndpointIdentifier;
pathParameterDiff: FernRegistry.PathParameterDiff;
queryParameterDiff: FernRegistry.QueryParameterDiff;
requestBodyDiff: FernRegistry.RequestBodyDiff;
responseBodyDiff: FernRegistry.ResponseBodyDiff;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* This file was auto-generated by Fern from our API Definition.
*/

export interface PathParameter {
wireKey: string;
}
Loading

0 comments on commit 636da28

Please sign in to comment.