From a3d0dfc6ffe2ea10d9f0aa33dc23b5a777fb5e8c Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Thu, 11 Apr 2019 08:18:03 -0700 Subject: [PATCH] feat(cli): normalize variable names for OpenAPI paths Non-word characters in variable names for OpenAPI paths are not allowed by `@loopback/rest`. --- packages/cli/generators/openapi/spec-helper.js | 17 +++++++++++++++-- .../cli/test/fixtures/openapi/3.0/customer.yaml | 4 ++-- .../test/unit/openapi/controller-spec.unit.js | 8 ++++---- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/cli/generators/openapi/spec-helper.js b/packages/cli/generators/openapi/spec-helper.js index 517135f0735c..cd29953376ab 100644 --- a/packages/cli/generators/openapi/spec-helper.js +++ b/packages/cli/generators/openapi/spec-helper.js @@ -203,7 +203,13 @@ function buildMethodSpec(controllerSpec, op, options) { const pType = mapSchemaType(p.schema, options); addImportsForType(pType); comments.push(`@param ${name} ${p.description || ''}`); - return `@param({name: '${p.name}', in: '${p.in}'}) ${name}: ${ + + // Normalize parameter name to match `\w` + let paramName = p.name; + if (p.in === 'path') { + paramName = paramName.replace(/[^\w]+/g, '_'); + } + return `@param({name: '${paramName}', in: '${p.in}'}) ${name}: ${ pType.signature }`; }); @@ -285,10 +291,17 @@ function buildMethodSpec(controllerSpec, op, options) { returnType.signature }>`; comments.unshift(op.spec.description || '', '\n'); + + // Normalize path variable names to alphanumeric characters including the + // underscore (Equivalent to [A-Za-z0-9_]). Please note `@loopback/rest` + // does not allow other characters that don't match `\w`. + const opPath = op.path.replace(/\{[^\}]+\}/g, varName => + varName.replace(/[^\w\{\}]+/g, '_'), + ); const methodSpec = { description: op.spec.description, comments, - decoration: `@operation('${op.verb}', '${op.path}')`, + decoration: `@operation('${op.verb}', '${opPath}')`, signature, }; if (op.spec['x-implementation']) { diff --git a/packages/cli/test/fixtures/openapi/3.0/customer.yaml b/packages/cli/test/fixtures/openapi/3.0/customer.yaml index 6a676327e015..ca94b9ca5181 100644 --- a/packages/cli/test/fixtures/openapi/3.0/customer.yaml +++ b/packages/cli/test/fixtures/openapi/3.0/customer.yaml @@ -69,7 +69,7 @@ paths: application/json: schema: $ref: '#/components/schemas/Customer' - /customers/{id}: + /customers/{customer-id}: get: tags: - Customer @@ -77,7 +77,7 @@ paths: x-implementation: "return {id: id, 'first-name': 'John', last-name: 'Smith'};" operationId: find customer by id parameters: - - name: id + - name: customer-id in: path description: ID of customer to fetch required: true diff --git a/packages/cli/test/unit/openapi/controller-spec.unit.js b/packages/cli/test/unit/openapi/controller-spec.unit.js index bdd55dc3f624..d56e126f37ac 100644 --- a/packages/cli/test/unit/openapi/controller-spec.unit.js +++ b/packages/cli/test/unit/openapi/controller-spec.unit.js @@ -59,13 +59,13 @@ describe('openapi to controllers/models', () => { comments: [ 'Returns a customer based on a single ID', '\n', - '@param id ID of customer to fetch', + '@param customerId ID of customer to fetch', '@returns customer response', ], - decoration: "@operation('get', '/customers/{id}')", + decoration: "@operation('get', '/customers/{customer_id}')", signature: - "async findCustomerById(@param({name: 'id', in: 'path'}) " + - 'id: number): Promise', + "async findCustomerById(@param({name: 'customer_id', " + + "in: 'path'}) customerId: number): Promise", implementation: "return {id: id, 'first-name': 'John', last-name: 'Smith'};", },