Happy Birthday, quicktype!

Today quicktype is one year old. After generating one billion lines of code, here's a look back on quicktype's first year.

How quicktype started

A year ago, I was writing some Swift to parse and represent JSON when I was struck by how mind-numbingly tedious the process was (especially before Codable was introduced in Swift 4). I had seen some simple JSON-to-code translators, but they were always buggy, had terrible UX, and were hard-coded for a single programming language.

"Mark, I need your big brain," I said to my big-brained friend Mark, before explaining the problem and what I thought a good solution would be like: paste JSON on the left, instantly get lovely code in any language on the right, with functions for marshaling to-and-from JSON strings. The goal would be to generate the same code that a person would write by hand, so the style had to be impeccable and we'd have to infer intuitive names for types and properties.

Mark agreed it would be a fun project, so we started hacking, and within a day or two, the world got its first look at a crude prototype:

Screen-Shot-2018-07-09-at-9.19.11-PM

quicktype was implemented as 700 lines of purely-functional PureScript, generating C# and Go from an intermediate representation. Here's the code that rendered C# classes:

renderCSharpClass :: IRClassData -> Doc Unit
renderCSharpClass (IRClassData { names, properties }) = do
  line $ words ["class", csNameStyle $ combineNames names]
  lines "{"
  indent do
    for_ (Map.toUnfoldable properties :: Array _) \(Tuple.Tuple pname ptype) -> do
      line do
        string "[JsonProperty(\""
        string pname
        string "\")]"
      line do
        string "public "
        graph <- getGraph
        string $ renderTypeToCSharp graph ptype
        words ["", csNameStyle pname, "{ get; set; }"]
      blank
    
    -- TODO don't rely on 'TopLevel'
    when (names == Set.singleton "TopLevel") do
      lines """// Loading helpers
           public static TopLevel FromJson(string json) => JsonConvert.DeserializeObject<TopLevel>(json);
           public static TopLevel FromUrl(string url) => FromJson(new WebClient().DownloadString(url));"""
  lines "}"

Then we continuously deployed updates and new features for a year.

quicktype today

quicktype has come a long way in that time. quicktype now has:

  • Generated over 1.2 billion lines of code, by rough estimate. In San Francisco, you'd have to hire 76 developers at a cost of $7.9 million to write this code, assuming no sick days and all programmers type 40 WPM for 6 hours per day!
  • 30k lines of TypeScript in core libraries
  • 13k lines of TypeScript in the web app
  • Support for C#, Go, Rust, C++, Objective-C, Java, TypeScript, JavaScript, Flow, Swift, Kotlin, Elm, JSON Schema, Ruby, and now Python
  • Support for GraphQL, JSON Schema, and TypeScript as input, so you can more formally specify desired output types
  • Many language-specific options, like typesafe HTTP request handlers in Swift or runtime type checking in JavaScript
  • Integer, enum, and map inference
  • Stringified number, boolean, date, and UUID inference with automatic parsing in C# and Python
  • Extensions for Xcode, VSCode, and Visual Studio

We recently released 'continuous mode' for the VSCode extension, which generates code from JSON, schema, and TypeScript as you type:

2018-07-09-10.24.53

Python is our latest language, with support for Python 2.7 through 3.7, including data classes and typing:
Screen-Shot-2018-07-12-at-9.31.48-AM

If you look carefully at the Python above*, you'll notice some subtle sophistications:

  • people is inferred to be a map using a Markov chain that discerns class property names from arbitrary keys
  • fav number is legalized as fav_number, automatically translated to-and-from JSON, and stringified numbers are detected and parsed
  • has friends is inferred as a sometimes-stringified boolean, and is automatically translated from string to bool
  • class is reserved in Python, so it's legalized as person_class and automatically translated
  • born is inferred to be a date and automatically parsed as a datetime
  • nickname is inferred as optional, and expressed as Optional[str]

* quicktype generates additional code to implement the automatic translations, omitted from the screenshot

As you can see, quicktype has evolved into something quite powerful from its simple beginnings.

Thank you!

Thank you for using quicktype and giving us feedback! Nothing motivates us more than interacting with you on Twitter, GitHub, Intercom, or Slack. If you'd like to support our work, please blog, screencast, tweet, or demo quicktype to your friends. 😊

David

David