Safe Haskell | Safe-Inferred |
---|---|
Language | GHC2021 |
Combinator library for defining bidirectional JSON encodings with associated Swagger schemas.
Documentation on the organisation of this library and a tutorial
can be found in README.md
.
Synopsis
- data SchemaP doc v w a b
- type ValueSchema doc a = ValueSchemaP doc a a
- type ValueSchemaP doc = SchemaP doc Value Value
- type ObjectSchema doc a = ObjectSchemaP doc a a
- type ObjectSchemaP doc = SchemaP doc Object [Pair]
- class ToSchema a where
- newtype Schema a = Schema {
- getSchema :: a
- mkSchema :: doc -> (v -> Parser b) -> (a -> Maybe w) -> SchemaP doc v w a b
- schemaDoc :: SchemaP ss v m a b -> ss
- schemaIn :: SchemaP doc v v' a b -> v -> Parser b
- schemaOut :: SchemaP ss v m a b -> a -> Maybe m
- class HasDoc a a' doc doc' | a a' -> doc doc' where
- doc' :: Lens' (SchemaP doc v w a b) doc
- class HasSchemaRef doc where
- schemaRef :: doc -> WithDeclare (Referenced Schema)
- class Monoid doc => HasObject doc ndoc | doc -> ndoc, ndoc -> doc where
- mkObject :: Text -> doc -> ndoc
- unmkObject :: ndoc -> doc
- class Monoid doc => HasField ndoc doc | ndoc -> doc where
- withParser :: SchemaP doc v w a b -> (b -> Parser b') -> SchemaP doc v w a b'
- type SwaggerDoc = WithDeclare Schema
- swaggerDoc :: forall a. ToSchema a => NamedSwaggerDoc
- type NamedSwaggerDoc = WithDeclare NamedSchema
- data WithDeclare s
- declareSwaggerSchema :: SchemaP (WithDeclare d) v w a b -> Declare d
- getName :: HasName doc => doc -> Maybe Text
- object :: HasObject doc doc' => Text -> SchemaP doc Object [Pair] a b -> SchemaP doc' Value Value a b
- objectWithDocModifier :: HasObject doc doc' => Text -> (doc' -> doc') -> ObjectSchema doc a -> ValueSchema doc' a
- objectOver :: HasObject doc doc' => Lens v v' Value Object -> Text -> SchemaP doc v' [Pair] a b -> SchemaP doc' v Value a b
- jsonObject :: ValueSchema SwaggerDoc Object
- jsonValue :: ValueSchema SwaggerDoc Value
- class Functor f => FieldFunctor doc f where
- field :: forall doc' doc a b. HasField doc' doc => Text -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a b
- fieldWithDocModifier :: forall doc' doc a b. HasField doc' doc => Text -> (doc' -> doc') -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a b
- fieldOver :: forall doc' doc v v' a b. HasField doc' doc => Lens v v' Object Value -> Text -> SchemaP doc' v' Value a b -> SchemaP doc v [Pair] a b
- optField :: forall doc doc' a b. (HasOpt doc, HasField doc' doc) => Text -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a (Maybe b)
- optFieldWithDocModifier :: forall doc doc' a b. (HasOpt doc, HasField doc' doc) => Text -> (doc' -> doc') -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a (Maybe b)
- fieldF :: forall doc' doc f a b. (HasField doc' doc, FieldFunctor doc f) => Text -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a (f b)
- fieldOverF :: forall f doc' doc v v' a b. (HasField doc' doc, FieldFunctor doc f) => Lens v v' Object Value -> Text -> SchemaP doc' v' Value a b -> SchemaP doc v [Pair] a (f b)
- fieldWithDocModifierF :: forall doc' doc f a b. (HasField doc' doc, FieldFunctor doc f) => Text -> (doc' -> doc') -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a (f b)
- array :: (HasArray ndoc doc, HasName ndoc) => ValueSchema ndoc a -> ValueSchema doc [a]
- set :: (HasArray ndoc doc, HasName ndoc, Ord a) => ValueSchema ndoc a -> ValueSchema doc (Set a)
- nonEmptyArray :: (HasArray ndoc doc, HasName ndoc, HasMinItems doc (Maybe Integer)) => ValueSchema ndoc a -> ValueSchema doc (NonEmpty a)
- map_ :: forall ndoc doc k a. (HasMap ndoc doc, Ord k, FromJSONKey k, ToJSONKey k) => ValueSchema ndoc a -> ValueSchema doc (Map k a)
- mapWithKeys :: forall ndoc doc k a. (HasMap ndoc doc, Ord k) => (k -> Text) -> (Text -> k) -> ValueSchema ndoc a -> ValueSchema doc (Map k a)
- enum :: forall v doc a b. (With v, HasEnum v doc) => Text -> SchemaP [Value] v (Alt Maybe v) a b -> SchemaP doc Value Value a b
- maybe_ :: Monoid w => SchemaP d v w a b -> SchemaP d v w (Maybe a) b
- maybeWithDefault :: w -> SchemaP d v w a b -> SchemaP d v w (Maybe a) b
- bind :: (Monoid d, Monoid w) => SchemaP d v w a b -> SchemaP d (v, b) w a c -> SchemaP d v w a (b, c)
- dispatch :: (Bounded t, Enum t, Monoid d) => (t -> SchemaP d v w a b) -> SchemaP d (v, t) w a b
- text :: Text -> ValueSchema NamedSwaggerDoc Text
- parsedText :: Text -> (Text -> Either String a) -> SchemaP NamedSwaggerDoc Value Value Text a
- null_ :: Monoid d => ValueSchemaP d () ()
- nullable :: Monoid d => ValueSchema d a -> ValueSchema d (Maybe a)
- element :: forall a b. (ToJSON a, Eq a, Eq b) => a -> b -> SchemaP [Value] a (Alt Maybe a) b b
- tag :: Prism b b' a a' -> SchemaP ss v m a a' -> SchemaP ss v m b b'
- unnamed :: HasObject doc doc' => SchemaP doc' v m a b -> SchemaP doc v m a b
- named :: HasObject doc doc' => Text -> SchemaP doc v m a b -> SchemaP doc' v m a b
- (.=) :: Profunctor p => (a -> a') -> p a' b -> p a b
- schemaToSwagger :: forall a. ToSchema a => Proxy a -> Declare NamedSchema
- schemaToJSON :: forall a. ToSchema a => a -> Value
- schemaParseJSON :: forall a. ToSchema a => Value -> Parser a
- genericToSchema :: forall a. (ToSchema a, ToJSON a, FromJSON a) => ValueSchema NamedSwaggerDoc a
- description :: HasDescription s a => Lens' s a
Documentation
data SchemaP doc v w a b Source #
A combined JSON encoder-decoder with associated documentation.
A value of type 'SchemaP d v w a b', which we will refer to as a schema, contains both a JSON parser and a JSON serialiser, together with documentation-like metadata, such as a JSON or Swagger schema.
The type variables are as follows:
d
- documentation type, usually a
Monoid
. v
- type of JSON values being parsed (e.g.
Value
). w
- type of JSON values being serialised (e.g.
Value
). a
- input type
b
- output type
Input and output types deserve some more explanation. We can think
of a value sch
of type 'SchemaP d v w a b' as a kind of special
"function" from a
to b
, but where a
and b
might potentially
live in different "languages". The parser portion of sch
takes a
JSON-encoded value of type a
and produces a value of type b
,
while the serialiser portion of sch
takes a haskell value of type
a
and produces a JSON-encoding of something of type b
.
In terms of composability, this way of representing schemas (based on input and output types) is superior to the perhaps more natural approach of using "bidirectional functions" or isomorphisms (based on a single type parameter).
Although schemas cannot be composed as functions (i.e. they do not
form a Category
), they still admit a number of important and
useful instances, such as Profunctor
(and specifically Choice
),
which makes it possible to use prism quite effectively to build
schema values.
Using type variables to represent JSON types might seem like
excessive generality, but it is useful to represent "intermediate"
schemas arising when building complex ones. For example, a schema
which is able to work with fields of a JSON object (see field
)
should not output full-blown objects, but only lists of pairs, so
that they can be combined correctly via the usual Monoid
structure of lists when using the Applicative
interface of
'SchemaP d v w a b'.
The idea of using the profunctor structure of SchemaP
is taken
from the codec library.
Instances
Choice (SchemaP doc v v') Source # | |
Profunctor (SchemaP doc v v') Source # | |
Defined in Data.Schema dimap :: (a -> b) -> (c -> d) -> SchemaP doc v v' b c -> SchemaP doc v v' a d Source # lmap :: (a -> b) -> SchemaP doc v v' b c -> SchemaP doc v v' a c Source # rmap :: (b -> c) -> SchemaP doc v v' a b -> SchemaP doc v v' a c Source # (#.) :: forall a b c q. Coercible c b => q b c -> SchemaP doc v v' a b -> SchemaP doc v v' a c Source # (.#) :: forall a b c q. Coercible b a => SchemaP doc v v' b c -> q a b -> SchemaP doc v v' a c Source # | |
(NearSemiRing doc, Monoid v') => Alternative (SchemaP doc v v' a) Source # | |
(Monoid doc, Monoid v') => Applicative (SchemaP doc v v' a) Source # | |
Defined in Data.Schema pure :: a0 -> SchemaP doc v v' a a0 # (<*>) :: SchemaP doc v v' a (a0 -> b) -> SchemaP doc v v' a a0 -> SchemaP doc v v' a b # liftA2 :: (a0 -> b -> c) -> SchemaP doc v v' a a0 -> SchemaP doc v v' a b -> SchemaP doc v v' a c # (*>) :: SchemaP doc v v' a a0 -> SchemaP doc v v' a b -> SchemaP doc v v' a b # (<*) :: SchemaP doc v v' a a0 -> SchemaP doc v v' a b -> SchemaP doc v v' a a0 # | |
Functor (SchemaP doc v w a) Source # | |
Monoid doc => Monoid (SchemaP doc v v' a b) Source # | |
Semigroup doc => Semigroup (SchemaP doc v v' a b) Source # | |
HasSchema d Schema => HasSchema (SchemaP d v w a b) Schema Source # | |
HasDoc (SchemaP doc v v' a b) (SchemaP doc' v v' a b) doc doc' Source # | |
type ValueSchema doc a = ValueSchemaP doc a a Source #
type ObjectSchema doc a = ObjectSchemaP doc a a Source #
class ToSchema a where Source #
A type with a canonical typed schema definition.
Using ToSchema, one can split a complicated shema definition
into manageable parts by defining instances for the various types
involved, and using the schema
method to reuse the
previously-defined schema definitions for component types.
Instances
ToSchema Int32 Source # | |
Defined in Data.Schema | |
ToSchema Int64 Source # | |
Defined in Data.Schema | |
ToSchema Word16 Source # | |
Defined in Data.Schema | |
ToSchema Word32 Source # | |
Defined in Data.Schema | |
ToSchema Word64 Source # | |
Defined in Data.Schema | |
ToSchema Word8 Source # | |
Defined in Data.Schema | |
ToSchema Text Source # | |
Defined in Data.Schema | |
ToSchema Text Source # | |
Defined in Data.Schema | |
ToSchema String Source # | |
Defined in Data.Schema | |
ToSchema Integer Source # | |
Defined in Data.Schema | |
ToSchema Natural Source # | |
Defined in Data.Schema | |
ToSchema Bool Source # | |
Defined in Data.Schema | |
ToSchema Char Source # | |
Defined in Data.Schema | |
ToSchema Int Source # | |
Defined in Data.Schema | |
ToSchema Word Source # | |
Defined in Data.Schema |
Instances
ToSchema a => FromJSON (Schema a) Source # | |
ToSchema a => ToJSON (Schema a) Source # | |
Generic (Schema a) Source # | |
(Typeable a, ToSchema a) => ToSchema (Schema a) Source # | |
Defined in Data.Schema declareNamedSchema :: Proxy (Schema a) -> Declare (Definitions Schema0) NamedSchema Source # | |
type Rep (Schema a) Source # | |
Defined in Data.Schema |
mkSchema :: doc -> (v -> Parser b) -> (a -> Maybe w) -> SchemaP doc v w a b Source #
Build a schema from documentation, parser and serialiser
class HasSchemaRef doc where Source #
schemaRef :: doc -> WithDeclare (Referenced Schema) Source #
Instances
HasSchemaRef NamedSwaggerDoc Source # | |
Defined in Data.Schema | |
HasSchemaRef SwaggerDoc Source # | |
Defined in Data.Schema schemaRef :: SwaggerDoc -> WithDeclare (Referenced Schema) Source # |
class Monoid doc => HasObject doc ndoc | doc -> ndoc, ndoc -> doc where Source #
Instances
HasObject SwaggerDoc NamedSwaggerDoc Source # | |
Defined in Data.Schema mkObject :: Text -> SwaggerDoc -> NamedSwaggerDoc Source # |
class Monoid doc => HasField ndoc doc | ndoc -> doc where Source #
Instances
HasSchemaRef doc => HasField doc SwaggerDoc Source # | |
Defined in Data.Schema mkField :: Text -> doc -> SwaggerDoc Source # |
type SwaggerDoc = WithDeclare Schema Source #
swaggerDoc :: forall a. ToSchema a => NamedSwaggerDoc Source #
type NamedSwaggerDoc = WithDeclare NamedSchema Source #
data WithDeclare s Source #
Instances
declareSwaggerSchema :: SchemaP (WithDeclare d) v w a b -> Declare d Source #
object :: HasObject doc doc' => Text -> SchemaP doc Object [Pair] a b -> SchemaP doc' Value Value a b Source #
A schema for a JSON object.
This can be used to convert a combination of schemas obtained using
field
into a single schema for a JSON object.
objectWithDocModifier :: HasObject doc doc' => Text -> (doc' -> doc') -> ObjectSchema doc a -> ValueSchema doc' a Source #
Like object
, but apply an arbitrary function to the
documentation of the resulting object.
objectOver :: HasObject doc doc' => Lens v v' Value Object -> Text -> SchemaP doc v' [Pair] a b -> SchemaP doc' v Value a b Source #
jsonObject :: ValueSchema SwaggerDoc Object Source #
A schema for an arbitrary JSON object.
jsonValue :: ValueSchema SwaggerDoc Value Source #
A schema for an arbitrary JSON value.
class Functor f => FieldFunctor doc f where Source #
Instances
FieldFunctor doc Identity Source # | |
HasOpt doc => FieldFunctor doc Maybe Source # | |
field :: forall doc' doc a b. HasField doc' doc => Text -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a b Source #
A schema for a one-field JSON object.
fieldWithDocModifier :: forall doc' doc a b. HasField doc' doc => Text -> (doc' -> doc') -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a b Source #
Like field
, but apply an arbitrary function to the
documentation of the field.
fieldOver :: forall doc' doc v v' a b. HasField doc' doc => Lens v v' Object Value -> Text -> SchemaP doc' v' Value a b -> SchemaP doc v [Pair] a b Source #
Like fieldOverF
, but specialised to the identity functor.
optField :: forall doc doc' a b. (HasOpt doc, HasField doc' doc) => Text -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a (Maybe b) Source #
A schema for a JSON object with a single optional field.
optFieldWithDocModifier :: forall doc doc' a b. (HasOpt doc, HasField doc' doc) => Text -> (doc' -> doc') -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a (Maybe b) Source #
Like optField
, but apply an arbitrary function to the
documentation of the field.
fieldF :: forall doc' doc f a b. (HasField doc' doc, FieldFunctor doc f) => Text -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a (f b) Source #
Generalization of optField
with FieldFunctor
.
fieldOverF :: forall f doc' doc v v' a b. (HasField doc' doc, FieldFunctor doc f) => Lens v v' Object Value -> Text -> SchemaP doc' v' Value a b -> SchemaP doc v [Pair] a (f b) Source #
fieldWithDocModifierF :: forall doc' doc f a b. (HasField doc' doc, FieldFunctor doc f) => Text -> (doc' -> doc') -> SchemaP doc' Value Value a b -> SchemaP doc Object [Pair] a (f b) Source #
Like fieldF
, but apply an arbitrary function to the
documentation of the field.
array :: (HasArray ndoc doc, HasName ndoc) => ValueSchema ndoc a -> ValueSchema doc [a] Source #
A schema for a JSON array.
set :: (HasArray ndoc doc, HasName ndoc, Ord a) => ValueSchema ndoc a -> ValueSchema doc (Set a) Source #
nonEmptyArray :: (HasArray ndoc doc, HasName ndoc, HasMinItems doc (Maybe Integer)) => ValueSchema ndoc a -> ValueSchema doc (NonEmpty a) Source #
map_ :: forall ndoc doc k a. (HasMap ndoc doc, Ord k, FromJSONKey k, ToJSONKey k) => ValueSchema ndoc a -> ValueSchema doc (Map k a) Source #
A schema for a JSON object with arbitrary keys of type k
. The type of
keys must have instances for FromJSONKey
and ToJSONKey
.
Use mapWithKeys
for key types that do not have such instances.
mapWithKeys :: forall ndoc doc k a. (HasMap ndoc doc, Ord k) => (k -> Text) -> (Text -> k) -> ValueSchema ndoc a -> ValueSchema doc (Map k a) Source #
A schema for a JSON object with arbitrary keys of type k
, where k
can
be converted to and from Text
.
enum :: forall v doc a b. (With v, HasEnum v doc) => Text -> SchemaP [Value] v (Alt Maybe v) a b -> SchemaP doc Value Value a b Source #
A schema for a JSON enumeration.
This is used to convert a combination of schemas obtained using
element
into a single schema for a JSON string.
maybe_ :: Monoid w => SchemaP d v w a b -> SchemaP d v w (Maybe a) b Source #
A schema for Maybe
that omits a field on serialisation.
This is most commonly used for optional fields, and it will cause the field to be omitted from the output of the serialiser.
maybeWithDefault :: w -> SchemaP d v w a b -> SchemaP d v w (Maybe a) b Source #
A schema for Maybe
, producing the given default value on serialisation.
bind :: (Monoid d, Monoid w) => SchemaP d v w a b -> SchemaP d (v, b) w a c -> SchemaP d v w a (b, c) Source #
A schema depending on a parsed value.
Even though SchemaP
does not expose a monadic interface, it is possible to
make the parser of a schema depend on the values parsed by a previous
schema.
For example, a schema for an object containing a "type" field which
determines how the rest of the object is parsed. To construct the schema to
use as the second argument of bind
, one can use dispatch
.
dispatch :: (Bounded t, Enum t, Monoid d) => (t -> SchemaP d v w a b) -> SchemaP d (v, t) w a b Source #
A union of schemas over a finite type of "tags".
Normally used together with bind
to construct schemas that depend on some
"tag" value.
text :: Text -> ValueSchema NamedSwaggerDoc Text Source #
A schema for a textual value.
parsedText :: Text -> (Text -> Either String a) -> SchemaP NamedSwaggerDoc Value Value Text a Source #
A schema for a textual value with possible failure.
null_ :: Monoid d => ValueSchemaP d () () Source #
A schema for a null value.
nullable :: Monoid d => ValueSchema d a -> ValueSchema d (Maybe a) Source #
A schema for a nullable value.
The parser accepts a JSON null as a valid value, and converts it to
Nothing
. Any non-null value is parsed using the underlying schema.
The serialiser behaves similarly, but in the other direction.
element :: forall a b. (ToJSON a, Eq a, Eq b) => a -> b -> SchemaP [Value] a (Alt Maybe a) b b Source #
A schema for a single value of an enumeration.
tag :: Prism b b' a a' -> SchemaP ss v m a a' -> SchemaP ss v m b b' Source #
Change the input and output types of a schema via a prism.
unnamed :: HasObject doc doc' => SchemaP doc' v m a b -> SchemaP doc v m a b Source #
Turn a named schema into an unnamed one.
This is mostly useful when using a schema as a field of a bigger schema. If the inner schema is unnamed, it gets "inlined" in the larger scheme definition, and otherwise it gets "referenced". This combinator makes it possible to choose one of the two options.
named :: HasObject doc doc' => Text -> SchemaP doc v m a b -> SchemaP doc' v m a b Source #
Attach a name to a schema.
This only affects the documentation portion of a schema, and not the parsing or serialisation.
(.=) :: Profunctor p => (a -> a') -> p a' b -> p a b Source #
Change the input type of a schema.
schemaToSwagger :: forall a. ToSchema a => Proxy a -> Declare NamedSchema Source #
schemaToJSON :: forall a. ToSchema a => a -> Value Source #
JSON serialiser for an instance of ToSchema
.
schemaParseJSON :: forall a. ToSchema a => Value -> Parser a Source #
JSON parser for an instance of ToSchema
.
genericToSchema :: forall a. (ToSchema a, ToJSON a, FromJSON a) => ValueSchema NamedSwaggerDoc a Source #
description :: HasDescription s a => Lens' s a Source #