diff --git a/changelog/@unreleased/path-param-ordering.v2.yml b/changelog/@unreleased/path-param-ordering.v2.yml new file mode 100644 index 00000000..e8750e7b --- /dev/null +++ b/changelog/@unreleased/path-param-ordering.v2.yml @@ -0,0 +1,5 @@ +type: fix +fix: + description: Fix a problem with the generated code in the case where path params show up in different orders in the path template and the args block. + links: + - https://github.com/palantir/conjure-typescript/pull/100 diff --git a/src/commands/generate/__tests__/resources/services/outOfOrderPathService.ts b/src/commands/generate/__tests__/resources/services/outOfOrderPathService.ts new file mode 100644 index 00000000..2f528609 --- /dev/null +++ b/src/commands/generate/__tests__/resources/services/outOfOrderPathService.ts @@ -0,0 +1,30 @@ +import { IHttpApiBridge, MediaType } from "conjure-client"; + +export interface IOutOfOrderPathService { + foo(param1: string, param2: string): Promise; +} + +export class OutOfOrderPathService { + constructor(private bridge: IHttpApiBridge) { + } + + public foo(param1: string, param2: string): Promise { + return this.bridge.callEndpoint({ + data: undefined, + endpointName: "foo", + endpointPath: "/{param2}/{param1}", + headers: { + }, + method: "GET", + pathArguments: [ + param2, + + param1, + ], + queryArguments: { + }, + requestMediaType: MediaType.APPLICATION_JSON, + responseMediaType: MediaType.APPLICATION_JSON, + }); + } +} diff --git a/src/commands/generate/__tests__/serviceGeneratorTest.ts b/src/commands/generate/__tests__/serviceGeneratorTest.ts index 6df4c59b..925441f9 100644 --- a/src/commands/generate/__tests__/serviceGeneratorTest.ts +++ b/src/commands/generate/__tests__/serviceGeneratorTest.ts @@ -261,6 +261,45 @@ describe("serviceGenerator", () => { assertOutputAndExpectedAreEqual(outDir, expectedDir, "services/paramTypeService.ts"); }); + it("handles out of order path params", async () => { + await generateService( + { + endpoints: [ + { + args: [ + { + argName: "param1", + markers: [], + paramType: { + path: {}, + type: "path", + }, + type: stringType, + }, + { + argName: "param2", + markers: [], + paramType: { + path: {}, + type: "path", + }, + type: stringType, + }, + ], + endpointName: "foo", + httpMethod: HttpMethod.GET, + httpPath: "/{param2}/{param1}", + markers: [], + }, + ], + serviceName: { name: "OutOfOrderPathService", package: "com.palantir.services" }, + }, + new Map(), + simpleAst, + ); + assertOutputAndExpectedAreEqual(outDir, expectedDir, "services/outOfOrderPathService.ts"); + }); + it("handles header auth-type", async () => { await generateService( { diff --git a/src/commands/generate/serviceGenerator.ts b/src/commands/generate/serviceGenerator.ts index 34be738a..285dab3e 100644 --- a/src/commands/generate/serviceGenerator.ts +++ b/src/commands/generate/serviceGenerator.ts @@ -165,6 +165,8 @@ function generateEndpointBody( } }); + const pathParamsFromPath = parsePathParamsFromPath(endpointDefinition.httpPath); + if (bodyArgs.length > 1) { throw Error("endpoint cannot have more than one body arg, found: " + bodyArgs.length); } @@ -201,7 +203,7 @@ function generateEndpointBody( writer.writeLine(`method: "${endpointDefinition.httpMethod}",`); writer.write("pathArguments: ["); - pathArgNames.forEach(pathArgName => writer.indent().writeLine(pathArgName + ",")); + pathParamsFromPath.forEach(pathArgName => writer.indent().writeLine(pathArgName + ",")); writer.writeLine("],"); writer.write("queryArguments: {"); @@ -222,3 +224,13 @@ function mediaType(conjureType?: IType) { } return "MediaType.APPLICATION_JSON"; } + +function parsePathParamsFromPath(httpPath: string): string[] { + // first fix up the path to remove any ':.+' stuff in path params + const fixedPath = httpPath.replace(/{(.*):[^}]*}/, "{$1}"); + // follow-up by just pulling out any path segment with a starting '{' and trailing '}' + return fixedPath + .split("/") + .filter(segment => segment.startsWith("{") && segment.endsWith("}")) + .map(segment => segment.slice(1, -1)); +}