JSON - Crystal 1.20.1

# module JSON

##
Overview

The JSON module allows parsing and generating JSON documents.

NOTE To use `JSON` or its children, you must explicitly import it with `require "json"`

###
General type-safe interface

The general type-safe interface for parsing JSON is to invoke `T.from_json` on a target type `T` and pass either a `String` or `IO` as an argument.

    require "json"

    json_text = %([1, 2, 3])
    Array(Int32).from_json(json_text) # => [1, 2, 3]

    json_text = %({"x": 1, "y": 2})
    Hash(String, Int32).from_json(json_text) # => {"x" => 1, "y" => 2}

Serializing is achieved by invoking `to_json`, which returns a `String`, or `to_json(io : IO)`, which will stream the JSON to an `IO`.

    require "json"

    [1, 2, 3].to_json            # => "[1,2,3]"
    {"x" => 1, "y" => 2}.to_json # => "{\"x\":1,\"y\":2}"

Most types in the standard library implement these methods. For user-defined types you can define a `self.new(pull : JSON::PullParser)` for parsing and `to_json(builder : JSON::Builder)` for serializing. The following sections show convenient ways to do this using `JSON::Serializable`.

NOTE JSON object keys are always strings but they can still be parsed and deserialized to other types. To deserialize, define a `T.from_json_object_key?(key : String) : T?` method, which can return `nil` if the string can't be parsed into that type. To serialize, define a `to_json_object_key : String` method can be serialized that way. All integer and float types in the standard library can be deserialized that way.

    require "json"

    json_text = %({"1": 2, "3": 4})
    Hash(Int32, Int32).from_json(json_text) # => {1 => 2, 3 => 4}

    {1.5 => 2}.to_json # => "{\"1.5\":2}"

###
Parsing with `JSON.parse`

`JSON.parse` will return an `Any`, which is a convenient wrapper around all possible JSON types, making it easy to traverse a complex JSON structure but requires some casts from time to time, mostly via some method invocations.

    require "json"

    value = JSON.parse("[1, 2, 3]") # : JSON::Any

    value[0]               # => 1
    typeof(value[0])       # => JSON::Any
    value[0].as_i          # => 1
    typeof(value[0].as_i)  # => Int32
    value[0].as_i?         # => 1
    typeof(value[0].as_i?) # => Int32 | Nil
    value[0].as_s?         # => nil
    typeof(value[0].as_s?) # => String | Nil

    value[0] + 1       # Error, because value[0] is JSON::Any
    value[0].as_i + 10 # => 11

`JSON.parse` can read from an `IO` directly (such as a file) which saves allocating a string:

    require "json"

    json = File.open("path/to/file.json") do |file|
      JSON.parse(file)
    end

Parsing with `JSON.parse` is useful for dealing with a dynamic JSON structure.

###
Generating with `JSON.build`

Use `JSON.build`, which uses `JSON::Builder`, to generate JSON by emitting scalars, arrays and objects:

    require "json"

    string = JSON.build do |json|
      json.object do
        json.field "name", "foo"
        json.field "values" do
          json.array do
            json.number 1
            json.number 2
            json.number 3
          end
        end
      end
    end
    string # => %<{"name":"foo","values":[1,2,3]}>

###
Generating with `to_json`

`to_json`, `to_json(IO)` and `to_json(JSON::Builder)` methods are provided for primitive types, but you need to define `to_json(JSON::Builder)` for custom objects, either manually or using `JSON::Serializable`.

##
Defined in:

json.cr
json/builder.cr
json/serialization.cr

##
Class Method Summary

- .build(indent : String | Int | Nil = nil, &)

  Returns the resulting `String` of writing JSON to the yielded `JSON::Builder`.

- .build(io : IO, indent : String | Int | Nil = nil, &) : Nil

  Writes JSON into the given `IO`.

- .parse(input : String | IO) : Any

  Parses a JSON document as a `JSON::Any`.

##
Class Method Detail

def self.build(indent : String | Int | Nil = nil, &) #

Returns the resulting `String` of writing JSON to the yielded `JSON::Builder`.

    require "json"

    string = JSON.build do |json|
      json.object do
        json.field "name", "foo"
        json.field "values" do
          json.array do
            json.number 1
            json.number 2
            json.number 3
          end
        end
      end
    end
    string # => %<{"name":"foo","values":[1,2,3]}>

Accepts an indent parameter which can either be an `Int` (number of spaces to indent) or a `String`, which will prefix each level with the string a corresponding amount of times.

def self.build(io : IO, indent : String | Int | Nil = nil, &) : Nil #

Writes JSON into the given `IO`. A `JSON::Builder` is yielded to the block.

def self.parse(input : String | IO) : Any #

Parses a JSON document as a `JSON::Any`.