From 1cb69a8ff0ea26f1d0c78c7e65b5f086a204115b Mon Sep 17 00:00:00 2001 From: Alex McKinney Date: Thu, 21 Nov 2024 19:34:21 -0500 Subject: [PATCH 1/2] feat(go): Add support for file upload dynamic snippets --- generators/go-v2/ast/package.json | 4 +- .../go-v2/ast/src/ast/TypeInstantiation.ts | 16 ++ .../go-v2/dynamic-snippets/package.json | 2 +- .../src/DynamicSnippetsGenerator.ts | 145 +++++++++++++++++- .../__snapshots__/file-upload.test.ts.snap | 82 ++++++++++ .../__test__/__snapshots__/ir.test.ts.snap | 12 +- .../src/__test__/file-upload.test.ts | 73 +++++++++ .../DynamicSnippetsGeneratorContext.ts | 121 ++++++++++++++- packages/cli/dynamic-snippets/package.json | 2 +- pnpm-lock.yaml | 18 +-- .../apis/examples/definition/.service.yml.swp | Bin 0 -> 12288 bytes 11 files changed, 443 insertions(+), 32 deletions(-) create mode 100644 generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/file-upload.test.ts.snap create mode 100644 generators/go-v2/dynamic-snippets/src/__test__/file-upload.test.ts create mode 100644 test-definitions/fern/apis/examples/definition/.service.yml.swp diff --git a/generators/go-v2/ast/package.json b/generators/go-v2/ast/package.json index c6b92142faa..1f5fb434e41 100644 --- a/generators/go-v2/ast/package.json +++ b/generators/go-v2/ast/package.json @@ -30,13 +30,13 @@ "@fern-api/core-utils": "workspace:*", "@fern-api/fs-utils": "workspace:*", "@fern-api/generator-commons": "workspace:*", - "@fern-fern/ir-sdk": "^53.19.0", + "@fern-fern/ir-sdk": "^53.21.0", "zod": "^3.22.3" }, "devDependencies": { "@fern-api/fs-utils": "workspace:*", "@fern-api/generator-commons": "workspace:*", - "@fern-fern/ir-sdk": "^53.19.0", + "@fern-fern/ir-sdk": "^53.21.0", "@types/jest": "^29.5.12", "@types/node": "^18.7.18", "depcheck": "^1.4.6", diff --git a/generators/go-v2/ast/src/ast/TypeInstantiation.ts b/generators/go-v2/ast/src/ast/TypeInstantiation.ts index 8b5ced513be..571802202b1 100644 --- a/generators/go-v2/ast/src/ast/TypeInstantiation.ts +++ b/generators/go-v2/ast/src/ast/TypeInstantiation.ts @@ -21,6 +21,7 @@ type InternalTypeInstantiation = | Nil | Nop | Optional + | Reference | Slice | String_ | Struct @@ -96,6 +97,11 @@ interface Nop { type: "nop"; } +interface Reference { + type: "reference"; + value: AstNode; +} + interface Slice { type: "slice"; valueType: Type; @@ -167,6 +173,9 @@ export class TypeInstantiation extends AstNode { case "optional": this.writeOptional({ writer, type: this.internalType.value }); break; + case "reference": + writer.writeNode(this.internalType.value); + break; case "slice": this.writeSlice({ writer, slice: this.internalType }); break; @@ -292,6 +301,13 @@ export class TypeInstantiation extends AstNode { }); } + public static reference(value: AstNode): TypeInstantiation { + return new this({ + type: "reference", + value + }); + } + public static slice({ valueType, values }: { valueType: Type; values: TypeInstantiation[] }): TypeInstantiation { return new this({ type: "slice", diff --git a/generators/go-v2/dynamic-snippets/package.json b/generators/go-v2/dynamic-snippets/package.json index fdb85f8553e..6404dd2b6ad 100644 --- a/generators/go-v2/dynamic-snippets/package.json +++ b/generators/go-v2/dynamic-snippets/package.json @@ -40,7 +40,7 @@ "@fern-api/project-loader": "workspace:*", "@fern-api/task-context": "workspace:*", "@fern-api/workspace-loader": "workspace:*", - "@fern-fern/ir-sdk": "^53.19.0", + "@fern-fern/ir-sdk": "^53.21.0", "@types/jest": "^29.5.12", "@types/node": "^18.7.18", "depcheck": "^1.4.6", diff --git a/generators/go-v2/dynamic-snippets/src/DynamicSnippetsGenerator.ts b/generators/go-v2/dynamic-snippets/src/DynamicSnippetsGenerator.ts index 7bb68816d9e..f0724a5a0f3 100644 --- a/generators/go-v2/dynamic-snippets/src/DynamicSnippetsGenerator.ts +++ b/generators/go-v2/dynamic-snippets/src/DynamicSnippetsGenerator.ts @@ -5,6 +5,8 @@ import { dynamic as DynamicSnippets } from "@fern-fern/ir-sdk/api"; import { AbstractDynamicSnippetsGenerator } from "@fern-api/dynamic-snippets"; import { ErrorReporter, Severity } from "./context/ErrorReporter"; import { Scope } from "./Scope"; +import { NameAndWireValue } from "@fern-api/ir-sdk"; +import { assertNever } from "@fern-api/core-utils"; const SNIPPET_PACKAGE_NAME = "example"; const SNIPPET_IMPORT_PATH = "fern"; @@ -384,10 +386,28 @@ export class DynamicSnippetsGenerator extends AbstractDynamicSnippetsGenerator field.value)); } - if (this.context.doesInlinedRequestExist({ request })) { + + if (!this.context.customConfig?.inlineFileProperties) { + args.push(...filePropertyFields.map((field) => field.value)); + } + + if (this.context.needsRequestParameter({ request })) { args.push( this.getInlinedRequestArg({ request, @@ -459,7 +479,7 @@ export class DynamicSnippetsGenerator extends AbstractDynamicSnippetsGenerator; + }): go.TypeInstantiation { + const fileValue = record[property.wireValue]; + if (fileValue == null) { + return go.TypeInstantiation.nop(); + } + if (typeof fileValue !== "string") { + this.context.errors.add({ + severity: Severity.Critical, + message: `Expected file value to be a string, got ${typeof fileValue}` + }); + return go.TypeInstantiation.nop(); + } + return go.TypeInstantiation.reference(this.context.getNewStringsReaderFunctionInvocation(fileValue as string)); + } + + private getArrayFileProperty({ + property, + record + }: { + property: DynamicSnippets.FileUploadRequestBodyProperty.FileArray; + record: Record; + }): go.TypeInstantiation { + const fileArrayValue = record[property.wireValue]; + if (fileArrayValue == null) { + return go.TypeInstantiation.nop(); + } + if (!Array.isArray(fileArrayValue)) { + this.context.errors.add({ + severity: Severity.Critical, + message: `Expected file array value to be an array of strings, got ${typeof fileArrayValue}` + }); + return go.TypeInstantiation.nop(); + } + const stringValues: string[] = []; + for (const value of fileArrayValue) { + if (typeof value !== "string") { + this.context.errors.add({ + severity: Severity.Critical, + message: `Expected file array value to be an array of strings, got ${typeof value}` + }); + } + stringValues.push(value as string); + } + return go.TypeInstantiation.slice({ + valueType: go.Type.reference(this.context.getIoReaderTypeReference()), + values: stringValues.map((value) => + go.TypeInstantiation.reference(this.context.getNewStringsReaderFunctionInvocation(value)) + ) + }); + } + + private getBodyProperty({ + property, + record + }: { + property: DynamicSnippets.NamedParameter; + record: Record; + }): go.TypeInstantiation { + const bodyPropertyValue = record[property.name.wireValue]; + if (bodyPropertyValue == null) { + return go.TypeInstantiation.nop(); + } + return this.context.dynamicTypeInstantiationMapper.convert({ + typeReference: property.typeReference, + value: bodyPropertyValue + }); + } + private getPathParameters({ namedParameters, snippet diff --git a/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/file-upload.test.ts.snap b/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/file-upload.test.ts.snap new file mode 100644 index 00000000000..80a23f3f535 --- /dev/null +++ b/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/file-upload.test.ts.snap @@ -0,0 +1,82 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`file-upload (success) > 'POST /' 1`] = ` +"package example + +import ( + context "context" + acme "github.com/acme/acme-go" + client "github.com/acme/acme-go/client" + io "io" + strings "strings" +) + +func do() { + client := client.NewClient() + client.Service.Post( + context.TODO(), + strings.NewReader( + "Hello, world!", + ), + []io.Reader{ + strings.NewReader( + "First", + ), + strings.NewReader( + "Second", + ), + }, + &acme.MyRequest{}, + ) +} +" +`; + +exports[`file-upload (success) > 'POST /just-file (simple)' 1`] = ` +"package example + +import ( + context "context" + client "github.com/acme/acme-go/client" + strings "strings" +) + +func do() { + client := client.NewClient() + client.Service.JustFile( + context.TODO(), + strings.NewReader( + "Hello, world!", + ), + ) +} +" +`; + +exports[`file-upload (success) > 'POST /just-file-with-query-params (si…' 1`] = ` +"package example + +import ( + context "context" + acme "github.com/acme/acme-go" + client "github.com/acme/acme-go/client" + strings "strings" +) + +func do() { + client := client.NewClient() + client.Service.JustFileWithQueryParams( + context.TODO(), + strings.NewReader( + "Hello, world!", + ), + &acme.JustFileWithQueryParamsRequet{ + Integer: 42, + MaybeString: acme.String( + "exists", + ), + }, + ) +} +" +`; diff --git a/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/ir.test.ts.snap b/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/ir.test.ts.snap index d9584bf6ab8..651d43138e0 100644 --- a/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/ir.test.ts.snap +++ b/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/ir.test.ts.snap @@ -4795,7 +4795,6 @@ package example import ( context "context" - acme "github.com/acme/acme-go" client "github.com/acme/acme-go/client" ) @@ -4804,7 +4803,6 @@ func do() { client.User.GetUser( context.TODO(), "userId", - &acme.GetUsersRequest{}, ) } @@ -4814,7 +4812,6 @@ package example import ( context "context" - acme "github.com/acme/acme-go" client "github.com/acme/acme-go/client" ) @@ -4824,7 +4821,6 @@ func do() { context.TODO(), "organizationId", "userId", - &acme.GetOrganizationUserRequest{}, ) } @@ -4834,20 +4830,14 @@ package example import ( context "context" - acme "github.com/acme/acme-go" client "github.com/acme/acme-go/client" ) func do() { client := client.NewClient() - client.User.SearchUsers( + client.User.GetUser( context.TODO(), "userId", - &acme.SearchUsersRequest{ - Limit: acme.Int( - 1, - ), - }, ) } diff --git a/generators/go-v2/dynamic-snippets/src/__test__/file-upload.test.ts b/generators/go-v2/dynamic-snippets/src/__test__/file-upload.test.ts new file mode 100644 index 00000000000..1e5fb31d1dc --- /dev/null +++ b/generators/go-v2/dynamic-snippets/src/__test__/file-upload.test.ts @@ -0,0 +1,73 @@ +import { buildDynamicSnippetsGenerator } from "./utils/buildDynamicSnippetsGenerator"; +import { join, RelativeFilePath } from "@fern-api/fs-utils"; +import { DYNAMIC_IR_TEST_DEFINITIONS_DIRECTORY } from "./utils/constant"; +import { buildGeneratorConfig } from "./utils/buildGeneratorConfig"; +import { TestCase } from "./utils/TestCase"; + +describe("file-upload (success)", () => { + const testCases: TestCase[] = [ + { + description: "POST /", + giveRequest: { + endpoint: { + method: "POST", + path: "/" + }, + auth: undefined, + pathParameters: undefined, + queryParameters: undefined, + headers: undefined, + requestBody: { + file: "Hello, world!", + fileList: ["First", "Second"] + } + } + }, + { + description: "POST /just-file (simple)", + giveRequest: { + endpoint: { + method: "POST", + path: "/just-file" + }, + auth: undefined, + pathParameters: undefined, + queryParameters: undefined, + headers: undefined, + requestBody: { + file: "Hello, world!" + } + } + }, + { + description: "POST /just-file-with-query-params (simple)", + giveRequest: { + endpoint: { + method: "POST", + path: "/just-file-with-query-params" + }, + auth: undefined, + pathParameters: undefined, + queryParameters: { + integer: 42, + maybeString: "exists" + }, + headers: undefined, + requestBody: { + file: "Hello, world!" + } + } + } + ]; + const generator = buildDynamicSnippetsGenerator({ + irFilepath: join(DYNAMIC_IR_TEST_DEFINITIONS_DIRECTORY, RelativeFilePath.of("file-upload.json")), + config: buildGeneratorConfig() + }); + test.each(testCases)("$description", async ({ giveRequest }) => { + const response = await generator.generate(giveRequest); + expect(response.snippet).toMatchSnapshot(); + + console.log(response.errors); + expect(response.errors).toBeUndefined(); + }); +}); diff --git a/generators/go-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts b/generators/go-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts index 4d744627a0c..5f813db81ce 100644 --- a/generators/go-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts +++ b/generators/go-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts @@ -1,3 +1,4 @@ +import { assertNever } from "@fern-api/core-utils"; import { FernGeneratorExec } from "@fern-api/generator-commons"; import { BaseGoCustomConfigSchema, resolveRootImportPath } from "@fern-api/go-ast"; import { FernFilepath, dynamic as DynamicSnippets, TypeId, Name } from "@fern-fern/ir-sdk/api"; @@ -107,11 +108,102 @@ export class DynamicSnippetsGeneratorContext { return instances; } - public doesInlinedRequestExist({ request }: { request: DynamicSnippets.InlinedRequest }): boolean { - // TODO: Reference the request wrapper's `includePathParameters` field. + public isFileUploadRequestBody( + body: DynamicSnippets.InlinedRequestBody + ): body is DynamicSnippets.InlinedRequestBody.FileUpload { + switch (body.type) { + case "fileUpload": + return true; + case "properties": + case "referenced": + return false; + default: + assertNever(body); + } + } + + public needsRequestParameter({ request }: { request: DynamicSnippets.InlinedRequest }): boolean { + if (this.includePathParametersInWrappedRequest({ request })) { + return true; + } + if (request.queryParameters != null && request.queryParameters.length > 0) { + return true; + } + if (request.headers != null && request.headers.length > 0) { + return true; + } + if (request.body != null) { + return this.includeRequestBodyInWrappedRequest({ body: request.body }); + } + if (request.metadata?.onlyPathParameters) { + return false; + } return true; } + private includePathParametersInWrappedRequest({ request }: { request: DynamicSnippets.InlinedRequest }): boolean { + return (this.customConfig?.inlinePathParameters ?? false) && (request.metadata?.includePathParameters ?? false); + } + + private includeRequestBodyInWrappedRequest({ body }: { body: DynamicSnippets.InlinedRequestBody }): boolean { + switch (body.type) { + case "properties": + case "referenced": + return true; + case "fileUpload": + return this.includeFileUploadBodyInWrappedRequest({ fileUpload: body }); + default: + assertNever(body); + } + } + + private includeFileUploadBodyInWrappedRequest({ + fileUpload + }: { + fileUpload: DynamicSnippets.FileUploadRequestBody; + }): boolean { + return ( + this.fileUploadHasBodyProperties({ fileUpload }) || + ((this.customConfig?.inlineFileProperties ?? false) && this.fileUploadHasFileProperties({ fileUpload })) + ); + } + + private fileUploadHasBodyProperties({ + fileUpload + }: { + fileUpload: DynamicSnippets.FileUploadRequestBody; + }): boolean { + return fileUpload.properties.some((property) => { + switch (property.type) { + case "file": + case "fileArray": + return false; + case "bodyProperty": + return true; + default: + assertNever(property); + } + }); + } + + private fileUploadHasFileProperties({ + fileUpload + }: { + fileUpload: DynamicSnippets.FileUploadRequestBody; + }): boolean { + return fileUpload.properties.some((property) => { + switch (property.type) { + case "file": + case "fileArray": + return true; + case "bodyProperty": + return false; + default: + assertNever(property); + } + }); + } + public getRecord(value: unknown): Record | undefined { if (typeof value !== "object" || Array.isArray(value)) { this.errors.add({ @@ -218,6 +310,23 @@ export class DynamicSnippetsGeneratorContext { }); } + public getIoReaderTypeReference(): go.TypeReference { + return go.typeReference({ + name: "Reader", + importPath: "io" + }); + } + + public getNewStringsReaderFunctionInvocation(s: string): go.FuncInvocation { + return go.invokeFunc({ + func: go.typeReference({ + name: "NewReader", + importPath: "strings" + }), + arguments_: [go.TypeInstantiation.string(s)] + }); + } + public getClientImportPath(): string { return path.join(this.rootImportPath, "client"); } @@ -258,6 +367,10 @@ export class DynamicSnippetsGeneratorContext { }); } + public newParameterNotRecognizedError(parameterName: string): Error { + return new Error(`"${parameterName}" is not a recognized parameter for this endpoint`); + } + private isListTypeReference(typeReference: DynamicSnippets.TypeReference): boolean { if (typeReference.type === "optional") { return this.isListTypeReference(typeReference.value); @@ -274,8 +387,4 @@ export class DynamicSnippetsGeneratorContext { }): boolean { return endpoint.location.method === parsedEndpoint.method && endpoint.location.path === parsedEndpoint.path; } - - private newParameterNotRecognizedError(parameterName: string): Error { - return new Error(`"${parameterName}" is not a recognized parameter for this endpoint`); - } } diff --git a/packages/cli/dynamic-snippets/package.json b/packages/cli/dynamic-snippets/package.json index 0593e517156..c6828ff337d 100644 --- a/packages/cli/dynamic-snippets/package.json +++ b/packages/cli/dynamic-snippets/package.json @@ -36,7 +36,7 @@ "@fern-api/project-loader": "workspace:*", "@fern-api/task-context": "workspace:*", "@fern-api/workspace-loader": "workspace:*", - "@fern-fern/ir-sdk": "^53.19.0", + "@fern-fern/ir-sdk": "^53.21.0", "@fern-fern/generator-exec-sdk": "^0.0.898", "url-join": "^5.0.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb5161cbb81..7d7fc82e2c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -397,8 +397,8 @@ importers: specifier: workspace:* version: link:../../commons '@fern-fern/ir-sdk': - specifier: ^53.19.0 - version: 53.19.0 + specifier: ^53.21.0 + version: 53.21.0 zod: specifier: ^3.22.3 version: 3.23.8 @@ -500,8 +500,8 @@ importers: specifier: workspace:* version: link:../../../packages/cli/workspace-loader '@fern-fern/ir-sdk': - specifier: ^53.19.0 - version: 53.19.0 + specifier: ^53.21.0 + version: 53.21.0 '@types/jest': specifier: ^29.5.12 version: 29.5.12 @@ -4500,8 +4500,8 @@ importers: specifier: ^0.0.898 version: 0.0.898 '@fern-fern/ir-sdk': - specifier: ^53.19.0 - version: 53.19.0 + specifier: ^53.21.0 + version: 53.21.0 url-join: specifier: ^5.0.0 version: 5.0.0 @@ -7634,8 +7634,8 @@ packages: '@fern-fern/ir-sdk@53.18.0': resolution: {integrity: sha512-KXHiAn8wjL9VIjjR9z8fXso0O2oaCMUSy9BSYRiGjEOmbIBUhplxSXjM3wSEXQ19hiPpsRYJTCCjnaZVP0OVrw==} - '@fern-fern/ir-sdk@53.19.0': - resolution: {integrity: sha512-mIi1S+fIc/+KnkvnFqJ+ZTXQkz4hdukkXSebx9VF9wRU78S4W1qEIX6Y7EqRz9/PFKrebe6SKXw+mn+hNqAWLA==} + '@fern-fern/ir-sdk@53.21.0': + resolution: {integrity: sha512-zZUoQ2zP9c6+4BUTZkkzVWhhmn56nnl1rG5I/SvEh2EUXAqPTktIXfFiSG84PYur6x42pG1L8Eu3Hxp3ls6luA==} '@fern-fern/ir-sdk@53.7.0': resolution: {integrity: sha512-PoCj8yOep3kFeDZYORAzqPwVtCSNmbT2SfR/AoxKCcikeZ5i+4Um4ZXx1e6UaAy7dIYF5kWeRc6lptFBRoj7Gw==} @@ -14701,7 +14701,7 @@ snapshots: '@fern-fern/ir-sdk@53.18.0': {} - '@fern-fern/ir-sdk@53.19.0': {} + '@fern-fern/ir-sdk@53.21.0': {} '@fern-fern/ir-sdk@53.7.0': {} diff --git a/test-definitions/fern/apis/examples/definition/.service.yml.swp b/test-definitions/fern/apis/examples/definition/.service.yml.swp new file mode 100644 index 0000000000000000000000000000000000000000..07f2f5e8b68e9f16be16aedf57b5772eadadacd1 GIT binary patch literal 12288 zcmeI2yK59d9LML<`G`hE8wDpCg3aDt6hYSqBp5=9BQa_aQDp9Ra<{lIcjsab(NyUy zY*bJy8ygEdA7Ei)C05#4q|v{?BDQ|_d6SFrz)txse6lz1-|w@t2S=t}ou97pljSPI zHN@D5rw5yRUws}pa=yfbBbVape%CnqMMh0DCVc;fF&p}2$8QK{!?3&Ygq4PG$;yHZ zz4VWgkuof~V0*T*eJ@IDMPNr2xg^}ckx`}FT#013Xg6fJ<8GXP!-7;n2FQSBV2~X< zI+ncZhYt<&J-aVyZS;{0kO4A42FL&zAOmE843L5U-GB;8Y#B)oWQm^0?xmi4R-_vl zAOmE843GgbKnBPF86X2>fDDiUGVl)?5Ef%2TNyjB4Z-98|M~C#pF0`*4!(h};3Iek zUV>-fK8V0oa0U#6U0`hoW1qlV@CZBvDfDDiU zGC&4&13bAx83j0(Dow6BfsD#?S()X{H`_SEnzv5a%}Gz$s*^PbLbXg@soPCM>h-Qv zE#ETv?97FWN!Lawg_6Z^lVua6tJHm~WAc$Sf|^vq5=xY3JgN060@dm`zif=pP8;(w zjBvWv Date: Thu, 21 Nov 2024 21:29:44 -0500 Subject: [PATCH 2/2] Refactor with FilePropertyMapper --- .../src/DynamicSnippetsGenerator.ts | 189 +++++------------- .../__snapshots__/file-upload.test.ts.snap | 36 ++-- .../__test__/__snapshots__/ir.test.ts.snap | 16 +- .../__test__/utils/buildGeneratorConfig.ts | 3 +- .../DynamicSnippetsGeneratorContext.ts | 5 +- .../src/context/FilePropertyMapper.ts | 131 ++++++++++++ .../test-definitions/path-parameters.json | 4 +- .../test-definitions/path-parameters.json | 12 +- .../__snapshots__/path-parameters.json | 8 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- seed/csharp-sdk/path-parameters/snippet.json | 4 +- .../MockServer/SearchOrganizationsTest.cs | 2 +- .../Unit/MockServer/SearchUsersTest.cs | 2 +- .../src/SeedPathParameters/User/UserClient.cs | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../resources/user/service/service.py | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../.mock/definition/user.yml | 4 +- .../dynamic-snippets/example4/snippet.go | 8 +- .../inline-path-parameters/snippet.json | 12 +- .../inline-path-parameters/user/client.go | 4 +- .../.mock/definition/user.yml | 4 +- .../dynamic-snippets/example1/snippet.go | 2 - .../dynamic-snippets/example2/snippet.go | 2 - .../dynamic-snippets/example4/snippet.go | 8 +- .../no-custom-config/snippet.json | 20 +- .../no-custom-config/user/client.go | 4 +- seed/go-sdk/seed.yml | 3 - .../path-parameters/.mock/definition/user.yml | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../resources/user/UserClient.java | 6 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../resources/user/UserService.java | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- seed/openapi/path-parameters/openapi.yml | 145 ++++++++++++++ .../path-parameters/.mock/definition/user.yml | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../path-parameters/src/User/UserClient.php | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- seed/postman/path-parameters/collection.json | 20 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../path-parameters/snippet-templates.json | 4 +- seed/python-sdk/path-parameters/snippet.json | 4 +- .../path-parameters/src/seed/user/client.py | 8 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../lib/fern_path_parameters/user/client.rb | 8 +- seed/ruby-sdk/path-parameters/snippet.json | 8 +- .../path-parameters/.mock/definition/user.yml | 4 +- .../api/resources/user/service/UserService.ts | 4 +- .../path-parameters/.mock/definition/user.yml | 4 +- seed/ts-sdk/path-parameters/README.md | 11 + .../path-parameters/snippet-templates.json | 4 +- seed/ts-sdk/path-parameters/snippet.json | 4 +- .../src/api/resources/user/client/Client.ts | 4 +- .../apis/path-parameters/definition/user.yml | 4 +- 60 files changed, 519 insertions(+), 290 deletions(-) create mode 100644 generators/go-v2/dynamic-snippets/src/context/FilePropertyMapper.ts create mode 100644 seed/openapi/path-parameters/openapi.yml diff --git a/generators/go-v2/dynamic-snippets/src/DynamicSnippetsGenerator.ts b/generators/go-v2/dynamic-snippets/src/DynamicSnippetsGenerator.ts index f0724a5a0f3..c9b6ac99df7 100644 --- a/generators/go-v2/dynamic-snippets/src/DynamicSnippetsGenerator.ts +++ b/generators/go-v2/dynamic-snippets/src/DynamicSnippetsGenerator.ts @@ -5,8 +5,8 @@ import { dynamic as DynamicSnippets } from "@fern-fern/ir-sdk/api"; import { AbstractDynamicSnippetsGenerator } from "@fern-api/dynamic-snippets"; import { ErrorReporter, Severity } from "./context/ErrorReporter"; import { Scope } from "./Scope"; -import { NameAndWireValue } from "@fern-api/ir-sdk"; import { assertNever } from "@fern-api/core-utils"; +import { FilePropertyInfo } from "./context/FilePropertyMapper"; const SNIPPET_PACKAGE_NAME = "example"; const SNIPPET_IMPORT_PATH = "fern"; @@ -387,24 +387,15 @@ export class DynamicSnippetsGenerator extends AbstractDynamicSnippetsGenerator field.value)); } if (!this.context.customConfig?.inlineFileProperties) { - args.push(...filePropertyFields.map((field) => field.value)); + args.push(...filePropertyInfo.fileFields.map((field) => field.value)); } if (this.context.needsRequestParameter({ request })) { @@ -412,21 +403,45 @@ export class DynamicSnippetsGenerator extends AbstractDynamicSnippetsGenerator; - }): go.TypeInstantiation { - const fileValue = record[property.wireValue]; - if (fileValue == null) { - return go.TypeInstantiation.nop(); - } - if (typeof fileValue !== "string") { - this.context.errors.add({ - severity: Severity.Critical, - message: `Expected file value to be a string, got ${typeof fileValue}` - }); - return go.TypeInstantiation.nop(); - } - return go.TypeInstantiation.reference(this.context.getNewStringsReaderFunctionInvocation(fileValue as string)); - } - - private getArrayFileProperty({ - property, - record - }: { - property: DynamicSnippets.FileUploadRequestBodyProperty.FileArray; - record: Record; - }): go.TypeInstantiation { - const fileArrayValue = record[property.wireValue]; - if (fileArrayValue == null) { - return go.TypeInstantiation.nop(); - } - if (!Array.isArray(fileArrayValue)) { - this.context.errors.add({ - severity: Severity.Critical, - message: `Expected file array value to be an array of strings, got ${typeof fileArrayValue}` - }); - return go.TypeInstantiation.nop(); - } - const stringValues: string[] = []; - for (const value of fileArrayValue) { - if (typeof value !== "string") { - this.context.errors.add({ - severity: Severity.Critical, - message: `Expected file array value to be an array of strings, got ${typeof value}` - }); - } - stringValues.push(value as string); - } - return go.TypeInstantiation.slice({ - valueType: go.Type.reference(this.context.getIoReaderTypeReference()), - values: stringValues.map((value) => - go.TypeInstantiation.reference(this.context.getNewStringsReaderFunctionInvocation(value)) - ) - }); - } - - private getBodyProperty({ - property, - record - }: { - property: DynamicSnippets.NamedParameter; - record: Record; - }): go.TypeInstantiation { - const bodyPropertyValue = record[property.name.wireValue]; - if (bodyPropertyValue == null) { - return go.TypeInstantiation.nop(); - } - return this.context.dynamicTypeInstantiationMapper.convert({ - typeReference: property.typeReference, - value: bodyPropertyValue - }); - } - private getPathParameters({ namedParameters, snippet diff --git a/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/file-upload.test.ts.snap b/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/file-upload.test.ts.snap index 80a23f3f535..652826835b7 100644 --- a/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/file-upload.test.ts.snap +++ b/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/file-upload.test.ts.snap @@ -15,18 +15,19 @@ func do() { client := client.NewClient() client.Service.Post( context.TODO(), - strings.NewReader( - "Hello, world!", - ), - []io.Reader{ - strings.NewReader( - "First", - ), - strings.NewReader( - "Second", + &acme.MyRequest{ + File: strings.NewReader( + "Hello, world!", ), + FileList: []io.Reader{ + strings.NewReader( + "First", + ), + strings.NewReader( + "Second", + ), + }, }, - &acme.MyRequest{}, ) } " @@ -37,6 +38,7 @@ exports[`file-upload (success) > 'POST /just-file (simple)' 1`] = ` import ( context "context" + acme "github.com/acme/acme-go" client "github.com/acme/acme-go/client" strings "strings" ) @@ -45,9 +47,11 @@ func do() { client := client.NewClient() client.Service.JustFile( context.TODO(), - strings.NewReader( - "Hello, world!", - ), + &acme.JustFileRequet{ + File: strings.NewReader( + "Hello, world!", + ), + }, ) } " @@ -67,14 +71,14 @@ func do() { client := client.NewClient() client.Service.JustFileWithQueryParams( context.TODO(), - strings.NewReader( - "Hello, world!", - ), &acme.JustFileWithQueryParamsRequet{ Integer: 42, MaybeString: acme.String( "exists", ), + File: strings.NewReader( + "Hello, world!", + ), }, ) } diff --git a/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/ir.test.ts.snap b/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/ir.test.ts.snap index 651d43138e0..fc03ccb2d4c 100644 --- a/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/ir.test.ts.snap +++ b/generators/go-v2/dynamic-snippets/src/__test__/__snapshots__/ir.test.ts.snap @@ -4830,14 +4830,20 @@ package example import ( context "context" + acme "github.com/acme/acme-go" client "github.com/acme/acme-go/client" ) func do() { client := client.NewClient() - client.User.GetUser( + client.User.SearchUsers( context.TODO(), "userId", + &acme.SearchUsersRequest{ + Limit: acme.Int( + 1, + ), + }, ) } @@ -4847,14 +4853,20 @@ package example import ( context "context" + acme "github.com/acme/acme-go" client "github.com/acme/acme-go/client" ) func do() { client := client.NewClient() - client.User.GetOrganization( + client.User.SearchOrganizations( context.TODO(), "organizationId", + &acme.SearchOrganizationsRequest{ + Limit: acme.Int( + 1, + ), + }, ) } " diff --git a/generators/go-v2/dynamic-snippets/src/__test__/utils/buildGeneratorConfig.ts b/generators/go-v2/dynamic-snippets/src/__test__/utils/buildGeneratorConfig.ts index e0f1fc6b420..4e45d7df40e 100644 --- a/generators/go-v2/dynamic-snippets/src/__test__/utils/buildGeneratorConfig.ts +++ b/generators/go-v2/dynamic-snippets/src/__test__/utils/buildGeneratorConfig.ts @@ -19,7 +19,8 @@ const DEFAULT_CONFIG: FernGeneratorExec.GeneratorConfig = { generateOauthClients: false, customConfig: { packageName: "acme", - union: "v1" + union: "v1", + inlineFileProperties: true } as BaseGoCustomConfigSchema }; diff --git a/generators/go-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts b/generators/go-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts index 5f813db81ce..4466c56503a 100644 --- a/generators/go-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts +++ b/generators/go-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts @@ -10,6 +10,7 @@ import { DynamicTypeInstantiationMapper } from "./DynamicTypeInstantiationMapper import { go } from "@fern-api/go-ast"; import path from "path"; import { ErrorReporter, Severity } from "./ErrorReporter"; +import { FilePropertyMapper } from "./FilePropertyMapper"; export class DynamicSnippetsGeneratorContext { public ir: DynamicSnippets.DynamicIntermediateRepresentation; @@ -18,6 +19,7 @@ export class DynamicSnippetsGeneratorContext { public errors: ErrorReporter; public dynamicTypeMapper: DynamicTypeMapper; public dynamicTypeInstantiationMapper: DynamicTypeInstantiationMapper; + public filePropertyMapper: FilePropertyMapper; public rootImportPath: string; private httpEndpointReferenceParser: HttpEndpointReferenceParser; @@ -35,6 +37,7 @@ export class DynamicSnippetsGeneratorContext { this.errors = new ErrorReporter(); this.dynamicTypeMapper = new DynamicTypeMapper({ context: this }); this.dynamicTypeInstantiationMapper = new DynamicTypeInstantiationMapper({ context: this }); + this.filePropertyMapper = new FilePropertyMapper({ context: this }); this.rootImportPath = resolveRootImportPath({ config, customConfig: this.customConfig }); this.httpEndpointReferenceParser = new HttpEndpointReferenceParser(); } @@ -141,7 +144,7 @@ export class DynamicSnippetsGeneratorContext { return true; } - private includePathParametersInWrappedRequest({ request }: { request: DynamicSnippets.InlinedRequest }): boolean { + public includePathParametersInWrappedRequest({ request }: { request: DynamicSnippets.InlinedRequest }): boolean { return (this.customConfig?.inlinePathParameters ?? false) && (request.metadata?.includePathParameters ?? false); } diff --git a/generators/go-v2/dynamic-snippets/src/context/FilePropertyMapper.ts b/generators/go-v2/dynamic-snippets/src/context/FilePropertyMapper.ts new file mode 100644 index 00000000000..19c9a6778ec --- /dev/null +++ b/generators/go-v2/dynamic-snippets/src/context/FilePropertyMapper.ts @@ -0,0 +1,131 @@ +import { go } from "@fern-api/go-ast"; +import { DynamicSnippetsGeneratorContext } from "./DynamicSnippetsGeneratorContext"; +import { dynamic as DynamicSnippets } from "@fern-fern/ir-sdk/api"; +import { assertNever } from "@fern-api/core-utils"; +import { Severity } from "./ErrorReporter"; + +export interface FilePropertyInfo { + fileFields: go.StructField[]; + bodyPropertyFields: go.StructField[]; +} + +export class FilePropertyMapper { + private context: DynamicSnippetsGeneratorContext; + + constructor({ context }: { context: DynamicSnippetsGeneratorContext }) { + this.context = context; + } + + public getFilePropertyInfo({ + body, + value + }: { + body: DynamicSnippets.FileUploadRequestBody; + value: unknown; + }): FilePropertyInfo { + const result: FilePropertyInfo = { + fileFields: [], + bodyPropertyFields: [] + }; + const record = this.context.getRecord(value) ?? {}; + for (const property of body.properties) { + switch (property.type) { + case "file": + result.fileFields.push({ + name: this.context.getTypeName(property.name), + value: this.getSingleFileProperty({ property, record }) + }); + break; + case "fileArray": + result.fileFields.push({ + name: this.context.getTypeName(property.name), + value: this.getArrayFileProperty({ property, record }) + }); + break; + case "bodyProperty": + result.bodyPropertyFields.push({ + name: this.context.getTypeName(property.name.name), + value: this.getBodyProperty({ property, record }) + }); + break; + default: + assertNever(property); + } + } + return result; + } + + private getSingleFileProperty({ + property, + record + }: { + property: DynamicSnippets.FileUploadRequestBodyProperty.File_; + record: Record; + }): go.TypeInstantiation { + const fileValue = record[property.wireValue]; + if (fileValue == null) { + return go.TypeInstantiation.nop(); + } + if (typeof fileValue !== "string") { + this.context.errors.add({ + severity: Severity.Critical, + message: `Expected file value to be a string, got ${typeof fileValue}` + }); + return go.TypeInstantiation.nop(); + } + return go.TypeInstantiation.reference(this.context.getNewStringsReaderFunctionInvocation(fileValue as string)); + } + + private getArrayFileProperty({ + property, + record + }: { + property: DynamicSnippets.FileUploadRequestBodyProperty.FileArray; + record: Record; + }): go.TypeInstantiation { + const fileArrayValue = record[property.wireValue]; + if (fileArrayValue == null) { + return go.TypeInstantiation.nop(); + } + if (!Array.isArray(fileArrayValue)) { + this.context.errors.add({ + severity: Severity.Critical, + message: `Expected file array value to be an array of strings, got ${typeof fileArrayValue}` + }); + return go.TypeInstantiation.nop(); + } + const stringValues: string[] = []; + for (const value of fileArrayValue) { + if (typeof value !== "string") { + this.context.errors.add({ + severity: Severity.Critical, + message: `Expected file array value to be an array of strings, got ${typeof value}` + }); + } + stringValues.push(value as string); + } + return go.TypeInstantiation.slice({ + valueType: go.Type.reference(this.context.getIoReaderTypeReference()), + values: stringValues.map((value) => + go.TypeInstantiation.reference(this.context.getNewStringsReaderFunctionInvocation(value)) + ) + }); + } + + private getBodyProperty({ + property, + record + }: { + property: DynamicSnippets.NamedParameter; + record: Record; + }): go.TypeInstantiation { + const bodyPropertyValue = record[property.name.wireValue]; + if (bodyPropertyValue == null) { + return go.TypeInstantiation.nop(); + } + return this.context.dynamicTypeInstantiationMapper.convert({ + typeReference: property.typeReference, + value: bodyPropertyValue + }); + } +} diff --git a/packages/cli/dynamic-snippets/src/__test__/test-definitions/path-parameters.json b/packages/cli/dynamic-snippets/src/__test__/test-definitions/path-parameters.json index 580fbf8a2b2..606bf47ac17 100644 --- a/packages/cli/dynamic-snippets/src/__test__/test-definitions/path-parameters.json +++ b/packages/cli/dynamic-snippets/src/__test__/test-definitions/path-parameters.json @@ -820,7 +820,7 @@ }, "location": { "method": "GET", - "path": "/user/users/{userId}" + "path": "/user/users/{userId}/search" }, "request": { "type": "inlined", @@ -1030,7 +1030,7 @@ }, "location": { "method": "GET", - "path": "/user/organizations/{organizationId}" + "path": "/user/organizations/{organizationId}/search" }, "request": { "type": "inlined", diff --git a/packages/cli/generation/ir-generator/src/__test__/test-definitions/path-parameters.json b/packages/cli/generation/ir-generator/src/__test__/test-definitions/path-parameters.json index 9573212c08c..7b18432a8eb 100644 --- a/packages/cli/generation/ir-generator/src/__test__/test-definitions/path-parameters.json +++ b/packages/cli/generation/ir-generator/src/__test__/test-definitions/path-parameters.json @@ -2456,7 +2456,7 @@ "parts": [ { "pathParameter": "userId", - "tail": "" + "tail": "/search" } ] }, @@ -2465,7 +2465,7 @@ "parts": [ { "pathParameter": "userId", - "tail": "" + "tail": "/search" } ] }, @@ -2746,7 +2746,7 @@ { "example": { "id": "77244d0cd8c4a7c57fd9c66c29faae4f7e9a17ec", - "url": "/user/users/userId", + "url": "/user/users/userId/search", "name": null, "endpointHeaders": [], "endpointPathParameters": [ @@ -3572,7 +3572,7 @@ "parts": [ { "pathParameter": "organizationId", - "tail": "" + "tail": "/search" } ] }, @@ -3581,7 +3581,7 @@ "parts": [ { "pathParameter": "organizationId", - "tail": "" + "tail": "/search" } ] }, @@ -3862,7 +3862,7 @@ { "example": { "id": "3dc2b2510dc46c91f013274ac3b8e78d9e58bf16", - "url": "/user/organizations/organizationId", + "url": "/user/organizations/organizationId/search", "name": null, "endpointHeaders": [], "endpointPathParameters": [ diff --git a/packages/cli/register/src/ir-to-fdr-converter/__test__/__snapshots__/path-parameters.json b/packages/cli/register/src/ir-to-fdr-converter/__test__/__snapshots__/path-parameters.json index 84b03646867..7d2298cf924 100644 --- a/packages/cli/register/src/ir-to-fdr-converter/__test__/__snapshots__/path-parameters.json +++ b/packages/cli/register/src/ir-to-fdr-converter/__test__/__snapshots__/path-parameters.json @@ -360,7 +360,7 @@ }, { "type": "literal", - "value": "" + "value": "/search" } ] }, @@ -394,7 +394,7 @@ "errorsV2": [], "examples": [ { - "path": "/user/users/userId", + "path": "/user/users/userId/search", "pathParameters": { "userId": "userId" }, @@ -473,7 +473,7 @@ }, { "type": "literal", - "value": "" + "value": "/search" } ] }, @@ -507,7 +507,7 @@ "errorsV2": [], "examples": [ { - "path": "/user/organizations/organizationId", + "path": "/user/organizations/organizationId/search", "pathParameters": { "organizationId": "organizationId" }, diff --git a/seed/csharp-model/path-parameters/.mock/definition/user.yml b/seed/csharp-model/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/csharp-model/path-parameters/.mock/definition/user.yml +++ b/seed/csharp-model/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/csharp-sdk/path-parameters/.mock/definition/user.yml b/seed/csharp-sdk/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/csharp-sdk/path-parameters/.mock/definition/user.yml +++ b/seed/csharp-sdk/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/csharp-sdk/path-parameters/snippet.json b/seed/csharp-sdk/path-parameters/snippet.json index 663cc6e1abd..a6971ff951e 100644 --- a/seed/csharp-sdk/path-parameters/snippet.json +++ b/seed/csharp-sdk/path-parameters/snippet.json @@ -40,7 +40,7 @@ { "example_identifier": null, "id": { - "path": "/user/users/{userId}", + "path": "/user/users/{userId}/search", "method": "GET", "identifier_override": "endpoint_user.searchUsers" }, @@ -52,7 +52,7 @@ { "example_identifier": null, "id": { - "path": "/user/organizations/{organizationId}", + "path": "/user/organizations/{organizationId}/search", "method": "GET", "identifier_override": "endpoint_user.searchOrganizations" }, diff --git a/seed/csharp-sdk/path-parameters/src/SeedPathParameters.Test/Unit/MockServer/SearchOrganizationsTest.cs b/seed/csharp-sdk/path-parameters/src/SeedPathParameters.Test/Unit/MockServer/SearchOrganizationsTest.cs index 8486107bfbe..4ec29064715 100644 --- a/seed/csharp-sdk/path-parameters/src/SeedPathParameters.Test/Unit/MockServer/SearchOrganizationsTest.cs +++ b/seed/csharp-sdk/path-parameters/src/SeedPathParameters.Test/Unit/MockServer/SearchOrganizationsTest.cs @@ -38,7 +38,7 @@ public async Task MockServerTest() .Given( WireMock .RequestBuilders.Request.Create() - .WithPath("/user/organizations/organizationId") + .WithPath("/user/organizations/organizationId/search") .WithParam("limit", "1") .UsingGet() ) diff --git a/seed/csharp-sdk/path-parameters/src/SeedPathParameters.Test/Unit/MockServer/SearchUsersTest.cs b/seed/csharp-sdk/path-parameters/src/SeedPathParameters.Test/Unit/MockServer/SearchUsersTest.cs index d3b56708635..69c8920d768 100644 --- a/seed/csharp-sdk/path-parameters/src/SeedPathParameters.Test/Unit/MockServer/SearchUsersTest.cs +++ b/seed/csharp-sdk/path-parameters/src/SeedPathParameters.Test/Unit/MockServer/SearchUsersTest.cs @@ -38,7 +38,7 @@ public async Task MockServerTest() .Given( WireMock .RequestBuilders.Request.Create() - .WithPath("/user/users/userId") + .WithPath("/user/users/userId/search") .WithParam("limit", "1") .UsingGet() ) diff --git a/seed/csharp-sdk/path-parameters/src/SeedPathParameters/User/UserClient.cs b/seed/csharp-sdk/path-parameters/src/SeedPathParameters/User/UserClient.cs index 5d2c2e7b5a1..215fbf2b4a8 100644 --- a/seed/csharp-sdk/path-parameters/src/SeedPathParameters/User/UserClient.cs +++ b/seed/csharp-sdk/path-parameters/src/SeedPathParameters/User/UserClient.cs @@ -168,7 +168,7 @@ public async Task> SearchUsersAsync( { BaseUrl = _client.Options.BaseUrl, Method = HttpMethod.Get, - Path = $"/user/users/{userId}", + Path = $"/user/users/{userId}/search", Query = _query, Options = options, }, @@ -219,7 +219,7 @@ public async Task> SearchOrganizationsAsync( { BaseUrl = _client.Options.BaseUrl, Method = HttpMethod.Get, - Path = $"/user/organizations/{organizationId}", + Path = $"/user/organizations/{organizationId}/search", Query = _query, Options = options, }, diff --git a/seed/fastapi/path-parameters/.mock/definition/user.yml b/seed/fastapi/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/fastapi/path-parameters/.mock/definition/user.yml +++ b/seed/fastapi/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/fastapi/path-parameters/resources/user/service/service.py b/seed/fastapi/path-parameters/resources/user/service/service.py index 55843ef9cb5..07560dbdcb0 100644 --- a/seed/fastapi/path-parameters/resources/user/service/service.py +++ b/seed/fastapi/path-parameters/resources/user/service/service.py @@ -222,7 +222,7 @@ def wrapper(*args: typing.Any, **kwargs: typing.Any) -> typing.Sequence[User]: wrapper.__globals__.update(cls.search_users.__globals__) router.get( - path="/user/users/{user_id}", + path="/user/users/{user_id}/search", response_model=typing.Sequence[User], description=AbstractUserService.search_users.__doc__, **get_route_args(cls.search_users, default_tag="user"), @@ -270,7 +270,7 @@ def wrapper( wrapper.__globals__.update(cls.search_organizations.__globals__) router.get( - path="/user/organizations/{organization_id}", + path="/user/organizations/{organization_id}/search", response_model=typing.Sequence[Organization], description=AbstractUserService.search_organizations.__doc__, **get_route_args(cls.search_organizations, default_tag="user"), diff --git a/seed/go-fiber/path-parameters/.mock/definition/user.yml b/seed/go-fiber/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/go-fiber/path-parameters/.mock/definition/user.yml +++ b/seed/go-fiber/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/go-model/path-parameters/.mock/definition/user.yml b/seed/go-model/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/go-model/path-parameters/.mock/definition/user.yml +++ b/seed/go-model/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/go-sdk/path-parameters/inline-path-parameters/.mock/definition/user.yml b/seed/go-sdk/path-parameters/inline-path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/go-sdk/path-parameters/inline-path-parameters/.mock/definition/user.yml +++ b/seed/go-sdk/path-parameters/inline-path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/go-sdk/path-parameters/inline-path-parameters/dynamic-snippets/example4/snippet.go b/seed/go-sdk/path-parameters/inline-path-parameters/dynamic-snippets/example4/snippet.go index bf408811166..f95903e3bff 100644 --- a/seed/go-sdk/path-parameters/inline-path-parameters/dynamic-snippets/example4/snippet.go +++ b/seed/go-sdk/path-parameters/inline-path-parameters/dynamic-snippets/example4/snippet.go @@ -3,12 +3,18 @@ package example import ( client "github.com/fern-api/path-parameters-go/client" context "context" + path "github.com/fern-api/path-parameters-go" ) func do() () { client := client.NewClient() - client.User.GetOrganization( + client.User.SearchOrganizations( context.TODO(), "organizationId", + &path.SearchOrganizationsRequest{ + Limit: path.Int( + 1, + ), + }, ) } diff --git a/seed/go-sdk/path-parameters/inline-path-parameters/snippet.json b/seed/go-sdk/path-parameters/inline-path-parameters/snippet.json index de66dc22911..f99f2701706 100644 --- a/seed/go-sdk/path-parameters/inline-path-parameters/snippet.json +++ b/seed/go-sdk/path-parameters/inline-path-parameters/snippet.json @@ -4,22 +4,22 @@ "id": { "path": "/user/organizations/{organizationId}", "method": "GET", - "identifier_override": "endpoint_user.searchOrganizations" + "identifier_override": "endpoint_user.getOrganization" }, "snippet": { "type": "go", - "client": "import (\n\tcontext \"context\"\n\tpathparametersgo \"github.com/fern-api/path-parameters-go\"\n\tpathparametersgoclient \"github.com/fern-api/path-parameters-go/client\"\n)\n\nclient := pathparametersgoclient.NewClient()\nresponse, err := client.User.SearchOrganizations(\n\tcontext.TODO(),\n\t\"organizationId\",\n\t\u0026pathparametersgo.SearchOrganizationsRequest{\n\t\tLimit: pathparametersgo.Int(\n\t\t\t1,\n\t\t),\n\t},\n)\n" + "client": "import (\n\tcontext \"context\"\n\tpathparametersgoclient \"github.com/fern-api/path-parameters-go/client\"\n)\n\nclient := pathparametersgoclient.NewClient()\nresponse, err := client.User.GetOrganization(\n\tcontext.TODO(),\n\t\"organizationId\",\n)\n" } }, { "id": { - "path": "/user/organizations/{organizationId}", + "path": "/user/organizations/{organizationId}/search", "method": "GET", - "identifier_override": "endpoint_user.getOrganization" + "identifier_override": "endpoint_user.searchOrganizations" }, "snippet": { "type": "go", - "client": "import (\n\tcontext \"context\"\n\tpathparametersgoclient \"github.com/fern-api/path-parameters-go/client\"\n)\n\nclient := pathparametersgoclient.NewClient()\nresponse, err := client.User.GetOrganization(\n\tcontext.TODO(),\n\t\"organizationId\",\n)\n" + "client": "import (\n\tcontext \"context\"\n\tpathparametersgo \"github.com/fern-api/path-parameters-go\"\n\tpathparametersgoclient \"github.com/fern-api/path-parameters-go/client\"\n)\n\nclient := pathparametersgoclient.NewClient()\nresponse, err := client.User.SearchOrganizations(\n\tcontext.TODO(),\n\t\"organizationId\",\n\t\u0026pathparametersgo.SearchOrganizationsRequest{\n\t\tLimit: pathparametersgo.Int(\n\t\t\t1,\n\t\t),\n\t},\n)\n" } }, { @@ -46,7 +46,7 @@ }, { "id": { - "path": "/user/users/{userId}", + "path": "/user/users/{userId}/search", "method": "GET", "identifier_override": "endpoint_user.searchUsers" }, diff --git a/seed/go-sdk/path-parameters/inline-path-parameters/user/client.go b/seed/go-sdk/path-parameters/inline-path-parameters/user/client.go index e0159de6cde..3b8303f3719 100644 --- a/seed/go-sdk/path-parameters/inline-path-parameters/user/client.go +++ b/seed/go-sdk/path-parameters/inline-path-parameters/user/client.go @@ -161,7 +161,7 @@ func (c *Client) SearchUsers( "", ) endpointURL := internal.EncodeURL( - baseURL+"/user/users/%v", + baseURL+"/user/users/%v/search", request.UserId, ) queryParams, err := internal.QueryValues(request) @@ -208,7 +208,7 @@ func (c *Client) SearchOrganizations( "", ) endpointURL := internal.EncodeURL( - baseURL+"/user/organizations/%v", + baseURL+"/user/organizations/%v/search", organizationId, ) queryParams, err := internal.QueryValues(request) diff --git a/seed/go-sdk/path-parameters/no-custom-config/.mock/definition/user.yml b/seed/go-sdk/path-parameters/no-custom-config/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/go-sdk/path-parameters/no-custom-config/.mock/definition/user.yml +++ b/seed/go-sdk/path-parameters/no-custom-config/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example1/snippet.go b/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example1/snippet.go index f6c39cf8fb7..8e07d1d6df8 100644 --- a/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example1/snippet.go +++ b/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example1/snippet.go @@ -3,7 +3,6 @@ package example import ( client "github.com/path-parameters/fern/client" context "context" - fern "github.com/path-parameters/fern" ) func do() () { @@ -11,6 +10,5 @@ func do() () { client.User.GetUser( context.TODO(), "userId", - &fern.GetUsersRequest{}, ) } diff --git a/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example2/snippet.go b/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example2/snippet.go index b459f85c6d3..173596095ca 100644 --- a/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example2/snippet.go +++ b/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example2/snippet.go @@ -3,7 +3,6 @@ package example import ( client "github.com/path-parameters/fern/client" context "context" - fern "github.com/path-parameters/fern" ) func do() () { @@ -12,6 +11,5 @@ func do() () { context.TODO(), "organizationId", "userId", - &fern.GetOrganizationUserRequest{}, ) } diff --git a/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example4/snippet.go b/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example4/snippet.go index e0494a50f95..79a92c23b7d 100644 --- a/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example4/snippet.go +++ b/seed/go-sdk/path-parameters/no-custom-config/dynamic-snippets/example4/snippet.go @@ -3,12 +3,18 @@ package example import ( client "github.com/path-parameters/fern/client" context "context" + fern "github.com/path-parameters/fern" ) func do() () { client := client.NewClient() - client.User.GetOrganization( + client.User.SearchOrganizations( context.TODO(), "organizationId", + &fern.SearchOrganizationsRequest{ + Limit: fern.Int( + 1, + ), + }, ) } diff --git a/seed/go-sdk/path-parameters/no-custom-config/snippet.json b/seed/go-sdk/path-parameters/no-custom-config/snippet.json index d1bd48b1953..0b13e134062 100644 --- a/seed/go-sdk/path-parameters/no-custom-config/snippet.json +++ b/seed/go-sdk/path-parameters/no-custom-config/snippet.json @@ -4,22 +4,22 @@ "id": { "path": "/user/organizations/{organizationId}", "method": "GET", - "identifier_override": "endpoint_user.searchOrganizations" + "identifier_override": "endpoint_user.getOrganization" }, "snippet": { "type": "go", - "client": "import (\n\tcontext \"context\"\n\tfern \"github.com/path-parameters/fern\"\n\tfernclient \"github.com/path-parameters/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.User.SearchOrganizations(\n\tcontext.TODO(),\n\t\"organizationId\",\n\t\u0026fern.SearchOrganizationsRequest{\n\t\tLimit: fern.Int(\n\t\t\t1,\n\t\t),\n\t},\n)\n" + "client": "import (\n\tcontext \"context\"\n\tfernclient \"github.com/path-parameters/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.User.GetOrganization(\n\tcontext.TODO(),\n\t\"organizationId\",\n)\n" } }, { "id": { - "path": "/user/organizations/{organizationId}", + "path": "/user/organizations/{organizationId}/search", "method": "GET", - "identifier_override": "endpoint_user.getOrganization" + "identifier_override": "endpoint_user.searchOrganizations" }, "snippet": { "type": "go", - "client": "import (\n\tcontext \"context\"\n\tfernclient \"github.com/path-parameters/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.User.GetOrganization(\n\tcontext.TODO(),\n\t\"organizationId\",\n)\n" + "client": "import (\n\tcontext \"context\"\n\tfern \"github.com/path-parameters/fern\"\n\tfernclient \"github.com/path-parameters/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.User.SearchOrganizations(\n\tcontext.TODO(),\n\t\"organizationId\",\n\t\u0026fern.SearchOrganizationsRequest{\n\t\tLimit: fern.Int(\n\t\t\t1,\n\t\t),\n\t},\n)\n" } }, { @@ -37,22 +37,22 @@ "id": { "path": "/user/users/{userId}", "method": "GET", - "identifier_override": "endpoint_user.searchUsers" + "identifier_override": "endpoint_user.getUser" }, "snippet": { "type": "go", - "client": "import (\n\tcontext \"context\"\n\tfern \"github.com/path-parameters/fern\"\n\tfernclient \"github.com/path-parameters/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.User.SearchUsers(\n\tcontext.TODO(),\n\t\"userId\",\n\t\u0026fern.SearchUsersRequest{\n\t\tLimit: fern.Int(\n\t\t\t1,\n\t\t),\n\t},\n)\n" + "client": "import (\n\tcontext \"context\"\n\tfernclient \"github.com/path-parameters/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.User.GetUser(\n\tcontext.TODO(),\n\t\"userId\",\n)\n" } }, { "id": { - "path": "/user/users/{userId}", + "path": "/user/users/{userId}/search", "method": "GET", - "identifier_override": "endpoint_user.getUser" + "identifier_override": "endpoint_user.searchUsers" }, "snippet": { "type": "go", - "client": "import (\n\tcontext \"context\"\n\tfernclient \"github.com/path-parameters/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.User.GetUser(\n\tcontext.TODO(),\n\t\"userId\",\n)\n" + "client": "import (\n\tcontext \"context\"\n\tfern \"github.com/path-parameters/fern\"\n\tfernclient \"github.com/path-parameters/fern/client\"\n)\n\nclient := fernclient.NewClient()\nresponse, err := client.User.SearchUsers(\n\tcontext.TODO(),\n\t\"userId\",\n\t\u0026fern.SearchUsersRequest{\n\t\tLimit: fern.Int(\n\t\t\t1,\n\t\t),\n\t},\n)\n" } } ] diff --git a/seed/go-sdk/path-parameters/no-custom-config/user/client.go b/seed/go-sdk/path-parameters/no-custom-config/user/client.go index e420e4852bb..d6c8bfa8319 100644 --- a/seed/go-sdk/path-parameters/no-custom-config/user/client.go +++ b/seed/go-sdk/path-parameters/no-custom-config/user/client.go @@ -163,7 +163,7 @@ func (c *Client) SearchUsers( "", ) endpointURL := internal.EncodeURL( - baseURL+"/user/users/%v", + baseURL+"/user/users/%v/search", userId, ) queryParams, err := internal.QueryValues(request) @@ -210,7 +210,7 @@ func (c *Client) SearchOrganizations( "", ) endpointURL := internal.EncodeURL( - baseURL+"/user/organizations/%v", + baseURL+"/user/organizations/%v/search", organizationId, ) queryParams, err := internal.QueryValues(request) diff --git a/seed/go-sdk/seed.yml b/seed/go-sdk/seed.yml index da7fd460886..1390ba06aab 100644 --- a/seed/go-sdk/seed.yml +++ b/seed/go-sdk/seed.yml @@ -101,6 +101,3 @@ allowedFailures: - server-sent-events - streaming-parameter - trace - - # TODO: Update DynamicSnippetsGenerator to recognize InlinedRequestMetadata. - - path-parameters:no-custom-config diff --git a/seed/java-model/path-parameters/.mock/definition/user.yml b/seed/java-model/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/java-model/path-parameters/.mock/definition/user.yml +++ b/seed/java-model/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/java-sdk/path-parameters/.mock/definition/user.yml b/seed/java-sdk/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/java-sdk/path-parameters/.mock/definition/user.yml +++ b/seed/java-sdk/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/java-sdk/path-parameters/src/main/java/com/seed/pathParameters/resources/user/UserClient.java b/seed/java-sdk/path-parameters/src/main/java/com/seed/pathParameters/resources/user/UserClient.java index cf6ba0a18bd..dafc37325a2 100644 --- a/seed/java-sdk/path-parameters/src/main/java/com/seed/pathParameters/resources/user/UserClient.java +++ b/seed/java-sdk/path-parameters/src/main/java/com/seed/pathParameters/resources/user/UserClient.java @@ -164,7 +164,8 @@ public List searchUsers(String userId, SearchUsersRequest request, Request .newBuilder() .addPathSegments("user") .addPathSegments("users") - .addPathSegment(userId); + .addPathSegment(userId) + .addPathSegments("search"); if (request.getLimit().isPresent()) { httpUrl.addQueryParameter("limit", request.getLimit().get().toString()); } @@ -208,7 +209,8 @@ public List searchOrganizations( .newBuilder() .addPathSegments("user") .addPathSegments("organizations") - .addPathSegment(organizationId); + .addPathSegment(organizationId) + .addPathSegments("search"); if (request.getLimit().isPresent()) { httpUrl.addQueryParameter("limit", request.getLimit().get().toString()); } diff --git a/seed/java-spring/path-parameters/.mock/definition/user.yml b/seed/java-spring/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/java-spring/path-parameters/.mock/definition/user.yml +++ b/seed/java-spring/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/java-spring/path-parameters/resources/user/UserService.java b/seed/java-spring/path-parameters/resources/user/UserService.java index 72822cda809..b059c262dff 100644 --- a/seed/java-spring/path-parameters/resources/user/UserService.java +++ b/seed/java-spring/path-parameters/resources/user/UserService.java @@ -39,14 +39,14 @@ User getOrganizationUser(@PathVariable("organizationId") String organizationId, @PathVariable("userId") String userId); @GetMapping( - value = "/users/{userId}", + value = "/users/{userId}/search", produces = "application/json" ) List searchUsers(@PathVariable("userId") String userId, @RequestParam("limit") Optional limit); @GetMapping( - value = "/organizations/{organizationId}", + value = "/organizations/{organizationId}/search", produces = "application/json" ) List searchOrganizations(@PathVariable("organizationId") String organizationId, diff --git a/seed/openapi/path-parameters/.mock/definition/user.yml b/seed/openapi/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/openapi/path-parameters/.mock/definition/user.yml +++ b/seed/openapi/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/openapi/path-parameters/openapi.yml b/seed/openapi/path-parameters/openapi.yml new file mode 100644 index 00000000000..79ed4147981 --- /dev/null +++ b/seed/openapi/path-parameters/openapi.yml @@ -0,0 +1,145 @@ +openapi: 3.0.1 +info: + title: path-parameters + version: '' +paths: + /user/organizations/{organizationId}: + get: + operationId: user_getOrganization + tags: + - User + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/Organization' + /user/users/{userId}: + get: + operationId: user_getUser + tags: + - User + parameters: + - name: userId + in: path + required: true + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/User' + /user/organizations/{organizationId}/users/{userId}: + get: + operationId: user_getOrganizationUser + tags: + - User + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + - name: userId + in: path + required: true + schema: + type: string + responses: + '200': + description: '' + content: + application/json: + schema: + $ref: '#/components/schemas/User' + /user/users/{userId}/search: + get: + operationId: user_searchUsers + tags: + - User + parameters: + - name: userId + in: path + required: true + schema: + type: string + - name: limit + in: query + required: false + schema: + type: integer + nullable: true + responses: + '200': + description: '' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + /user/organizations/{organizationId}/search: + get: + operationId: user_searchOrganizations + tags: + - User + parameters: + - name: organizationId + in: path + required: true + schema: + type: string + - name: limit + in: query + required: false + schema: + type: integer + nullable: true + responses: + '200': + description: '' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Organization' +components: + schemas: + Organization: + title: Organization + type: object + properties: + name: + type: string + tags: + type: array + items: + type: string + required: + - name + - tags + User: + title: User + type: object + properties: + name: + type: string + tags: + type: array + items: + type: string + required: + - name + - tags + securitySchemes: {} diff --git a/seed/php-model/path-parameters/.mock/definition/user.yml b/seed/php-model/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/php-model/path-parameters/.mock/definition/user.yml +++ b/seed/php-model/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/php-sdk/path-parameters/.mock/definition/user.yml b/seed/php-sdk/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/php-sdk/path-parameters/.mock/definition/user.yml +++ b/seed/php-sdk/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/php-sdk/path-parameters/src/User/UserClient.php b/seed/php-sdk/path-parameters/src/User/UserClient.php index 54e23c6c291..2c507f755cd 100644 --- a/seed/php-sdk/path-parameters/src/User/UserClient.php +++ b/seed/php-sdk/path-parameters/src/User/UserClient.php @@ -164,7 +164,7 @@ public function searchUsers(string $userId, SearchUsersRequest $request, ?array $response = $this->client->sendRequest( new JsonApiRequest( baseUrl: $options['baseUrl'] ?? $this->client->options['baseUrl'] ?? '', - path: "/user/users/$userId", + path: "/user/users/$userId/search", method: HttpMethod::GET, query: $query, ), @@ -206,7 +206,7 @@ public function searchOrganizations(string $organizationId, SearchOrganizationsR $response = $this->client->sendRequest( new JsonApiRequest( baseUrl: $options['baseUrl'] ?? $this->client->options['baseUrl'] ?? '', - path: "/user/organizations/$organizationId", + path: "/user/organizations/$organizationId/search", method: HttpMethod::GET, query: $query, ), diff --git a/seed/postman/path-parameters/.mock/definition/user.yml b/seed/postman/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/postman/path-parameters/.mock/definition/user.yml +++ b/seed/postman/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/postman/path-parameters/collection.json b/seed/postman/path-parameters/collection.json index 124d922771c..70423c0c08b 100644 --- a/seed/postman/path-parameters/collection.json +++ b/seed/postman/path-parameters/collection.json @@ -272,14 +272,15 @@ "request": { "description": null, "url": { - "raw": "{{baseUrl}}/user/users/:userId?limit=1", + "raw": "{{baseUrl}}/user/users/:userId/search?limit=1", "host": [ "{{baseUrl}}" ], "path": [ "user", "users", - ":userId" + ":userId", + "search" ], "query": [ { @@ -315,14 +316,15 @@ "originalRequest": { "description": null, "url": { - "raw": "{{baseUrl}}/user/users/:userId?limit=1", + "raw": "{{baseUrl}}/user/users/:userId/search?limit=1", "host": [ "{{baseUrl}}" ], "path": [ "user", "users", - ":userId" + ":userId", + "search" ], "query": [ { @@ -362,14 +364,15 @@ "request": { "description": null, "url": { - "raw": "{{baseUrl}}/user/organizations/:organizationId?limit=1", + "raw": "{{baseUrl}}/user/organizations/:organizationId/search?limit=1", "host": [ "{{baseUrl}}" ], "path": [ "user", "organizations", - ":organizationId" + ":organizationId", + "search" ], "query": [ { @@ -405,14 +408,15 @@ "originalRequest": { "description": null, "url": { - "raw": "{{baseUrl}}/user/organizations/:organizationId?limit=1", + "raw": "{{baseUrl}}/user/organizations/:organizationId/search?limit=1", "host": [ "{{baseUrl}}" ], "path": [ "user", "organizations", - ":organizationId" + ":organizationId", + "search" ], "query": [ { diff --git a/seed/pydantic-v2/path-parameters/.mock/definition/user.yml b/seed/pydantic-v2/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/pydantic-v2/path-parameters/.mock/definition/user.yml +++ b/seed/pydantic-v2/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/pydantic/path-parameters/.mock/definition/user.yml b/seed/pydantic/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/pydantic/path-parameters/.mock/definition/user.yml +++ b/seed/pydantic/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/python-sdk/path-parameters/.mock/definition/user.yml b/seed/python-sdk/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/python-sdk/path-parameters/.mock/definition/user.yml +++ b/seed/python-sdk/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/python-sdk/path-parameters/snippet-templates.json b/seed/python-sdk/path-parameters/snippet-templates.json index 50c0f0ce716..308c6ef4915 100644 --- a/seed/python-sdk/path-parameters/snippet-templates.json +++ b/seed/python-sdk/path-parameters/snippet-templates.json @@ -308,7 +308,7 @@ "type": "python" }, "endpointId": { - "path": "/user/users/{userId}", + "path": "/user/users/{userId}/search", "method": "GET", "identifierOverride": "endpoint_user.searchUsers" }, @@ -430,7 +430,7 @@ "type": "python" }, "endpointId": { - "path": "/user/organizations/{organizationId}", + "path": "/user/organizations/{organizationId}/search", "method": "GET", "identifierOverride": "endpoint_user.searchOrganizations" }, diff --git a/seed/python-sdk/path-parameters/snippet.json b/seed/python-sdk/path-parameters/snippet.json index 58fba49e541..23835fd3b3e 100644 --- a/seed/python-sdk/path-parameters/snippet.json +++ b/seed/python-sdk/path-parameters/snippet.json @@ -43,7 +43,7 @@ { "example_identifier": "default", "id": { - "path": "/user/users/{userId}", + "path": "/user/users/{userId}/search", "method": "GET", "identifier_override": "endpoint_user.searchUsers" }, @@ -56,7 +56,7 @@ { "example_identifier": "default", "id": { - "path": "/user/organizations/{organizationId}", + "path": "/user/organizations/{organizationId}/search", "method": "GET", "identifier_override": "endpoint_user.searchOrganizations" }, diff --git a/seed/python-sdk/path-parameters/src/seed/user/client.py b/seed/python-sdk/path-parameters/src/seed/user/client.py index dc15e9f0184..67d3cf3dfe7 100644 --- a/seed/python-sdk/path-parameters/src/seed/user/client.py +++ b/seed/python-sdk/path-parameters/src/seed/user/client.py @@ -186,7 +186,7 @@ def search_users( ) """ _response = self._client_wrapper.httpx_client.request( - f"user/users/{jsonable_encoder(user_id)}", + f"user/users/{jsonable_encoder(user_id)}/search", method="GET", params={ "limit": limit, @@ -241,7 +241,7 @@ def search_organizations( ) """ _response = self._client_wrapper.httpx_client.request( - f"user/organizations/{jsonable_encoder(organization_id)}", + f"user/organizations/{jsonable_encoder(organization_id)}/search", method="GET", params={ "limit": limit, @@ -469,7 +469,7 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._client_wrapper.httpx_client.request( - f"user/users/{jsonable_encoder(user_id)}", + f"user/users/{jsonable_encoder(user_id)}/search", method="GET", params={ "limit": limit, @@ -532,7 +532,7 @@ async def main() -> None: asyncio.run(main()) """ _response = await self._client_wrapper.httpx_client.request( - f"user/organizations/{jsonable_encoder(organization_id)}", + f"user/organizations/{jsonable_encoder(organization_id)}/search", method="GET", params={ "limit": limit, diff --git a/seed/ruby-model/path-parameters/.mock/definition/user.yml b/seed/ruby-model/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/ruby-model/path-parameters/.mock/definition/user.yml +++ b/seed/ruby-model/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/ruby-sdk/path-parameters/.mock/definition/user.yml b/seed/ruby-sdk/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/ruby-sdk/path-parameters/.mock/definition/user.yml +++ b/seed/ruby-sdk/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/ruby-sdk/path-parameters/lib/fern_path_parameters/user/client.rb b/seed/ruby-sdk/path-parameters/lib/fern_path_parameters/user/client.rb index aede9cb7bd0..6e356fbcb01 100644 --- a/seed/ruby-sdk/path-parameters/lib/fern_path_parameters/user/client.rb +++ b/seed/ruby-sdk/path-parameters/lib/fern_path_parameters/user/client.rb @@ -112,7 +112,7 @@ def search_users(user_id:, limit: nil, request_options: nil) unless request_options.nil? || request_options&.additional_body_parameters.nil? req.body = { **(request_options&.additional_body_parameters || {}) }.compact end - req.url "#{@request_client.get_url(request_options: request_options)}/user/users/#{user_id}" + req.url "#{@request_client.get_url(request_options: request_options)}/user/users/#{user_id}/search" end parsed_json = JSON.parse(response.body) parsed_json&.map do |item| @@ -140,7 +140,7 @@ def search_organizations(organization_id:, limit: nil, request_options: nil) unless request_options.nil? || request_options&.additional_body_parameters.nil? req.body = { **(request_options&.additional_body_parameters || {}) }.compact end - req.url "#{@request_client.get_url(request_options: request_options)}/user/organizations/#{organization_id}" + req.url "#{@request_client.get_url(request_options: request_options)}/user/organizations/#{organization_id}/search" end parsed_json = JSON.parse(response.body) parsed_json&.map do |item| @@ -262,7 +262,7 @@ def search_users(user_id:, limit: nil, request_options: nil) unless request_options.nil? || request_options&.additional_body_parameters.nil? req.body = { **(request_options&.additional_body_parameters || {}) }.compact end - req.url "#{@request_client.get_url(request_options: request_options)}/user/users/#{user_id}" + req.url "#{@request_client.get_url(request_options: request_options)}/user/users/#{user_id}/search" end parsed_json = JSON.parse(response.body) parsed_json&.map do |item| @@ -292,7 +292,7 @@ def search_organizations(organization_id:, limit: nil, request_options: nil) unless request_options.nil? || request_options&.additional_body_parameters.nil? req.body = { **(request_options&.additional_body_parameters || {}) }.compact end - req.url "#{@request_client.get_url(request_options: request_options)}/user/organizations/#{organization_id}" + req.url "#{@request_client.get_url(request_options: request_options)}/user/organizations/#{organization_id}/search" end parsed_json = JSON.parse(response.body) parsed_json&.map do |item| diff --git a/seed/ruby-sdk/path-parameters/snippet.json b/seed/ruby-sdk/path-parameters/snippet.json index e8246246895..bb656344d5e 100644 --- a/seed/ruby-sdk/path-parameters/snippet.json +++ b/seed/ruby-sdk/path-parameters/snippet.json @@ -35,7 +35,7 @@ }, { "id": { - "path": "/user/users/{userId}", + "path": "/user/users/{userId}/search", "method": "GET", "identifierOverride": "endpoint_user.searchUsers" }, @@ -46,7 +46,7 @@ }, { "id": { - "path": "/user/organizations/{organizationId}", + "path": "/user/organizations/{organizationId}/search", "method": "GET", "identifierOverride": "endpoint_user.searchOrganizations" }, @@ -90,7 +90,7 @@ }, { "id": { - "path": "/user/users/{userId}", + "path": "/user/users/{userId}/search", "method": "GET", "identifierOverride": "endpoint_user.searchUsers" }, @@ -101,7 +101,7 @@ }, { "id": { - "path": "/user/organizations/{organizationId}", + "path": "/user/organizations/{organizationId}/search", "method": "GET", "identifierOverride": "endpoint_user.searchOrganizations" }, diff --git a/seed/ts-express/path-parameters/.mock/definition/user.yml b/seed/ts-express/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/ts-express/path-parameters/.mock/definition/user.yml +++ b/seed/ts-express/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/ts-express/path-parameters/api/resources/user/service/UserService.ts b/seed/ts-express/path-parameters/api/resources/user/service/UserService.ts index 9179e1ebb31..bb3e4c2c990 100644 --- a/seed/ts-express/path-parameters/api/resources/user/service/UserService.ts +++ b/seed/ts-express/path-parameters/api/resources/user/service/UserService.ts @@ -199,7 +199,7 @@ export class UserService { next(error); } }); - this.router.get("/users/:userId", async (req, res, next) => { + this.router.get("/users/:userId/search", async (req, res, next) => { try { await this.methods.searchUsers( req as any, @@ -231,7 +231,7 @@ export class UserService { next(error); } }); - this.router.get("/organizations/:organizationId", async (req, res, next) => { + this.router.get("/organizations/:organizationId/search", async (req, res, next) => { try { await this.methods.searchOrganizations( req as any, diff --git a/seed/ts-sdk/path-parameters/.mock/definition/user.yml b/seed/ts-sdk/path-parameters/.mock/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/seed/ts-sdk/path-parameters/.mock/definition/user.yml +++ b/seed/ts-sdk/path-parameters/.mock/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string diff --git a/seed/ts-sdk/path-parameters/README.md b/seed/ts-sdk/path-parameters/README.md index a986c62d502..c9d302c1c34 100644 --- a/seed/ts-sdk/path-parameters/README.md +++ b/seed/ts-sdk/path-parameters/README.md @@ -58,6 +58,17 @@ try { } ``` +## Pagination + +List endpoints are paginated. The SDK provides an iterator so that you can simply loop over the items: + +```typescript +import { SeedPathParametersClient, SeedPathParameters } from "@fern/path-parameters"; + +const client = new SeedPathParametersClient({ environment: "YOUR_BASE_URL" }); +await client.user.getOrganization("organizationId"); +``` + ## Advanced ### Raw Responses diff --git a/seed/ts-sdk/path-parameters/snippet-templates.json b/seed/ts-sdk/path-parameters/snippet-templates.json index 8d52d9b3cd4..dad8a41bc4a 100644 --- a/seed/ts-sdk/path-parameters/snippet-templates.json +++ b/seed/ts-sdk/path-parameters/snippet-templates.json @@ -274,7 +274,7 @@ "type": "typescript" }, "endpointId": { - "path": "/user/users/{userId}", + "path": "/user/users/{userId}/search", "method": "GET", "identifierOverride": "endpoint_user.searchUsers" }, @@ -386,7 +386,7 @@ "type": "typescript" }, "endpointId": { - "path": "/user/organizations/{organizationId}", + "path": "/user/organizations/{organizationId}/search", "method": "GET", "identifierOverride": "endpoint_user.searchOrganizations" }, diff --git a/seed/ts-sdk/path-parameters/snippet.json b/seed/ts-sdk/path-parameters/snippet.json index dd6df1d0fdd..7667eaf5c6c 100644 --- a/seed/ts-sdk/path-parameters/snippet.json +++ b/seed/ts-sdk/path-parameters/snippet.json @@ -35,7 +35,7 @@ }, { "id": { - "path": "/user/users/{userId}", + "path": "/user/users/{userId}/search", "method": "GET", "identifier_override": "endpoint_user.searchUsers" }, @@ -46,7 +46,7 @@ }, { "id": { - "path": "/user/organizations/{organizationId}", + "path": "/user/organizations/{organizationId}/search", "method": "GET", "identifier_override": "endpoint_user.searchOrganizations" }, diff --git a/seed/ts-sdk/path-parameters/src/api/resources/user/client/Client.ts b/seed/ts-sdk/path-parameters/src/api/resources/user/client/Client.ts index 6a82e5bcbec..b35d70f6669 100644 --- a/seed/ts-sdk/path-parameters/src/api/resources/user/client/Client.ts +++ b/seed/ts-sdk/path-parameters/src/api/resources/user/client/Client.ts @@ -269,7 +269,7 @@ export class User { const _response = await core.fetcher({ url: urlJoin( await core.Supplier.get(this._options.environment), - `/user/users/${encodeURIComponent(userId)}` + `/user/users/${encodeURIComponent(userId)}/search` ), method: "GET", headers: { @@ -349,7 +349,7 @@ export class User { const _response = await core.fetcher({ url: urlJoin( await core.Supplier.get(this._options.environment), - `/user/organizations/${encodeURIComponent(organizationId)}` + `/user/organizations/${encodeURIComponent(organizationId)}/search` ), method: "GET", headers: { diff --git a/test-definitions/fern/apis/path-parameters/definition/user.yml b/test-definitions/fern/apis/path-parameters/definition/user.yml index 25ea9e21e02..0a2c271301a 100644 --- a/test-definitions/fern/apis/path-parameters/definition/user.yml +++ b/test-definitions/fern/apis/path-parameters/definition/user.yml @@ -40,7 +40,7 @@ service: response: User searchUsers: - path: "/users/{userId}" + path: "/users/{userId}/search" method: GET request: name: SearchUsersRequest @@ -51,7 +51,7 @@ service: response: list searchOrganizations: - path: "/organizations/{organizationId}" + path: "/organizations/{organizationId}/search" method: GET path-parameters: organizationId: string