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)
- JsonTypeBuilder#Record not passing on options HOT 1
- No implicit defaults on Value.Create() HOT 5
- [BUG] Value.create caches the default date HOT 1
- Feature request: Value.Assert and TypeCheck.Assert HOT 3
- [Feature Request?] allow more flexible input for string pattern HOT 3
- Individual types imports naming conflict with native classes HOT 4
- Strict error: Unknown type HOT 2
- Maximum call stack size exceeded. HOT 2
- TUnion of literals from const array HOT 2
- "Value.Clean" doesn't work with Unions of objects with prohibited additionalProperties HOT 3
- JS floating point precision bug causes multipleOf validation to fail HOT 4
- Tuple with rest items (or Array with prefixedItems) HOT 2
- useDefaults HOT 3
- Support for discriminator HOT 1
- Support for self-referencing fields of recursive type HOT 2
- Property '[Kind]' is missing in type 'TObject' but required in type 'TObject<TProperties>' HOT 3
- [feat] Bail / Early Cancel Mode HOT 1
- Setting Description HOT 1
- Schema dependency using Typebox HOT 3
- Composite working uncorrect HOT 5
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.