loopbackio / loopbackio/loopback-next
Allow RegExp values for `jsonSchema.pattern` field in property definition
- Dominant language
- TypeScript
- Stars
- 5.1k
- Forks
- 1.1k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 27
Description
When creating a model, I'd like to specify pattern-based validation for my `phoneNum` property:
```ts
@property({
type: 'string',
jsonSchema: {
pattern: /\d{3}-\d{3}-\d{4}/,
},
})
phoneNum?: string;
```
At the moment, we require the pattern to be a string source:
```js
pattern: '\\d{3}-\\d{3}-\\d{4}'
```
I find these strings problematic:
- Editors/IDEs don't highlight RegExp keywords
- It's easy to forget to escape `\` characters. When they are not escaped, users end up with a different RegExp that expected - see #4218 for an example.
## Workaround
Use `RegExp.source` property to convert from a RegExp instance to a source string.
```ts
@property({
type: 'string',
jsonSchema: {
pattern: /\d{3}-\d{3}-\d{4}/.source,
},
})
phoneNum?: string;
```
## Acceptance criteria
### Models (the important and also easy part)
Allow LB4 app developers to use RegExp `pattern` values in their model definitions, scoped to `jsonSchema` only for now (i.e. to apply during REST API validation only, not as a database constraint). Example property definition:
```ts
@property({
jsonSchema: {
pattern: /\d{3}-\d{3}-\d{4}/,
},
})
phoneNum?: string;
```
- [ ] Implementation: The conversion from `RegExp` to `string` should probably happen inside [`metaToJsonProperty()`](https://github.com/strongloop/loopback-next/blob/b0a84b5adc30cac3614ea90e414b59cf76009ecf/packages/repository-json-schema/src/build-schema.ts#L296-L298) function. Use [`RegExp.prototype.source`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/source) property to convert a `RegExp` instance to a string.
- [ ] Test coverage: Add tests to verify the new behavior, e.g. to [`packages/repository-json-schema/src/__tests__/unit/build-schema.unit.ts`](https://github.com/strongloop/loopback-next/blob/b0a84b5adc30cac3614ea90e414b59cf76009ecf/packages/repository-json-schema/src/__tests__/unit/build-schema.unit.ts)
- [ ] Docs: Update documentation to explain users how to use `jsonSchema` and `jsonSchema.pattern` in `@property()` decorators - see e.g. https://loopback.io/doc/en/lb4/Model.html#supported-json-keywords
### REST API layer (optional, could be difficult to implement)
Allow LB4 app developers to use RegExp values in OpenAPI spec metadata, e.g. provided via Controller decorators.
```ts
class MyController {
greet(
@param({
name: 'date',
in: 'path',
schema: {
type: 'string',
pattern: /^\d{4}-\d{2}-\d{2}$/,
}
})
today: string,
) {
return `Good morning, today is ${date}`;
}
}
```
Start by writing a group of (acceptance-level) tests to verify handling of RegExp patterns by our REST API layer:
- [ ] Define a controller with a method with a parameter using `pattern`-based validation and a RegExp pattern value.
- [ ] Send a request with a valid value expecting 200 response.
- [ ] Send a request with an invalid value expecting 4xx response.
- [ ] Verify that the OpenAPI spec document returned by the app includes the pattern converted to string via `.source` property. Quoting from https://github.com/OAI/OpenAPI-Specification/blob/3.0.1/versions/3.0.1.md#properties: _pattern (This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression dialect)_
- [ ] Fix the implementation (and type definitions) as necessary to allow such test to pass.
- [ ] I think we will need to update `@param` definitions to allow `RegExp` values for `pattern` fields.
- [ ] Figure out how to pass `RegExp` patterns to AJV so that it can perform pattern-base validation. It's possible that AJV supports RegExp values out of the box, in which case no changes may be required
## Out of scope
`pattern` as a top-level model property:
```ts
@property({
pattern: /\d{3}-\d{3}-\d{4}/,
...
})
```
Quoting from https://github.com/strongloop/loopback-next/issues/4228#issuecomment-646700989:
> The catch is that once `pattern` is a regular property metadata, it must be enforced both at REST API level (`@loopback/rest` must translate that pattern to AJV JSON Schema field) and at data-access level (by loopback-datasource-juggler), so it's more work to make this happen 🤷 The upside is that with a new property-level metadata, connectors can translate the `pattern` constraint to a database constraint too ([a PostgreSQL example](https://stackoverflow.com/a/35822507/69868)). Related: Epic: Validation at Model/ORM level #1872.
---
## 🎆 Hacktoberfest 2020
Greetings :wave: to all Hacktoberfest 2020 participants!
Here are few tips 👀 to make your start easier:
- Before you start working on this issue, please leave a comment to let others know.
- Feel free to implement support for RegExp patterns in model property definitions only, it's ok to leave the rest for others to pick up.
- If you are new to GitHub pull requests, then you can learn about the process in [Submitting a pull request to LoopBack 4](https://loopback.io/doc/en/lb4/submitting_a_pr.html).
- If this is your first contribution to LoopBack, then please take a look at our [Developer guide](https://loopback.io/doc/en/lb4/code-contrib-lb4.html)
- Feel free to ask for help in `#loopback-contributors` channel, you can join our Slack workspace [here](https://join.slack.com/t/loopbackio/shared_invite/zt-8lbow73r-SKAKz61Vdao~_rGf91pcsw).
See also #6456.
Contributor guide
Research direction
For the scoped model work, start in packages/repository-json-schema/src/build-schema.ts at metaToJsonProperty(), then add cases to packages/repository-json-schema/src/__tests__/unit/build-schema.unit.ts. Run the repository-json-schema unit tests and verify RegExp patterns are represented by their source strings. The broader REST portion requires acceptance tests for valid and invalid requests plus the generated OpenAPI document, while the documentation update should cover jsonSchema.pattern usage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- openapi, typescript
- Domain
- api, backend-api-design, documentation, testing
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100