Code Monkey home page Code Monkey logo

plate's Introduction

Plate

Language-agnostic schemas based on Haskell's type system.

Why Schemas

Schema languages like JSON Schema let you to describe data in a way that can be understood by any programming language. They're one of the core components of API description tools like Swagger. Once you write schemas to describe the data your API deals with you can use them to automatically generate documentation, UIs, and client code. This avoids lots of manual, error-prone work at your application boundary.

Why Another Schema Language

Writing a schema language is trickier than it looks. You have to strike a careful balance between over and under-expressiveness.

If you make your schema under-expressive it becomes little better than no schema at all. For example JSchema allows all values described by the schema to be null. While it's easy to find nice things to say about JSchema (such as its simplicity), implicit nulls don't allow enough structure for many tasks.

On the other hand you can error by allowing too much expressiveness. For instance in JSON Schema a clever combination of the "anyOf", "allOf", and "not" keywords is enough to build if and case statements (discovered by Evgeny Poberezkin).

This allows schemas to describe enormously complex structures for which it's impossible to automatically generate clean UIs or client code. Once again this defeats the original purpose. One solution would be to ask schema writers to work in only some subset of the schema langauge, but which subset? We're back to the original problem.

The Idea Behind Plate

The solution is to look for rescue from a related field. Language-specific type system writers have been feeling out the sweet spot of expressiveness longer than the other tools mentioned here have existed. Even better, many of them are battle-hardened and sit on a principled theoretical foundation.

And of course the most glorious, battle-hardened, and principled of these is Haskell. Plate is what you get when you steal the most basic, essential features of Haskell's type system and build a schema language from them. Hopefully this lets Plate strike the right level of expressiveness for many tasks.

Status

Work-in-progress. Nothing is final or production ready. Everything is a mess. Documentation is wrong.

Example

Say we have the following Haskell type:

data Album = Album
  { title  :: Text
  , artist :: Text
  , tracks :: [Text]
  }

We can also express it as a Plate schema using the plate library:

album :: Schema
album = ProductType (HM.fromList
  [ ("title", Builtin SString)
  , ("artist", Builtin SString)
  , ("tracks", Builtin (SSequence (Builtin SString)))
  ])

(It won't be hard to make this conversion automatic, though I haven't gotten around to it yet.)

We can then generate a JSON representation of the schema for other tools to use:

{
  "schema.product": {
    "title": {
      "type": {
        "schema.string": {}
      }
    },
    "artist": {
      "type": {
        "schema.string": {}
      }
    },
    "tracks": {
      "type": {
        "schema.sequence": {
          "type": {
            "schema.string": {}
          }
        }
      }
    }
  }
}

We can also generate UIs so users can conveniently create instances of our schema:

(Note: the editor isn't released yet)

Then say a user creates this piece of data:

{
  "title": "Interstellar: Original Motion Picture Soundtrack",
  "artist": "Hans Zimmer",
  "tracks": {
    "sequence": [
      "Dreaming of the Crash",
      "Cornfield Chase",
      "Dust",
      "Day One",
      "Stay",
      "Message from Home",
      "The Wormhole",
      "Mountains",
      "Afraid of Time",
      "A Place Among the Stars",
      "Running Out",
      "I'm Going Home",
      "Coward",
      "Detach",
      "S.T.A.Y.",
      "Where We're Going"
    ]
  }
}

We can convert it to its Plate representation and then validate it:

λ> Plate.validate mempty albumSchema interstellarSountrack
Right ()

Special Thanks

TJ Weigel created the logo.

plate's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

plate's Issues

Examine common migration patterns

Users will often want to expand Plate schemas while still keeping backwards compatibility with old data. Lets examine some of the ways this can play out.

Adding a new field to a sum type

100% backward compatibility with old data. Nice.

Adding a new field to a product type

Currently this always breaks backwards compatibility. We could avoid some of this in two ways: either by allowing optional fields to be missing or by allowing defaults to be set. This ties in to issue #2.

Academic work / similar projects?

The only similar schema project I've seen with polymorphism and algebraic types is http://cakoose.com/cks/ (which I found after starting work on Plate).

Does anyone know of other, similar projects? I'm especially interested in any schema system that's designed with expressiveness in mind, not speed of message encoding/decoding.

Make a plan for how to handle product types

Currently product types act like PureScript row types where as long as the required fields exist it doesn't matter if there are other fields as well. See the implementation here. Is this actually what we want?

This issue is made additionally tricky by the goals of a schema system as opposed to a type system. As a schema system we'd like to be able to add additional, optional fields to a product type and still maintain backwards compatibility with old data. Is there a principled way to do this that won't cause us trouble in the future?

Enumerate features we might add to Plate

This will hopefully stay fairly short.

  • Maximum and Minimum (for integers, sequences, etc.)
  • New value types (e.g. multisets). See #4.
  • Default values
  • Optional record values (in the sense that fields can be missing entirely, not just null)
  • A distinction between row types and record types

We'll open individual issues for some of these topics. This issue is for the big picture things: do we want Plate to stay close to Haskell/PureScript's type systems, or do we want to add features common in other schema systems like maximum and minimum integers?

Make sure we a good definition of Plate values

Values are currently defined in docs/specification.md.

  1. Is the rationale for making values more complicated than type Value = Map String Value solid?

  2. Can we find a principled distinction between things like sequences that we define as primitive values and other things like multisets that we don't?

  3. Once we find a principle for determining what to make a primitive value, does it suggest any new primitives we should add (or old ones we should take away)?

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.