-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | json-spec-openapi -- -- This package provides a way to produce openapi3 documentation -- from a json-spec specification. -- --
-- data User = User
-- { name :: Text
-- , lastLogin :: Maybe UTCTime
-- }
-- deriving ToSchema via (EncodingSchema User) -- <-- ToSchema instance defined here
-- instance HasJsonEncodingSpec User where
-- type EncodingSpec User =
-- JsonObject
-- '[ Required "name" JsonString
-- , Optional "last-login" JsonDateTime
-- ]
-- toJSONStructure user =
-- (Field @"name" (name user),
-- (fmap (Field @"last-login") (lastLogin user),
-- ()))
--
--
-- Calling `Data.Aeson.encode (Data.OpenApi3.toSchema (Proxy :: Proxy
-- User))` will produce the following Schema:
--
--
-- {
-- "additionalProperties": false,
-- "properties": {
-- "last-login": {
-- "format": "date-time",
-- "type": "string"
-- },
-- "name": {
-- "type": "string"
-- }
-- },
-- "required": [
-- "name"
-- ],
-- "type": "object"
-- }
--
@package json-spec-openapi
@version 1.0.0.0
-- | This module provides tools for integrating the type-level JSON
-- Specification with the "openapi" package.
--
-- You can use toOpenApiSchema as a low-level tool to transform
-- json-spec Specifications into openapi3
-- Schemas directly, irrespective of any particular business data
-- type.
--
-- More likely you will want to use -XDerivingVia along with
-- EncodingSchema or DecodingSchema to derive
-- ToSchema instances for your data types.
--
-- Example, given this data type:
--
--
-- data User = User
-- { name :: Text
-- , lastLogin :: Maybe UTCTime
-- }
-- deriving ToSchema via (EncodingSchema User) -- <-- ToSchema instance defined here
-- instance HasJsonEncodingSpec User where
-- type EncodingSpec User =
-- JsonObject
-- '[ Required "name" JsonString
-- , Optional "last-login" JsonDateTime
-- ]
-- toJSONStructure user =
-- (Field @"name" (name user),
-- (fmap (Field @"last-login") (lastLogin user),
-- ()))
--
--
-- Calling encode (toSchema (Proxy ::
-- Proxy User)) will produce the following Schema:
--
--
-- {
-- "additionalProperties": false,
-- "properties": {
-- "last-login": {
-- "format": "date-time",
-- "type": "string"
-- },
-- "name": {
-- "type": "string"
-- }
-- },
-- "required": [
-- "name"
-- ],
-- "type": "object"
-- }
--
--
-- If you needed more control over the content of the schema you might
-- also consider doing something like this, e.g. in the case where you
-- would like to allow additional properties:
--
--
-- data User = User
-- { name :: Text
-- , lastLogin :: Maybe UTCTime
-- }
-- instance HasJsonEncodingSpec User where
-- type EncodingSpec User =
-- JsonObject
-- '[ Required "name" JsonString
-- , Optional "last-login" JsonDateTime
-- ]
-- toJSONStructure user =
-- (Field @"name" (name user),
-- (fmap (Field @"last-login") (lastLogin user),
-- ()))
-- instance ToSchema User where
-- declareNamedSchema _proxy =
-- pure $
-- NamedSchema
-- Nothing
-- (
-- toOpenApiSchema (EncodingSpec User)
-- & set
-- additionalProperties
-- (Just (AdditionalPropertiesAllowed True))
-- )
--
module Data.JsonSpec.OpenApi
-- | Convert a Specification into an OpenApi Schema. The type
-- class Schemaable is an internal and opaque implementation
-- detail and not something you should have to worry about.
--
-- It should already have an instance for every Specification that
-- can be turned into a Schema. If it does not, then that is a
-- bug. Please report it! :-)
--
-- The limitations of this function are:
--
-- JsonLet '[ '("foo", ...) ] ( JsonRef "foo"
-- )toOpenApiSchema returns a Schema, not a
-- Referenced Schema. Therefore, if the "top
-- level" of the Specification is a JsonRef, then we will
-- try to dereference and inline the referenced schema. In other
-- words,toOpenApiSchema (Proxy @( JsonLet '[ '("foo", JsonString) ]
-- (JsonRef "foo") ))will behave as if you had
-- calledtoOpenApiSchema (Proxy @( JsonLet '[ '("foo", JsonString) ]
-- JsonString ))However, if the reference is undefined, then you
-- will get a custom type error explaining what the problem is.let
-- (defs, schema) = toOpenApiSchema (Proxy @( JsonObject '[ ("bar",
-- JsonRef "not-defined") ] )) in ...This will compile, and will
-- not throw any runtime errors directly, but depending on how you
-- use defs and schema (like, for instance,
-- generating an OpenApi specification) you will probably encounter a
-- runtime error complaining that "not-defined" hasn't been defined.-- data MyType = ... -- deriving ToSchema via (EncodingSchema MyType) -- instance HasJsonEncodingSchema MyType where -- ... --newtype EncodingSchema a EncodingSchema :: a -> EncodingSchema a [unEncodingSchema] :: EncodingSchema a -> a -- | Helper for defining ToSchema instances based on -- HasJsonDecodingSpec using deriving via. -- -- Example: -- --
-- data MyType = ... -- deriving ToSchema via (DecodingSchema MyType) -- instance HasJsonDecodingSchema MyType where -- ... --newtype DecodingSchema a DecodingSchema :: a -> DecodingSchema a [unDecodingSchema] :: DecodingSchema a -> a -- | Resolve OpenApi name conflicts. -- -- The json-spec mechanism for giving names to things is more powerful -- than OpenApi mechanism for naming things. JsonLet allows for -- nested scopes, where deeper names can shadow other names. OpenApi on -- the other hand only has a flat space to name schemas, so every name is -- "globally scoped", resulting in possible name conflicts when mapping -- JsonLet names to OpenApi names. -- -- This type family resolves the conflict by renaming the JsonLet -- names in your Specification so that they are all unique, so -- they won't conflict when mapping them into the global OpenApi schema -- namespace. -- -- We do not apply this type family by default because it has the -- potential to add significant compilation time if your -- Specifications are large. If you happen to know that your -- Specification contains no name conflicts then you can avoid -- paying that cost. -- -- It isn't perfect. I've tried to strike a balance between -- implementation complexity and avoiding unnecessary renames. -- -- Essentially, if a duplicate name is detected, I append a -- ".n" to the name, where n is an -- integer. So if you are using names that already follow this -- format you might get into trouble. -- -- For instance, this Specification will fail to rename properly: -- > JsonLet > '[ '("foo", JsonString) > , '("foo.1", -- JsonString) > ] > ( JsonObject > '[ "field1" ::: JsonRef -- "foo" > , "field2" ::: JsonLet '[ '("foo", JsonInt)] (JsonRef -- "foo") > ] > ) -- -- because the "foo" in "field2" will be renamed to "foo.1", causing a -- new conflict with the existing "foo.1". type family Rename (spec :: Specification) :: Specification instance (Data.JsonSpec.OpenApi.Defs defs more, Data.JsonSpec.OpenApi.Inlineable defs spec, GHC.Internal.TypeLits.KnownSymbol name) => Data.JsonSpec.OpenApi.Defs defs ('(name, spec) : more) instance Data.JsonSpec.OpenApi.Defs defs '[] instance Data.JsonSpec.OpenApi.Inlineable defs spec => Data.JsonSpec.OpenApi.Deref defs ('(target, spec) : more) target instance Data.JsonSpec.OpenApi.Deref defs more target => Data.JsonSpec.OpenApi.Deref defs ('(miss, spec) : more) target instance Data.JsonSpec.OpenApi.NotDereferenceable defs target => Data.JsonSpec.OpenApi.Deref defs '[] target instance Data.JsonSpec.OpenApi.Refable defs spec => Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonArray spec) instance Data.JsonSpec.OpenApi.Inlineable defs 'Data.JsonSpec.Spec.JsonBool instance Data.JsonSpec.OpenApi.Inlineable defs 'Data.JsonSpec.Spec.JsonDateTime instance (Data.JsonSpec.OpenApi.Refable defs left, Data.JsonSpec.OpenApi.Refable defs right) => Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonEither left right) instance Data.JsonSpec.OpenApi.Inlineable defs 'Data.JsonSpec.Spec.JsonInt instance (Data.JsonSpec.OpenApi.Inlineable (Data.JsonSpec.OpenApi.Concat newDefs defs) spec, Data.JsonSpec.OpenApi.Defs newDefs newDefs) => Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonLet newDefs spec) instance Data.JsonSpec.OpenApi.Refable defs spec => Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonNullable spec) instance Data.JsonSpec.OpenApi.Inlineable defs 'Data.JsonSpec.Spec.JsonNum instance (Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonObject more), Data.JsonSpec.OpenApi.Refable defs spec, GHC.Internal.TypeLits.KnownSymbol key) => Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonObject ('Data.JsonSpec.Spec.Optional key spec : more)) instance Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonObject '[]) instance (Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonObject ('Data.JsonSpec.Spec.Optional key spec : more)), GHC.Internal.TypeLits.KnownSymbol key) => Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonObject ('Data.JsonSpec.Spec.Required key spec : more)) instance Data.JsonSpec.OpenApi.Inlineable defs 'Data.JsonSpec.Spec.JsonRaw instance Data.JsonSpec.OpenApi.Deref defs defs target => Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonRef target) instance Data.JsonSpec.OpenApi.Inlineable defs 'Data.JsonSpec.Spec.JsonString instance GHC.Internal.TypeLits.KnownSymbol tag => Data.JsonSpec.OpenApi.Inlineable defs ('Data.JsonSpec.Spec.JsonTag tag) instance (Data.JsonSpec.OpenApi.Defs newDefs newDefs, Data.JsonSpec.OpenApi.Refable (Data.JsonSpec.OpenApi.Concat newDefs defs) spec) => Data.JsonSpec.OpenApi.Refable defs ('Data.JsonSpec.Spec.JsonLet newDefs spec) instance GHC.Internal.TypeLits.KnownSymbol name => Data.JsonSpec.OpenApi.Refable defs ('Data.JsonSpec.Spec.JsonRef name) instance Data.JsonSpec.OpenApi.Inlineable defs a => Data.JsonSpec.OpenApi.Refable defs a instance Data.JsonSpec.OpenApi.Inlineable '[] spec => Data.JsonSpec.OpenApi.Schemaable spec instance (Data.JsonSpec.OpenApi.Schemaable (Data.JsonSpec.Decode.DecodingSpec a), GHC.Internal.Data.Typeable.Internal.Typeable a) => Data.OpenApi.Internal.Schema.ToSchema (Data.JsonSpec.OpenApi.DecodingSchema a) instance (Data.JsonSpec.OpenApi.Schemaable (Data.JsonSpec.Encode.EncodingSpec a), GHC.Internal.Data.Typeable.Internal.Typeable a) => Data.OpenApi.Internal.Schema.ToSchema (Data.JsonSpec.OpenApi.EncodingSchema a)