Repository: cdimascio/express-openapi-validator
Pull request #898 (2024-01-31 16:45:04)

fix: #887 allow multiple params with wildcard
- add test for paths with multiple params including a wildcard param
- update the `toExpressParams` wildcard regex

Fixes: #887 


Patch:
diff --git a/README.md b/README.md
index 23c21c8..65d3fe8 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 docs.
 
-[![example workflow](https://github.com/cdimascio/express-openapi-validator/actions/workflows/default.yml/badge.svg)](#) [![](https://img.shields.io/npm/v/express-openapi-validator.svg)](https://www.npmjs.com/package/express-openapi-validator) [![](https://img.shields.io/npm/dm/express-openapi-validator?color=blue)](https://www.npmjs.com/package/express-openapi-validator) [![All Contributors](https://img.shields.io/badge/all_contributors-54-darkcyan.svg?style=flat)](#contributors) [![Coverage Status](https://coveralls.io/repos/github/cdimascio/express-openapi-validator/badge.svg?branch=master)](https://coveralls.io/github/cdimascio/express-openapi-validator?branch=master) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/1570a06f609345ddb237114bbd6ceed7)](https://www.codacy.com/manual/cdimascio/express-openapi-validator?utm_source=github.com&utm_medium=referral&utm_content=cdimascio/express-openapi-validator&utm_campaign=Badge_Grade) [![](https://img.shields.io/gitter/room/cdimascio-oss/community?color=%23eb205a)](https://gitter.im/cdimascio-oss/community) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/cdimascio/express-openapi-validator) [![](https://img.shields.io/badge/documentation-wiki-informational)](https://cdimascio.github.io/express-openapi-validator-documentation/) [![](https://img.shields.io/badge/license-MIT-blue.svg)](#license)
+[![example workflow](https://github.com/cdimascio/express-openapi-validator/actions/workflows/default.yml/badge.svg)](#) [![](https://img.shields.io/npm/v/express-openapi-validator.svg)](https://www.npmjs.com/package/express-openapi-validator) [![](https://img.shields.io/npm/dm/express-openapi-validator?color=blue)](https://www.npmjs.com/package/express-openapi-validator) [![All Contributors](https://img.shields.io/badge/all_contributors-54-darkcyan.svg?style=flat)](#contributors) [![Coverage Status](https://coveralls.io/repos/github/cdimascio/express-openapi-validator/badge.svg?branch=master)](https://coveralls.io/github/cdimascio/express-openapi-validator?branch=master) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/1570a06f609345ddb237114bbd6ceed7)](https://www.codacy.com/manual/cdimascio/express-openapi-validator?utm_source=github.com&utm_medium=referral&utm_content=cdimascio/express-openapi-validator&utm_campaign=Badge_Grade) [![](https://img.shields.io/gitter/room/cdimascio-oss/community?color=%23eb205a)](https://gitter.im/cdimascio-oss/community) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/cdimascio/express-openapi-validator) [![](https://img.shields.io/badge/documentation-yes-informational)](https://cdimascio.github.io/express-openapi-validator-documentation/) [![](https://img.shields.io/badge/license-MIT-blue.svg)](#license)
 
 **An OpenApi validator for ExpressJS** that automatically validates **API** _**requests**_ and _**responses**_ using an **OpenAPI 3** specification.
 
diff --git a/src/framework/openapi.spec.loader.ts b/src/framework/openapi.spec.loader.ts
index bc0d075..44b6a8a 100644
--- a/src/framework/openapi.spec.loader.ts
+++ b/src/framework/openapi.spec.loader.ts
@@ -106,7 +106,7 @@ export class OpenApiSpecLoader {
     // instead create our own syntax that is compatible with express' pathToRegex
     // /{path}* => /:path*)
     // /{path}(*) => /:path*)
-    const pass1 = part.replace(/\/{([^\*]+)}\({0,1}(\*)\){0,1}/g, '/:$1$2');
+    const pass1 = part.replace(/\/{([^}]+)}\({0,1}(\*)\){0,1}/g, '/:$1$2');
     // substitute params with express equivalent
     // /path/{id} => /path/:id
     return pass1.replace(/\{([^}]+)}/g, ':$1');


Test patch:
diff --git a/test/resources/wildcard.path.params.yaml b/test/resources/wildcard.path.params.yaml
index d9122af..13bf3a4 100644
--- a/test/resources/wildcard.path.params.yaml
+++ b/test/resources/wildcard.path.params.yaml
@@ -52,6 +52,42 @@ paths:
 
   /d3:
     get:
+      responses:
+        200:
+          description: dummy response
+          content: {}
+
+  /d4/{multi}/spaced/{path}(*):
+    get:
+      parameters:
+        - name: multi
+          in: path
+          required: true
+          schema:
+            type: string
+        - name: path
+          in: path
+          required: true
+          schema:
+            type: string
+      responses:
+        200:
+          description: dummy response
+          content: {}
+
+  /d5/{multi}/{path}(*):
+    get:
+      parameters:
+        - name: multi
+          in: path
+          required: true
+          schema:
+            type: string
+        - name: path
+          in: path
+          required: true
+          schema:
+            type: string
       responses:
         200:
           description: dummy response
diff --git a/test/wildcard.path.params.spec.ts b/test/wildcard.path.params.spec.ts
index 52f72f4..cbf610b 100644
--- a/test/wildcard.path.params.spec.ts
+++ b/test/wildcard.path.params.spec.ts
@@ -34,6 +34,16 @@ describe('wildcard path params', () => {
             res.json({
               success: true,
             }),
+          )
+          .get(`${app.basePath}/d4/:multi/spaced/:path(*)`, (req, res) =>
+            res.json({
+              ...req.params,
+            }),
+          )
+          .get(`${app.basePath}/d5/:multi/:path(*)`, (req, res) =>
+            res.json({
+              ...req.params,
+            }),
           );
       },
     );
@@ -83,4 +93,22 @@ describe('wildcard path params', () => {
       .then((r) => {
         expect(r.body.success).to.be.true;
       }));
+
+  it('should return 200 when wildcard path includes all required params and multiple path params', async () =>
+    request(app)
+      .get(`${app.basePath}/d4/one/spaced/two/three/four`)
+      .expect(200)
+      .then((r) => {
+        expect(r.body.multi).to.equal('one');
+        expect(r.body.path).to.equal('two/three/four');
+      }));
+
+  it('should return 200 when wildcard path includes all required params and multiple path params', async () =>
+    request(app)
+      .get(`${app.basePath}/d5/one/two/three/four`)
+      .expect(200)
+      .then((r) => {
+        expect(r.body.multi).to.equal('one');
+        expect(r.body.path).to.equal('two/three/four');
+      }));
 });