Skip to content

Commit

Permalink
(feat): init new snippets template-based API (cherry-picked) (#669)
Browse files Browse the repository at this point in the history
  • Loading branch information
armandobelardo authored Apr 19, 2024
1 parent 405b8d3 commit 28071e5
Show file tree
Hide file tree
Showing 122 changed files with 2,339 additions and 91 deletions.
34 changes: 34 additions & 0 deletions fern/apis/fdr/definition/__package__.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ service:
The SDKs for which to load snippets. If unspecified,
snippets for the latest published SDKs will be returned.
endpoint: EndpointIdentifier
# TODO: Nice to have, allow client variable name to be configurable
# clientName:
# type: optional<string>
# docs: |
# The name of the client to be used in the snippet. If not specified then the default client name (the API name) will be used.
payload:
type: optional<CustomSnippetPayload>
docs: |
The JSON payload to be used as the input for the code snippet. This should just be thought of as the
request body you'd be sending to the endpoint as a cURL. If not specified then the default payload will be used.
response: list<Snippet>
errors:
- commons.UnauthorizedError
Expand Down Expand Up @@ -252,6 +263,18 @@ types:

####### Load Snippets #######

### Load Snippets Custom Payload ###
ParameterPayload:
properties:
name: string
value: unknown
CustomSnippetPayload:
properties:
headers: optional<list<ParameterPayload>>
pathParameters: optional<list<ParameterPayload>>
queryParameters: optional<list<ParameterPayload>>
requestBody: optional<unknown>

SnippetsPage:
properties:
next:
Expand All @@ -266,6 +289,12 @@ types:
SnippetsByEndpointMethod:
type: map<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:
# properties:
# imports: string[]
# clientInstantiation: string
# functionInvocation: string
Snippet:
union:
typescript: TypeScriptSnippet
Expand Down Expand Up @@ -312,6 +341,11 @@ errors:
docs: "An OrgId is required"
type: string

SnippetTemplateNotFoundError:
status-code: 404
docs: "A template for this snippet could not be found"
type: string

InvalidPageError:
status-code: 400
docs: "Page must be >=1"
Expand Down
191 changes: 191 additions & 0 deletions fern/apis/fdr/definition/template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
imports:
commons: commons.yml
snippets: __package__.yml

service:
auth: true
base-path: /snippet-template
endpoints:
register:
path: /register
docs: Store endpoint snippet for a particular SDK.
display-name: Store snippet
method: POST
request:
name: RegisterSnippetTemplateRequest
body:
properties:
orgId:
type: commons.OrgId
docs: |
The organization to create snippets for.
apiId:
type: commons.ApiId
docs: |
The API name.
apiDefinitionId: commons.ApiDefinitionId
snippet: SnippetRegistryEntry

registerBatch:
path: /register/batch
docs: Store endpoint snippets for a particular SDK.
display-name: Store snippets
method: POST
request:
name: RegisterSnippetTemplateBatchRequest
body:
properties:
orgId:
type: commons.OrgId
docs: |
The organization to create snippets for.
apiId:
type: commons.ApiId
docs: |
The API name.
apiDefinitionId: commons.ApiDefinitionId
snippets: list<SnippetRegistryEntry>

get:
path: /get
docs: Get the endpoint's snippet template for a particular SDK.
display-name: Store snippets
method: POST
errors:
- commons.UnauthorizedError
- SnippetNotFound
request:
name: GetSnippetTemplate
body:
properties:
orgId:
type: commons.OrgId
docs: |
The organization to create snippets for.
apiId:
type: commons.ApiId
docs: |
The API name.
sdk: snippets.SDK
endpointId: snippets.EndpointIdentifier
response: EndpointSnippetTemplate

types:
# Internal Snippet structure
TemplateSentinel: literal<"$FERN_INPUT">

UnionTemplate:
properties:
templateString: string
members:
type: map<string, Template>
docs: A map of the union member's typeID to the template.
templateInput: optional<PayloadInput>
DiscriminatedUnionTemplate:
properties:
templateString: string
discriminantField: string
members:
type: map<string, Template>
docs: A map of the union member's discriminant to the template to use to create it
templateInput: optional<PayloadInput>
EnumTemplate:
properties:
templateString: optional<string>
values: map<string, string>
templateInput: optional<PayloadInput>
GenericTemplate:
properties:
templateString: string
templateInputs:
type: optional<list<TemplateInput>>
docs: An ordered list of inputs to the template.
inputDelimiter:
type: optional<string>
docs: In the event you have multiple template inputs, how do you concat them together
DictTemplate:
properties:
containerTemplateString:
type: string
docs: Commonly the braces of a container like `{ $FERN_INPUT }`, but may even be something like `new Dict( $FERN_INPUT )`
delimiter: string
keyTemplate: Template
valueTemplate: Template
keyValueSeparator: string
templateInput: optional<PayloadInput>
IterableTemplate:
properties:
containerTemplateString:
type: string
docs: Commonly the braces of a container like `[ $FERN_INPUT ]` for a list or `{ $FERN_INPUT }` for a set
delimiter: string
innerTemplate:
type: Template
docs: |
In the event of an array, the root template would be something like `[ fern!{{ child }} ]`
and so the child would be the actual object type seen in the example.
templateInput: optional<PayloadInput>
Template:
base-properties:
imports: optional<list<string>>
isOptional:
type: boolean
docs: |
We might not need this, but the idea here is to be able to omit if it's optional and undefined,
or default if omitted and required.
union:
generic: GenericTemplate
enum: EnumTemplate
discriminatedUnion: DiscriminatedUnionTemplate
union: UnionTemplate
dict: DictTemplate
iterable: IterableTemplate

TemplateInput:
union:
template: Template
payload: PayloadInput
PayloadLocation:
docs: |
The location of the payload, if omitted the full payload is used.
Note that RELATIVE should be used for iterables primarily, so be
able to specify the path to the field relative to the iterated on object
enum:
- BODY
- QUERY
- PATH
- HEADERS
- RELATIVE
PayloadInput:
properties:
location: PayloadLocation
path:
type: optional<string>
docs: Dot delimited path to the value within the payload, if omitted the full payload is used.

SnippetTemplate:
properties:
# TODO: Make clientInstantiation a Template
clientInstantiation: string
functionInvocation: Template
VersionedSnippetTemplate:
union:
v1: SnippetTemplate

SnippetRegistryEntry:
properties:
sdk: snippets.SDK
endpointId: snippets.EndpointIdentifier
snippetTemplate: VersionedSnippetTemplate

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

errors:
SnippetNotFound:
status-code: 404
docs: The requested snippet was not found
type: string
30 changes: 30 additions & 0 deletions fern/apis/fdr/generators.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,36 @@ groups:
outputEsm: true
extraDevDependencies:
"@types/mime": "3.0.4"

fdr-test:
generators:
- name: fernapi/fern-typescript-node-sdk
version: 0.12.8-rc0
output:
location: npm
url: npm.buildwithfern.com
package-name: "@fern-fern/fdr-test-sdk"
config:
noSerdeLayer: true
outputSourceFiles: true
neverThrowErrors: true
timeoutInSeconds: infinity
outputEsm: true
extraDevDependencies:
"@types/mime": "3.0.4"

sdk-generators:
generators:
- name: fernapi/fern-python-sdk
version: 1.1.0-rc4
output:
location: pypi
url: pypi.buildwithfern.com
package-name: "fern-fern-fdr-sdk"
config:
client:
class_name: FdrClient

fiddle:
audiences:
- fiddle
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 @@ -9,6 +9,7 @@ import urlJoin from "url-join";
import { Api } from "./api/resources/api/client/Client";
import { Docs } from "./api/resources/docs/client/Client";
import { SnippetsFactory } from "./api/resources/snippetsFactory/client/Client";
import { Template } from "./api/resources/template/client/Client";

export declare namespace FernRegistryClient {
interface Options {
Expand Down Expand Up @@ -165,6 +166,12 @@ export class FernRegistryClient {
return (this._snippetsFactory ??= new SnippetsFactory(this._options));
}

protected _template: Template | undefined;

public get template(): Template {
return (this._template ??= new Template(this._options));
}

protected async _getAuthorizationHeader() {
const bearer = await core.Supplier.get(this._options.token);
if (bearer != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,10 @@ export interface GetSnippetRequest {
*/
sdks?: FernRegistry.Sdk[];
endpoint: FernRegistry.EndpointIdentifier;
/**
* The JSON payload to be used as the input for the code snippet. This should just be thought of as the
* request body you'd be sending to the endpoint as a cURL. If not specified then the default payload will be used.
*
*/
payload?: FernRegistry.CustomSnippetPayload;
}
3 changes: 3 additions & 0 deletions packages/fdr-sdk/src/client/generated/api/resources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ export * as commons from "./commons";
export * from "./commons/types";
export * as snippetsFactory from "./snippetsFactory";
export * from "./snippetsFactory/types";
export * as template from "./template";
export * from "./template/types";
export * from "./snippetsFactory/client/requests";
export * from "./template/client/requests";
Loading

0 comments on commit 28071e5

Please sign in to comment.