Comments (5)
@Remirror-zz
Cool, thanks for the suggestion mate, its a good one. Ill leave this issue up for a while and give the feature some thought. TypeBox is due for some updates to align with some new features in TS 4.0, so may give this some thought then when I get around to those updates.
Thanks again!
from typebox.
Good point, but I think that using $ref
is possible even without specifying additional properties for a type such as Person
, at least if the name of this type is not important. In this case, whenever the generator recognizes a schema is used more than once (except for primitive/trivial schemas of course), it can be made a definition
and referenced by $ref
. However, I would agree that this may rather be an approach of schema optimization (in terms of length) and too implicit for the actual use case. So for that, I like your design suggestion.
Additional difficulties will arise though if one wants to harness the actual power of $ref
by including definitions of already existing schemas. This would require some serious design thinking, which should probably be done from the beginning.
For my case, I have now decided to go the other way round and put the priority on JSON schema rather than on TypeScript and thus to create my schema files manually and have them converted to interfaces by approaches such as json-schema-to-typescript
and validated by ajv
, so I fear I cannot be of help for you at the moment.
from typebox.
@Remirror-zz Hi. This issue has been outstanding for a while. I have recently pushed an update to TypeBox to support $ref
. You can read about the feature here https://github.com/sinclairzx81/typebox#reference-types. (note, this is still in an experimental state).
Note that $ref
Reference Types currently don't support referencing into the same schema (as per your initial example) (as it's quite difficult for TypeBox to flatten all declarations when composing for large nested schemas). So all referenced schemas MUST live inside a Box
type that can be referenced into.
As such, your original example can be expressed as.
const Person = Type.Object({ name: Type.String(), age: Type.Number() })
const Common = Type.Box('https://chess.app.com/common', {
Person
})
const ChessMatch = Type.Object({
playerWhite: Type.Ref(Common, 'Person'),
playerBlack: Type.Ref(Common, 'Person'),
});
This produces the following two schemas.
const Common = {
"$id": "https://chess.app.com/common",
"definitions": {
"Person": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "number"
}
},
"required": [
"name",
"age"
]
}
}
}
const ChessMatch = {
"type": "object",
"properties": {
"playerWhite": {
"$ref": "https://chess.app.com/common#/definitions/Person"
},
"playerBlack": {
"$ref": "https://chess.app.com/common#/definitions/Person"
}
},
"required": [
"playerWhite",
"playerBlack"
]
}
For validation using AJV, you would now pass the Common
referenceable schema to AJV via the addSchema()
function. This allows the ChessMatch
schema to validate against the loaded Common
schema containing the Person
type. As follows.
const ajv = new Ajv()
ajv.addSchema(Common) // adds the `Person` definition to AJV
ajv.validate(ChessMatch, {
playerWhite: { name: 'dave', age: 42 },
playerBlack: { name: 'alice', age: 28 },
})
Note that this feature provides a form of namespacing
for common related schemas. It's this direction I feel yields the most downstream benefit (in terms of practicality). Going with this approach, it would be possible to manually merge in the schemas into a single schema (as a manual downstream process), but it's not something that TypeBox should necessarily handle as part of its API (as there are a number of ways achieve this). Also, going with split schemas also promotes the idea of defining domain objects
that can be loaded as groups (and suggests dependency on domains at a namespace level).
Will close off this issue, but feel free to re-open if you have additional thoughts on the current implementation.
Cheers
S
from typebox.
@Remirror-zz Hi
I like the idea, however there isn't any way to trivially resolve the "definitions"
."person"
property or the {"$ref": "#/definitions/person"}
as the name "person" isn't directly resolvable from const Person = Type.Object({ ... })
. TypeBox would need to be extended to support the feature.
One option may be to extend TypeBox to support something like...
const Person = Type.Object({
'name': Type.String(),
'age': Type.Number()
}, { ref: 'person' }); // new
const ChessMatch = Type.Object({
'playerWhite': Person, // check here if Person has a 'ref', and if so assign it to "definitions"
'playerBlack': Person
});
The only reservation I'd have about implementing this is it may add a fair amount of complexity to the current schema generation. But id be curious to see an implementation.
Would you be interested in having a go implementing a reference design for this feature? I guess the make or break depends on just how intuitive the schema generation turns out to be for $ref
types.
Let me know!
from typebox.
I want this functionality too. But The problem is - TypeBox doesn't know which schema is to be exported. You'll have to create your own "Schema Container" (or "Schema Storage"), traverse entire definitions, and replace "referenced" schemas to JSONSchema reference object ($ref
). I've done this manually in our framework (see serverless-seoul/corgi@f817e42#diff-eda32f3dbf6b5eb9924a1cef12c90cf6R194-R222)
from typebox.
Related Issues (20)
- TypeCompiler.Compile incorrectly parsing `Record<any, any>` HOT 7
- Error when using Composite with Ref (Unable to dereference schema with $id 'undefined') HOT 3
- Transform type keys in Record HOT 2
- Is it possible to add support to the Type.String additional properties for the enum keyword HOT 2
- Support for async validations? HOT 1
- Transform + Map/Index does not work HOT 4
- Update the error message for required properties HOT 3
- Covariance issue with `TypeCheck<TSchema>` and `TypeCheck<TObject<{}>>` HOT 1
- Default values in nested objects are not generated HOT 2
- Doubt on Record HOT 2
- TypeCompiler compile on Type.Strict(T) - Preflight validation check failed to guard for the given schema HOT 2
- Max call stack size exceeded HOT 1
- Value.Convert() doesn't work with nullable record HOT 1
- Variadic Any Typed function parameters HOT 2
- How to do a cross field validation? HOT 3
- Undefined is incorrectly handled in Diff HOT 3
- QoL helper: `TypeCheck.Ensure` HOT 3
- Usage of `Type.Composite` with `Type.TemplateLiteral` HOT 3
- `Check` doesn't validate strings with enums HOT 4
- `Type.Omit` mixed with `Type.Union` is not preserving the `additionalProperties` attribute HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typebox.