Repository: cdimascio/express-openapi-validator
Pull request #897 (2024-01-31 07:04:17)

[Snyk] Upgrade @types/multer from 1.4.7 to 1.4.11
<p>This PR was automatically created by Snyk using the credentials of a real user.</p><br /><h3>Snyk has created this PR to upgrade @types/multer from 1.4.7 to 1.4.11.</h3>

:information_source: Keep your dependencies up-to-date. This makes it easier to fix existing vulnerabilities and to more quickly identify and fix newly disclosed vulnerabilities when they affect your project.
<hr/>

- The recommended version is **4 versions** ahead of your current version.
- The recommended version was released **2 months ago**, on 2023-11-21.


<details>
<summary><b>Release notes</b></summary>
<br/>
  <details>
    <summary>Package name: <b>@types/multer</b></summary>
    <ul>
      <li>
        <b>1.4.11</b> - 2023-11-21
      </li>
      <li>
        <b>1.4.10</b> - 2023-11-07
      </li>
      <li>
        <b>1.4.9</b> - 2023-10-18
      </li>
      <li>
        <b>1.4.8</b> - 2023-09-27
      </li>
      <li>
        <b>1.4.7</b> - 2021-07-07
      </li>
    </ul>
    from <a href="https://snyk.io/redirect/github/DefinitelyTyped/DefinitelyTyped/releases">@types/multer GitHub release notes</a>
  </details>
</details>
<hr/>

**Note:** *You are seeing this because you or someone else with access to this repository has authorized Snyk to open upgrade PRs.*

For more information:  <img src="https://api.segment.io/v1/pixel/track?data=eyJ3cml0ZUtleSI6InJyWmxZcEdHY2RyTHZsb0lYd0dUcVg4WkFRTnNCOUEwIiwiYW5vbnltb3VzSWQiOiJiMDJhZjQ5ZC0yM2U1LTRlZWMtOGI3Yi1kYzNkNzQ1MDYwMmYiLCJldmVudCI6IlBSIHZpZXdlZCIsInByb3BlcnRpZXMiOnsicHJJZCI6ImIwMmFmNDlkLTIzZTUtNGVlYy04YjdiLWRjM2Q3NDUwNjAyZiJ9fQ==" width="0" height="0"/>

🧐 [View latest project report](https://app.snyk.io/org/cdimascio/project/f63fb44e-f154-45ba-b1f0-20d49ea578ce?utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;upgrade-pr)

🛠 [Adjust upgrade PR settings](https://app.snyk.io/org/cdimascio/project/f63fb44e-f154-45ba-b1f0-20d49ea578ce/settings/integration?utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;upgrade-pr)

🔕 [Ignore this dependency or unsubscribe from future upgrade PRs](https://app.snyk.io/org/cdimascio/project/f63fb44e-f154-45ba-b1f0-20d49ea578ce/settings/integration?pkg&#x3D;@types/multer&amp;utm_source&#x3D;github&amp;utm_medium&#x3D;referral&amp;page&#x3D;upgrade-pr#auto-dep-upgrades)

<!--- (snyk:metadata:{"prId":"b02af49d-23e5-4eec-8b7b-dc3d7450602f","prPublicId":"b02af49d-23e5-4eec-8b7b-dc3d7450602f","dependencies":[{"name":"@types/multer","from":"1.4.7","to":"1.4.11"}],"packageManager":"npm","type":"auto","projectUrl":"https://app.snyk.io/org/cdimascio/project/f63fb44e-f154-45ba-b1f0-20d49ea578ce?utm_source=github&utm_medium=referral&page=upgrade-pr","projectPublicId":"f63fb44e-f154-45ba-b1f0-20d49ea578ce","env":"prod","prType":"upgrade","vulns":[],"issuesToFix":[],"upgrade":[],"upgradeInfo":{"versionsDiff":4,"publishedDate":"2023-11-21T00:37:06.924Z"},"templateVariants":[],"hasFixes":false,"isMajorUpgrade":false,"isBreakingChange":false,"priorityScoreList":[]}) --->



Patch:
diff --git a/CHANGE_HISTORY.md b/CHANGE_HISTORY.md
index 140523b..2798074 100644
--- a/CHANGE_HISTORY.md
+++ b/CHANGE_HISTORY.md
@@ -1,7 +1,41 @@
+## <small>5.1.6 (2024-02-11)</small>
+
+* Fixes for 881 - multiple specs w/validateRequests fail (#903) ([766806b](https://github.com/cdimascio/express-openapi-validator/commit/766806b)), closes [#903](https://github.com/cdimascio/express-openapi-validator/issues/903)
+
+
+
+## <small>5.1.5 (2024-02-10)</small>
+
+* fixes write-only tests ([8c53e58](https://github.com/cdimascio/express-openapi-validator/commit/8c53e58))
+* Support writeOnly + required combination #149 (#756) ([4f16ed2](https://github.com/cdimascio/express-openapi-validator/commit/4f16ed2)), closes [#149](https://github.com/cdimascio/express-openapi-validator/issues/149) [#756](https://github.com/cdimascio/express-openapi-validator/issues/756)
+* v5.1.5 ([708f2f5](https://github.com/cdimascio/express-openapi-validator/commit/708f2f5))
+
+
+
+## <small>5.1.4 (2024-02-09)</small>
+
+* add cookies to examples 1 and 2 (#891) ([2c95d5b](https://github.com/cdimascio/express-openapi-validator/commit/2c95d5b)), closes [#891](https://github.com/cdimascio/express-openapi-validator/issues/891)
+* Direct example broken link to the guide ([00a9c8f](https://github.com/cdimascio/express-openapi-validator/commit/00a9c8f))
+* fixes badging for build and test ([631fb7b](https://github.com/cdimascio/express-openapi-validator/commit/631fb7b))
+* npm audit fix (#892) ([2977c0a](https://github.com/cdimascio/express-openapi-validator/commit/2977c0a)), closes [#892](https://github.com/cdimascio/express-openapi-validator/issues/892)
+* Remove read only and write only fields (#895) ([97617fd](https://github.com/cdimascio/express-openapi-validator/commit/97617fd)), closes [#895](https://github.com/cdimascio/express-openapi-validator/issues/895) [#627](https://github.com/cdimascio/express-openapi-validator/issues/627)
+* removes lodash.uniq and lodash.zipobject dependencies (#893) ([1206802](https://github.com/cdimascio/express-openapi-validator/commit/1206802)), closes [#893](https://github.com/cdimascio/express-openapi-validator/issues/893)
+* Update CONTRIBUTING.md ([6d67169](https://github.com/cdimascio/express-openapi-validator/commit/6d67169))
+* Update README.md ([dffda28](https://github.com/cdimascio/express-openapi-validator/commit/dffda28))
+* Update README.md ([bdd0d79](https://github.com/cdimascio/express-openapi-validator/commit/bdd0d79))
+* Update README.md (#896) ([bb66916](https://github.com/cdimascio/express-openapi-validator/commit/bb66916)), closes [#896](https://github.com/cdimascio/express-openapi-validator/issues/896)
+* v5.1.4 ([b3d7483](https://github.com/cdimascio/express-openapi-validator/commit/b3d7483))
+* v5.1.4 ([509fa22](https://github.com/cdimascio/express-openapi-validator/commit/509fa22))
+* fix: #887 allow multiple params with wildcard (#898) ([2d33d0a](https://github.com/cdimascio/express-openapi-validator/commit/2d33d0a)), closes [#887](https://github.com/cdimascio/express-openapi-validator/issues/887) [#898](https://github.com/cdimascio/express-openapi-validator/issues/898) [#1](https://github.com/cdimascio/express-openapi-validator/issues/1)
+* docs: fix doc typo in README.md (#885) ([8a81bf8](https://github.com/cdimascio/express-openapi-validator/commit/8a81bf8)), closes [#885](https://github.com/cdimascio/express-openapi-validator/issues/885)
+
+
+
 ## <small>5.1.3 (2024-01-27)</small>
 
 * CLS Context is lost after using multer middleware (#695) ([40716fb](https://github.com/cdimascio/express-openapi-validator/commit/40716fb)), closes [#695](https://github.com/cdimascio/express-openapi-validator/issues/695)
 * remove examples from schema (#890) ([0ad49ec](https://github.com/cdimascio/express-openapi-validator/commit/0ad49ec)), closes [#890](https://github.com/cdimascio/express-openapi-validator/issues/890)
+* v5.1.3 ([f806690](https://github.com/cdimascio/express-openapi-validator/commit/f806690))
 * v5.1.3 ([e567701](https://github.com/cdimascio/express-openapi-validator/commit/e567701))
 
 
@@ -117,3 +151,37 @@
 
 
 
+## <small>4.13.8 (2022-05-30)</small>
+
+* Bump AJV to v8 (#713) ([2b27332](https://github.com/cdimascio/express-openapi-validator/commit/2b27332)), closes [#713](https://github.com/cdimascio/express-openapi-validator/issues/713)
+* Bump multer to version that removes dicer as sub-dependency (#739) ([6501a62](https://github.com/cdimascio/express-openapi-validator/commit/6501a62)), closes [#739](https://github.com/cdimascio/express-openapi-validator/issues/739)
+* update ansi-regex ([6448f45](https://github.com/cdimascio/express-openapi-validator/commit/6448f45))
+* Update README.md ([c954b4b](https://github.com/cdimascio/express-openapi-validator/commit/c954b4b))
+* v4.14.0-beta.1 ([369a4a6](https://github.com/cdimascio/express-openapi-validator/commit/369a4a6))
+* v4.14.0-beta.2 ([1706538](https://github.com/cdimascio/express-openapi-validator/commit/1706538))
+* chore(deps): bump ansi-regex in /examples/2-standard-multiple-api-specs (#727) ([3e803b5](https://github.com/cdimascio/express-openapi-validator/commit/3e803b5)), closes [#727](https://github.com/cdimascio/express-openapi-validator/issues/727)
+* chore(deps): bump ansi-regex in /examples/3-eov-operations (#726) ([aba3cd0](https://github.com/cdimascio/express-openapi-validator/commit/aba3cd0)), closes [#726](https://github.com/cdimascio/express-openapi-validator/issues/726)
+* chore(deps): bump ansi-regex in /examples/5-custom-operation-resolver (#725) ([2bf250e](https://github.com/cdimascio/express-openapi-validator/commit/2bf250e)), closes [#725](https://github.com/cdimascio/express-openapi-validator/issues/725)
+* chore(deps): bump ansi-regex in /examples/6-multi-file-spec (#723) ([e29c1eb](https://github.com/cdimascio/express-openapi-validator/commit/e29c1eb)), closes [#723](https://github.com/cdimascio/express-openapi-validator/issues/723)
+* chore(deps): bump ansi-regex in /examples/7-response-date-serialization (#722) ([acdae50](https://github.com/cdimascio/express-openapi-validator/commit/acdae50)), closes [#722](https://github.com/cdimascio/express-openapi-validator/issues/722)
+* chore(deps): bump ansi-regex in /examples/8-top-level-discriminator (#719) ([45059a6](https://github.com/cdimascio/express-openapi-validator/commit/45059a6)), closes [#719](https://github.com/cdimascio/express-openapi-validator/issues/719)
+* chore(deps): bump follow-redirects in /examples/9-nestjs (#705) ([15e91aa](https://github.com/cdimascio/express-openapi-validator/commit/15e91aa)), closes [#705](https://github.com/cdimascio/express-openapi-validator/issues/705)
+* chore(deps): bump minimist from 1.2.5 to 1.2.6 in /examples/1-standard (#714) ([1eecf40](https://github.com/cdimascio/express-openapi-validator/commit/1eecf40)), closes [#714](https://github.com/cdimascio/express-openapi-validator/issues/714)
+* chore(deps): bump minimist in /examples/2-standard-multiple-api-specs (#716) ([6f6ea71](https://github.com/cdimascio/express-openapi-validator/commit/6f6ea71)), closes [#716](https://github.com/cdimascio/express-openapi-validator/issues/716)
+* chore(deps): bump minimist in /examples/3-eov-operations (#715) ([3f6cb37](https://github.com/cdimascio/express-openapi-validator/commit/3f6cb37)), closes [#715](https://github.com/cdimascio/express-openapi-validator/issues/715)
+* chore(deps): bump minimist in /examples/4-eov-operations-babel (#717) ([6b90f35](https://github.com/cdimascio/express-openapi-validator/commit/6b90f35)), closes [#717](https://github.com/cdimascio/express-openapi-validator/issues/717)
+* chore(deps): bump minimist in /examples/5-custom-operation-resolver (#718) ([acc3f33](https://github.com/cdimascio/express-openapi-validator/commit/acc3f33)), closes [#718](https://github.com/cdimascio/express-openapi-validator/issues/718)
+* chore(deps): bump minimist in /examples/6-multi-file-spec (#724) ([15814ba](https://github.com/cdimascio/express-openapi-validator/commit/15814ba)), closes [#724](https://github.com/cdimascio/express-openapi-validator/issues/724)
+* chore(deps): bump minimist in /examples/7-response-date-serialization (#721) ([ff63618](https://github.com/cdimascio/express-openapi-validator/commit/ff63618)), closes [#721](https://github.com/cdimascio/express-openapi-validator/issues/721)
+* chore(deps): bump minimist in /examples/8-top-level-discriminator (#720) ([a23a09f](https://github.com/cdimascio/express-openapi-validator/commit/a23a09f)), closes [#720](https://github.com/cdimascio/express-openapi-validator/issues/720)
+* chore(deps): bump node-fetch from 2.6.1 to 2.6.7 in /examples/9-nestjs (#711) ([87bb6df](https://github.com/cdimascio/express-openapi-validator/commit/87bb6df)), closes [#711](https://github.com/cdimascio/express-openapi-validator/issues/711)
+
+
+
+## <small>4.13.7 (2022-03-27)</small>
+
+* migrate README to wiki ([4887ba5](https://github.com/cdimascio/express-openapi-validator/commit/4887ba5))
+* Update README ([13b26d6](https://github.com/cdimascio/express-openapi-validator/commit/13b26d6))
+
+
+
diff --git a/README.md b/README.md
index 23c21c8..a73489f 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.
 
@@ -10,7 +10,7 @@ docs.
 <img src="https://raw.githubusercontent.com/cdimascio/express-openapi-validator/master/assets/express-openapi-validator-logo-v2.png" width="600">
 </p>
 
-[🦋express-openapi-validator](https://github.com/cdimascio/express-openapi-validator) is an unopinionated library that integrates with new and existing API applications. express-openapi-validator lets you write code the way you want; it does not impose any coding convention or project layout. Simply, install the validator onto your express app, point it to your OpenAPI 3 specification, then define and implement routes the way you prefer. See an [example](#example-express-api-server).
+[🦋express-openapi-validator](https://github.com/cdimascio/express-openapi-validator) is an unopinionated library that integrates with new and existing API applications. express-openapi-validator lets you write code the way you want; it does not impose any coding convention or project layout. Simply, install the validator onto your express app, point it to your OpenAPI 3 specification, then define and implement routes the way you prefer. See an [example](https://cdimascio.github.io/express-openapi-validator-documentation/guide-standard/).
 
 **Features:**
 
diff --git a/examples/2-standard-multiple-api-specs/api.v2.yaml b/examples/2-standard-multiple-api-specs/api.v2.yaml
index b5b7f2e..91a58f8 100644
--- a/examples/2-standard-multiple-api-specs/api.v2.yaml
+++ b/examples/2-standard-multiple-api-specs/api.v2.yaml
@@ -117,9 +117,9 @@ components:
   schemas:
     Pet:
       required:
-        - id
-        - name
-        - type
+        - pet_id
+        - pet_name
+        - pet_type
       properties:
         pet_id:
           readOnly: true
diff --git a/package-lock.json b/package-lock.json
index 6ff155e..42bfefc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,16 @@
 {
   "name": "express-openapi-validator",
-  "version": "5.1.3",
+  "version": "5.1.6",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "express-openapi-validator",
-      "version": "5.1.3",
+      "version": "5.1.6",
       "license": "MIT",
       "dependencies": {
         "@apidevtools/json-schema-ref-parser": "^9.1.2",
-        "@types/multer": "^1.4.7",
+        "@types/multer": "^1.4.11",
         "ajv": "^8.11.2",
         "ajv-draft-04": "^1.0.0",
         "ajv-formats": "^2.1.1",
@@ -1164,9 +1164,9 @@
       }
     },
     "node_modules/@types/multer": {
-      "version": "1.4.7",
-      "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz",
-      "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==",
+      "version": "1.4.11",
+      "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.11.tgz",
+      "integrity": "sha512-svK240gr6LVWvv3YGyhLlA+6LRRWA4mnGIU7RcNmgjBYFl6665wcXrRfxGp5tEPVHUNm5FMcmq7too9bxCwX/w==",
       "dependencies": {
         "@types/express": "*"
       }
diff --git a/package.json b/package.json
index aa09554..c756b8f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "express-openapi-validator",
-  "version": "5.1.3",
+  "version": "5.1.6",
   "description": "Automatically validate API requests and responses with OpenAPI 3 and Express.",
   "main": "dist/index.js",
   "scripts": {
@@ -34,7 +34,7 @@
   "license": "MIT",
   "dependencies": {
     "@apidevtools/json-schema-ref-parser": "^9.1.2",
-    "@types/multer": "^1.4.7",
+    "@types/multer": "^1.4.11",
     "ajv": "^8.11.2",
     "ajv-draft-04": "^1.0.0",
     "ajv-formats": "^2.1.1",
diff --git a/src/framework/openapi.context.ts b/src/framework/openapi.context.ts
index 2df421f..8d6fc23 100644
--- a/src/framework/openapi.context.ts
+++ b/src/framework/openapi.context.ts
@@ -12,6 +12,7 @@ export class OpenApiContext {
   public readonly routes: RouteMetadata[] = [];
   public readonly ignoreUndocumented: boolean;
   public readonly useRequestUrl: boolean;
+  public readonly serial: number;
   private readonly basePaths: string[];
   private readonly ignorePaths: RegExp | Function;
 
@@ -28,6 +29,7 @@ export class OpenApiContext {
     this.ignoreUndocumented = ignoreUndocumented;
     this.buildRouteMaps(spec.routes);
     this.useRequestUrl = useRequestUrl;
+    this.serial = spec.serial;
   }
 
   public isManagedRoute(path: string): boolean {
diff --git a/src/framework/openapi.spec.loader.ts b/src/framework/openapi.spec.loader.ts
index bc0d075..3ccb148 100644
--- a/src/framework/openapi.spec.loader.ts
+++ b/src/framework/openapi.spec.loader.ts
@@ -9,6 +9,7 @@ export interface Spec {
   apiDoc: OpenAPIV3.Document;
   basePaths: string[];
   routes: RouteMetadata[];
+  serial: number;
 }
 
 export interface RouteMetadata {
@@ -23,6 +24,7 @@ interface DiscoveredRoutes {
   apiDoc: OpenAPIV3.Document;
   basePaths: string[];
   routes: RouteMetadata[];
+  serial: number;
 }
 // Sort routes by most specific to least specific i.e. static routes before dynamic
 // e.g. /users/my_route before /users/{id}
@@ -33,6 +35,9 @@ export const sortRoutes = (r1, r2) => {
   return e1 > e2 ? 1 : -1;
 };
 
+// Uniquely identify the Spec that is emitted
+let serial = 0;
+
 export class OpenApiSpecLoader {
   private readonly framework: OpenAPIFramework;
   constructor(opts: OpenAPIFrameworkArgs) {
@@ -91,10 +96,12 @@ export class OpenApiSpecLoader {
 
     routes.sort(sortRoutes);
 
+    serial = serial + 1;
     return {
       apiDoc,
       basePaths,
       routes,
+      serial
     };
   }
 
@@ -106,7 +113,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');
diff --git a/src/framework/types.ts b/src/framework/types.ts
index eb4f4af..7cc4167 100644
--- a/src/framework/types.ts
+++ b/src/framework/types.ts
@@ -497,6 +497,7 @@ export interface OpenApiRequestMetadata {
   openApiRoute: string;
   pathParams: { [index: string]: string };
   schema: OpenAPIV3.OperationObject;
+  serial: number;
 }
 
 export interface OpenApiRequest extends Request {
diff --git a/src/middlewares/openapi.metadata.ts b/src/middlewares/openapi.metadata.ts
index a137073..12813f0 100644
--- a/src/middlewares/openapi.metadata.ts
+++ b/src/middlewares/openapi.metadata.ts
@@ -48,6 +48,7 @@ export function applyOpenApiMetadata(
         openApiRoute: openApiRoute,
         pathParams: pathParams,
         schema: schema,
+        serial: openApiContext.serial,
       };
       req.params = pathParams;
       if (responseApiDoc) {
@@ -101,6 +102,7 @@ export function applyOpenApiMetadata(
             expressRoute,
             openApiRoute,
             pathParams,
+            serial: -1,
           };
           (<any>r)._responseSchema = _schema;
           return r;
diff --git a/src/middlewares/openapi.response.validator.ts b/src/middlewares/openapi.response.validator.ts
index 6166ca5..a187ad0 100644
--- a/src/middlewares/openapi.response.validator.ts
+++ b/src/middlewares/openapi.response.validator.ts
@@ -32,15 +32,18 @@ export class ResponseValidator {
     [key: string]: { [key: string]: ValidateFunction };
   } = {};
   private eovOptions: ValidateResponseOpts;
+  private serial: number;
 
   constructor(
     openApiSpec: OpenAPIV3.Document,
     options: Options = {},
     eovOptions: ValidateResponseOpts = {},
+    serial: number = -1,
   ) {
     this.spec = openApiSpec;
     this.ajvBody = createResponseAjv(openApiSpec, options);
     this.eovOptions = eovOptions;
+    this.serial = serial;
 
     // This is a pseudo-middleware function. It doesn't get registered with
     // express via `use`
@@ -51,7 +54,7 @@ export class ResponseValidator {
 
   public validate(): RequestHandler {
     return mung.json((body, req, res) => {
-      if (req.openapi) {
+      if (req.openapi && this.serial == req.openapi.serial) {
         const openapi = <OpenApiRequestMetadata>req.openapi;
         // instead of openapi.schema, use openapi._responseSchema to get the response copy
         const responses: OpenAPIV3.ResponsesObject = (<any>openapi)
diff --git a/src/middlewares/parsers/schema.preprocessor.ts b/src/middlewares/parsers/schema.preprocessor.ts
index 8d9d894..8e14f4c 100644
--- a/src/middlewares/parsers/schema.preprocessor.ts
+++ b/src/middlewares/parsers/schema.preprocessor.ts
@@ -287,6 +287,7 @@ export class SchemaPreprocessor {
         // This null check should no longer be necessary
         this.handleSerDes(pschema, nschema, options);
         this.handleReadonly(pschema, nschema, options);
+        this.handleWriteonly(pschema, nschema, options);
         this.processDiscriminator(pschema, nschema, options);
         this.removeExamples(pschema, nschema, options)
       }
@@ -479,6 +480,27 @@ export class SchemaPreprocessor {
     }
   }
 
+  private handleWriteonly(
+    parent: OpenAPIV3.SchemaObject,
+    schema: OpenAPIV3.SchemaObject,
+    opts,
+  ) {
+    if (opts.kind === 'req') return;
+
+    const required = parent?.required ?? [];
+    const prop = opts?.path?.[opts?.path?.length - 1];
+    const index = required.indexOf(prop);
+    if (schema.writeOnly && index > -1) {
+      // remove required if writeOnly
+      parent.required = required
+        .slice(0, index)
+        .concat(required.slice(index + 1));
+      if (parent.required.length === 0) {
+        delete parent.required;
+      }
+    }
+  }
+
   /**
    * extract all requestBodies' schemas from an operation
    * @param op
diff --git a/src/openapi.validator.ts b/src/openapi.validator.ts
index c4b639e..43073be 100644
--- a/src/openapi.validator.ts
+++ b/src/openapi.validator.ts
@@ -35,6 +35,12 @@ export {
   Forbidden,
 } from './framework/types';
 
+interface MiddlewareContext {
+  context: OpenApiContext,
+  responseApiDoc: OpenAPIV3.Document,
+  error: any,
+}
+
 export class OpenApiValidator {
   readonly options: NormalizedOpenApiValidatorOpts;
   readonly ajvOpts: AjvOptions;
@@ -92,7 +98,7 @@ export class OpenApiValidator {
 
   installMiddleware(spec: Promise<Spec>): OpenApiRequestHandler[] {
     const middlewares: OpenApiRequestHandler[] = [];
-    const pContext = spec
+    const pContext: Promise<MiddlewareContext> = spec
       .then((spec) => {
         const apiDoc = spec.apiDoc;
         const ajvOpts = this.ajvOpts.preprocessor;
@@ -183,7 +189,7 @@ export class OpenApiValidator {
       });
     }
 
-    // request middlweare
+    // request middleware
     if (this.options.validateRequests) {
       let reqmw;
       middlewares.push(function requestMiddleware(req, res, next) {
@@ -201,8 +207,8 @@ export class OpenApiValidator {
       let resmw;
       middlewares.push(function responseMiddleware(req, res, next) {
         return pContext
-          .then(({ responseApiDoc }) => {
-            resmw = resmw || self.responseValidationMiddleware(responseApiDoc);
+          .then(({ responseApiDoc, context: { serial } }) => {
+            resmw = resmw || self.responseValidationMiddleware(responseApiDoc, serial);
             return resmw(req, res, next);
           })
           .catch(next);
@@ -288,12 +294,13 @@ export class OpenApiValidator {
     return (req, res, next) => requestValidator.validate(req, res, next);
   }
 
-  private responseValidationMiddleware(apiDoc: OpenAPIV3.Document) {
+  private responseValidationMiddleware(apiDoc: OpenAPIV3.Document, serial: number) {
     return new middlewares.ResponseValidator(
       apiDoc,
       this.ajvOpts.response,
       // This has already been converted from boolean if required
       this.options.validateResponses as ValidateResponseOpts,
+      serial
     ).validate();
   }
 


Test patch:
diff --git a/test/356.campaign.spec.ts b/test/356.campaign.spec.ts
index 57004cd..fbe834d 100644
--- a/test/356.campaign.spec.ts
+++ b/test/356.campaign.spec.ts
@@ -1,4 +1,4 @@
-import * as path from 'path';
+ import * as path from 'path';
 import * as express from 'express';
 import * as request from 'supertest';
 import { createApp } from './common/app';
diff --git a/test/881.spec.ts b/test/881.spec.ts
new file mode 100644
index 0000000..33bd3d1
--- /dev/null
+++ b/test/881.spec.ts
@@ -0,0 +1,119 @@
+import { expect } from 'chai';
+import * as request from 'supertest';
+
+describe('multi-spec', () => {
+  let app = null;
+
+  before(async () => {
+    // Set up the express app
+    app = createServer();
+  });
+
+  after(() => {
+    app.server.close();
+  });
+
+  it('create campaign should return 200', async () =>
+    request(app)
+      .get(`/v1/pets`)
+      .expect(400)
+      .then((r) => {
+        expect(r.body.message).include('limit');
+        expect(r.body.message).include(`'type'`);
+      }));
+
+  it('create campaign should return 200', async () =>
+    request(app)
+      .get(`/v2/pets`)
+      .expect(400)
+      .then((r) => {
+        expect(r.body.message).include(`'pet_type'`);
+      }));
+});
+
+function createServer() {
+  const express = require('express');
+  const path = require('path');
+  const bodyParser = require('body-parser');
+  const http = require('http');
+  const OpenApiValidator = require('../src');
+
+  const app = express();
+  app.use(bodyParser.urlencoded({ extended: false }));
+  app.use(bodyParser.text());
+  app.use(bodyParser.json());
+
+  const versions = [1, 2];
+
+  for (const v of versions) {
+    const apiSpec = path.join(__dirname, `api.v${v}.yaml`);
+    app.use(
+      OpenApiValidator.middleware({
+        apiSpec,
+        validateResponses: true,
+      }),
+    );
+
+    routes(app, v);
+  }
+
+  const server = http.createServer(app);
+  server.listen(3000);
+  console.log('Listening on port 3000');
+
+  function routes(app, v) {
+    if (v === 1) routesV1(app);
+    if (v === 2) routesV2(app);
+  }
+
+  function routesV1(app) {
+    const v = '/v1';
+    app.post(`${v}/pets`, (req, res, next) => {
+      res.json({ ...req.body });
+    });
+    app.get(`${v}/pets`, (req, res, next) => {
+      res.json([
+        {
+          id: 1,
+          name: 'happy',
+          type: 'cat',
+        },
+      ]);
+    });
+
+    app.use((err, req, res, next) => {
+      // format error
+      res.status(err.status || 500).json({
+        message: err.message,
+        errors: err.errors,
+      });
+    });
+  }
+
+  function routesV2(app) {
+    const v = '/v2';
+    app.get(`${v}/pets`, (req, res, next) => {
+      res.json([
+        {
+          pet_id: 1,
+          pet_name: 'happy',
+          pet_type: 'kitty',
+        },
+      ]);
+    });
+    app.post(`${v}/pets`, (req, res, next) => {
+      res.json({ ...req.body });
+    });
+
+    app.use((err, req, res, next) => {
+      // format error
+      res.status(err.status || 500).json({
+        message: err.message,
+        errors: err.errors,
+      });
+    });
+  }
+
+  app.server = server;
+  return app;
+}
diff --git a/test/api.v2.yaml b/test/api.v2.yaml
index b5b7f2e..91a58f8 100644
--- a/test/api.v2.yaml
+++ b/test/api.v2.yaml
@@ -117,9 +117,9 @@ components:
   schemas:
     Pet:
       required:
-        - id
-        - name
-        - type
+        - pet_id
+        - pet_name
+        - pet_type
       properties:
         pet_id:
           readOnly: true
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/resources/write.only.yaml b/test/resources/write.only.yaml
index 64db4be..cf8d62e 100644
--- a/test/resources/write.only.yaml
+++ b/test/resources/write.only.yaml
@@ -95,6 +95,8 @@ components:
     # TODO add nested test
     ProductNested:
       type: object
+      required:
+        - "password"
       properties:
         id:
           type: string
@@ -117,9 +119,14 @@ components:
           type: array
           items:
             $ref: '#/components/schemas/Review'
+        password:
+          type: string
+          writeOnly: true
 
     Review:
       type: object
+      required:
+        - "review_password"
       properties:
         id:
           type: integer
@@ -132,3 +139,6 @@ components:
           writeOnly: true
         rating:
           type: integer
+        review_password:
+          type: string
+          writeOnly: true
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');
+      }));
 });
diff --git a/test/write.only.removeadditional.spec.ts b/test/write.only.removeadditional.spec.ts
index e50da1d..cbf9161 100644
--- a/test/write.only.removeadditional.spec.ts
+++ b/test/write.only.removeadditional.spec.ts
@@ -10,31 +10,34 @@ describe(packageJson.name, () => {
   before(async () => {
     // Set up the express app
     const apiSpec = path.join('test', 'resources', 'write.only.yaml');
-    app = await createApp({ apiSpec, validateResponses: {removeAdditional : true} }, 3005, app =>
-      app
-        .post(`${app.basePath}/products/inlined`, (req, res) => {
-          const body = req.body;
-          const excludeWriteOnly = req.query.exclude_write_only;
-          if (excludeWriteOnly) {
-            delete body.role;
-          }
-          res.json(body);
-        })
-        .post(`${app.basePath}/products/nested`, (req, res) => {
-          const body = req.body;
-          const excludeWriteOnly = req.query.exclude_write_only;
-          body.id = 'test';
-          body.created_at = new Date().toISOString();
-          body.reviews = body.reviews.map(r => ({
-            ...(excludeWriteOnly ? {} : { role_x: 'admin' }),
-            rating: r.rating ?? 2,
-          }));
+    app = await createApp(
+      { apiSpec, validateResponses: { removeAdditional: true } },
+      3005,
+      (app) =>
+        app
+          .post(`${app.basePath}/products/inlined`, (req, res) => {
+            const body = req.body;
+            const excludeWriteOnly = req.query.exclude_write_only;
+            if (excludeWriteOnly) {
+              delete body.role;
+            }
+            res.json(body);
+          })
+          .post(`${app.basePath}/products/nested`, (req, res) => {
+            const body = req.body;
+            const excludeWriteOnly = req.query.exclude_write_only;
+            body.id = 'test';
+            body.created_at = new Date().toISOString();
+            body.reviews = body.reviews.map((r) => ({
+              ...(excludeWriteOnly ? {} : { role_x: 'admin' }),
+              rating: r.rating ?? 2,
+            }));
 
-          if (excludeWriteOnly) {
-            delete body.role;
-          }
-          res.json(body);
-        }),
+            if (excludeWriteOnly) {
+              delete body.role;
+            }
+            res.json(body);
+          }),
     );
   });
 
@@ -52,7 +55,7 @@ describe(packageJson.name, () => {
         price: 10.99,
       })
       .expect(200)
-      .then(r => {
+      .then((r) => {
         const body = r.body;
         expect(body.message).to.be.undefined;
         expect(body.role).to.be.undefined;
@@ -71,8 +74,7 @@ describe(packageJson.name, () => {
         role: 'admin',
         price: 10.99,
       })
-      .expect(200)
-  );
+      .expect(200));
 
   it('should remove write only properties in responses (nested schema $refs) thanks to removeAdditional', async () =>
     request(app)
@@ -81,18 +83,18 @@ describe(packageJson.name, () => {
       .send({
         name: 'some name',
         price: 10.99,
+        password: 'password_value',
         reviews: [
           {
-            rating: 5
+            rating: 5,
+            review_password: 'review_password_value',
           },
         ],
       })
       .expect(200)
-      .then(r => {
+      .then((r) => {
         const body = r.body;
-        console.log('%j', r.body);
         expect(body.reviews[0].role_x).to.be.undefined;
         expect(body.reviews[0].rating).to.be.equal(5);
       }));
-
 });
diff --git a/test/write.only.spec.ts b/test/write.only.spec.ts
index 04b6d4b..565fcbf 100644
--- a/test/write.only.spec.ts
+++ b/test/write.only.spec.ts
@@ -10,7 +10,7 @@ describe(packageJson.name, () => {
   before(async () => {
     // Set up the express app
     const apiSpec = path.join('test', 'resources', 'write.only.yaml');
-    app = await createApp({ apiSpec, validateResponses: true }, 3005, app =>
+    app = await createApp({ apiSpec, validateResponses: true }, 3005, (app) =>
       app
         .post(`${app.basePath}/products/inlined`, (req, res) => {
           const body = req.body;
@@ -18,22 +18,29 @@ describe(packageJson.name, () => {
           if (excludeWriteOnly) {
             delete body.role;
           }
-          res.json(body);
+          res.json({
+            ...body,
+          });
         })
         .post(`${app.basePath}/products/nested`, (req, res) => {
           const body = req.body;
           const excludeWriteOnly = req.query.exclude_write_only;
           body.id = 'test';
           body.created_at = new Date().toISOString();
-          body.reviews = body.reviews.map(r => ({
+          body.reviews = body.reviews.map((r) => ({
             ...(excludeWriteOnly ? {} : { role_x: 'admin' }),
             rating: r.rating ?? 2,
           }));
 
           if (excludeWriteOnly) {
             delete body.role;
+            delete body.password;
           }
-          res.json(body);
+          res.json({
+            // id: 'xxxxx',
+            // created_at: '2024-02-09T17:32:28Z',
+            ...body,
+          });
         }),
     );
   });
@@ -52,7 +59,7 @@ describe(packageJson.name, () => {
         created_at: new Date().toUTCString(),
       })
       .expect(400)
-      .then(r => {
+      .then((r) => {
         const body = r.body;
         // id is a readonly property and should not be allowed in the request
         expect(body.message).to.contain('created_at');
@@ -68,7 +75,7 @@ describe(packageJson.name, () => {
         price: 10.99,
       })
       .expect(500)
-      .then(r => {
+      .then((r) => {
         const body = r.body;
         expect(body.message).to.contain('role');
         expect(body.errors[0].path).to.contain('/response/role');
@@ -86,9 +93,35 @@ describe(packageJson.name, () => {
         name: 'some name',
         role: 'admin',
         price: 10.99,
+        password: 'password_value',
       })
       .expect(200));
 
+  it('should return 200 if no write-only properties are in the responses', async () =>
+    request(app)
+      .post(`${app.basePath}/products/nested`)
+      .query({
+        exclude_write_only: true,
+      })
+      .set('content-type', 'application/json')
+      .send({
+        name: 'some name',
+        price: 10.99,
+        password: 'password_value',
+        reviews: [
+          {
+            rating: 5,
+            review_password: 'review_password_value',
+          },
+        ],
+      })
+      .expect(200)
+      .then((r) => {
+        const body = r.body;
+        // check that read-only props were not affected and present in the response
+        expect(body.created_at).to.be;
+      }));
+
   it('should not allow write only properties in responses (nested schema $refs)', async () =>
     request(app)
       .post(`${app.basePath}/products/nested`)
@@ -96,14 +129,16 @@ describe(packageJson.name, () => {
       .send({
         name: 'some name',
         price: 10.99,
+        password: 'password_value',
         reviews: [
           {
             rating: 5,
+            review_password: 'review_password_value',
           },
         ],
       })
       .expect(500)
-      .then(r => {
+      .then((r) => {
         const body = r.body;
         expect(body.message).to.contain('role_x');
         expect(body.errors[0].path).to.contain('/response/reviews/0/role_x');
@@ -129,7 +164,7 @@ describe(packageJson.name, () => {
         ],
       })
       .expect(400)
-      .then(r => {
+      .then((r) => {
         const body = r.body;
         expect(body.message).to.contain('request/body/reviews/0/id');
       }));