Skip to content

Commit

Permalink
update README
Browse files Browse the repository at this point in the history
  • Loading branch information
cdimascio committed Jun 8, 2020
1 parent 29ed69e commit ff1ad92
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 57 deletions.
74 changes: 17 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,61 +295,6 @@ module.exports = {
};
```

## [Example Express API Server: with custom operation resolver](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/5-custom-operation-resolver)

By default, when you configure `operationHandlers` to be the base path to your operation handler files, we use `operationId`, `x-eov-operation-id` and `x-eov-operation-handler` to determine what request handler should be used during routing.

If you ever want _FULL_ control over how that resolution happens (e.g. you want to use your own extended attributes or simply rely on `operationId`), then here's how you can accomplish that following an example where our `operationId` becomes a template that follows `{module}.{function}`.

- First, specifiy the `operationHandlers` option to be an object with a `basePath` and `resolver` properties. `basePath` is the path to where all your handler files are located. `resolver` is a function that **MUST** return an Express `RequestHandler` given `basePath` and `route` (which gives you access to the OpenAPI schema for a specific Operation)

```javascript
new OpenApiValidator({
apiSpec,
operationHandlers: {
basePath: path.join(__dirname, 'routes'),
resolver: (basePath, route) => {
// Pluck controller and function names from operationId
const [controllerName, functionName] = route.schema['operationId'].split('.')

// Get path to module and attempt to require it
const modulePath = path.join(basePath, controllerName);
const handler = require(modulePath)

// Simplistic error checking to make sure the function actually exists
// on the handler module
if (handler[functionName] === undefined) {
throw new Error(
`Could not find a [${functionName}] function in ${modulePath} when trying to route [${route.method} ${route.expressRoute}].`
)
}

// Finally return our function
return handler[functionName]
}
});
```
- Next, use `operationId` to specify the id of opeartion handler to invoke.
```yaml
/pets:
get:
# This means our resolver will look for a file named "pets.js" at our
# configured base path and will return an export named "list" from
# that module as the Express RequestHandler.
operationId: pets.list
```
- Finally, create the express handler module e.g. `routes/pets.js`
```javascript
module.exports = {
// the express handler implementation for the pets collection
list: (req, res) => res.json(/* ... */),
};
```
## API Validation Response Examples

#### Validates a query parameter with a value constraint
Expand Down Expand Up @@ -544,7 +489,7 @@ new OpenApiValidator(options).install({
}
}
},
operationHandlers: false | 'operations/base/path',
operationHandlers: false | 'operations/base/path' | { ... },
ignorePaths: /.*\/pets$/,
unknownFormats: ['phone-number', 'uuid'],
fileUploader: { ... } | true | false,
Expand Down Expand Up @@ -665,11 +610,26 @@ Defines how the validator should behave if an unknown or custom format is encoun

### ▪️ operationHandlers (optional)

Defines the base directory for operation handlers. This is used in conjunction with express-openapi-validator's OpenAPI vendor extensions.
Defines the base directory for operation handlers. This is used in conjunction with express-openapi-validator's OpenAPI vendor extensions, `x-eov-operation-id` and x-eov-operation-handler.

If you want to change how modules are resolved e.g. use dot separated operation ids e.g. `path.to.module.func`, you may optionally add a custom resovler `resolver`. See [example](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/5-eov-operations)

- `string` - the base directory containing operation handlers
- `false` - (default) disable auto wired operation handlers
- `{ ... }` - specifies a base directory and optionally a custom resolver

**handlers:**

For example:

```javascript
operationHandlers: {
basePath: __dirname,
resolver: function (modulePath, route): express.RequestHandler {
///...
}
}
```
```
operationHandlers: 'operations/base/path'
```
Expand Down
48 changes: 48 additions & 0 deletions examples/5-custom-operation-resolver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,51 @@ curl http://localhost:3000/v1/ping
## the call below should return 400 since it requires additional parameters
curl http://localhost:3000/v1/pets
```

## [Example Express API Server: with custom operation resolver](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/5-custom-operation-resolver)

By default, when you configure `operationHandlers` to be the base path to your operation handler files, we use `operationId`, `x-eov-operation-id` and `x-eov-operation-handler` to determine what request handler should be used during routing.

If you ever want _FULL_ control over how that resolution happens (e.g. you want to use your own extended attributes or simply rely on `operationId`), then here's how you can accomplish that following an example where our `operationId` becomes a template that follows `{module}.{function}`.

- First, specifiy the `operationHandlers` option to be an object with a `basePath` and `resolver` properties. `basePath` is the path to where all your handler files are located. `resolver` is a function that **MUST** return an Express `RequestHandler` given `basePath` and `route` (which gives you access to the OpenAPI schema for a specific Operation)

```javascript
new OpenApiValidator({
apiSpec,
operationHandlers: {
basePath: path.join(__dirname, 'routes'),
resolver: (basePath, route) => {
// Pluck controller and function names from operationId
const [controllerName, functionName] = route.schema['operationId'].split('.')
// Get path to module and attempt to require it
const modulePath = path.join(basePath, controllerName);
const handler = require(modulePath)
// Simplistic error checking to make sure the function actually exists
// on the handler module
if (handler[functionName] === undefined) {
throw new Error(
`Could not find a [${functionName}] function in ${modulePath} when trying to route [${route.method} ${route.expressRoute}].`
)
}
// Finally return our function
return handler[functionName]
}
});
```
- Next, use `operationId` to specify the id of opeartion handler to invoke.
```yaml
/pets:
get:
# This means our resolver will look for a file named "pets.js" at our
# configured base path and will return an export named "list" from
# that module as the Express RequestHandler.
operationId: pets.list
```
- Finally, create the express handler module e.g. `routes/pets.js`
```javascript
module.exports = {
// the express handler implementation for the pets collection
list: (req, res) => res.json(/* ... */),
};
```

0 comments on commit ff1ad92

Please sign in to comment.