$darkmode
schema.hpp File Reference
#include <chrono>
#include <map>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <fable/fable_fwd.hpp>
#include <fable/schema/array.hpp>
#include <fable/schema/boolean.hpp>
#include <fable/schema/confable.hpp>
#include <fable/schema/const.hpp>
#include <fable/schema/duration.hpp>
#include <fable/schema/enum.hpp>
#include <fable/schema/ignore.hpp>
#include <fable/schema/interface.hpp>
#include <fable/schema/json.hpp>
#include <fable/schema/map.hpp>
#include <fable/schema/number.hpp>
#include <fable/schema/optional.hpp>
#include <fable/schema/passthru.hpp>
#include <fable/schema/path.hpp>
#include <fable/schema/string.hpp>
#include <fable/schema/struct.hpp>
#include <fable/schema/variant.hpp>
#include <fable/schema/vector.hpp>
#include <fable/schema/xmagic.hpp>
Include dependency graph for schema.hpp:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  fable::schema_type< T >
 
class  fable::Schema
 

Detailed Description

See also
fable/schema.cpp
fable/schema_test.cpp
fable/confable.hpp

This file includes most types from the schema namespace and defines the Schema type.

Schema is a class that can be used to describe how to set the values of a C++ datatype from a Json. This description can be used to

  • output a JSON Schema,
  • validate a JSON input,
  • deserialize a JSON input,
  • serialize a C++ type to JSON.

The last activity is not necessarily the most effective way to serialize a datatype, as there is quite a lot of indirection involved. However, Schema is designed to be the way to deserialize JSON. It is recommended to do this by making your type derive from Confable. Part of the Confable interface is to provide a Schema, which is then used for validation and deserialization.

There are several ways to define a Schema.

  1. Use Schema interface. The Schema class provides several constructors that take various datatypes and instantiate a correct underlying type. The advantage is that it looks good and doesn't require you to know anything about the underlying types. The great disadvantage is that the type-specific methods can't be used to further refine validation.
  2. Use make_schema functions. These functions can be used to return the underlying types. The advantage is that it looks okay and doesn't require you to know anything about the underlying types. It also returns the underlying types, which means you can use type-specific methods to further refine validation. This is the recommended way to create Schemas. These functions are defined in headers that can be found in the schema/ directory, but have in principle exactly the same syntax as the Schema interface. Thus it is generally possible to simply replace all instances of Schema with make_schema.
  3. Use types in schema namespace. This is kind of ugly but provides you with the most control. Because the types are templated, you often have to be very specific when instantiating a type. These types are defined in headers that can be found in the schema/ directory.

Examples

Given the following type:

struct MyData { std::string host{"localhost"}; uint16_t port{0};

Schema schema_impl(); };

We can implement the schema_impl method in the three ways detailed above.

  1. Using Schema interface:

    Schema MyData::schema_impl() { return Schema{ {"host", Schema(&host, "hostname of connection")}, {"port", Schema(&port, "port of connection")}, }; }

  2. Using make_schema functions:

    Schema MyData::schema_impl() { return make_schema({ {"host", make_schema(&host, "hostname of connection").require()}, {"port", make_schema(&port, "port of connection").minimum(1024)}, }); }

  3. Using types in schema namespace:

    Schema MyData::schema_impl() { using namespace schema; return Struct{ {"host", String(&host, "hostname of connection").require()}, {"port", Number<uint16_t>(&port, "port of connection").minimum(1024)}, }; }

Note that Schema contains pointers to the variables of MyData. The schema is therefore invalidated whenever MyData is moved or copied. The Confable type takes care of these issues to ensure that you don't shoot yourself in the foot.