Coder Social home page Coder Social logo

Comments (5)

sinclairzx81 avatar sinclairzx81 commented on May 23, 2024 4

@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.

 avatar commented on May 23, 2024 2

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.

sinclairzx81 avatar sinclairzx81 commented on May 23, 2024 2

@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.

sinclairzx81 avatar sinclairzx81 commented on May 23, 2024

@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.

mooyoul avatar mooyoul commented on May 23, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.