{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# OPTIONS_GHC -XNoCPP #-}
module Data.API.API.DSL
( apiAPI
) where
import Data.API.Parse
import Data.API.Types
apiAPI :: API
apiAPI :: API
apiAPI = [api|
//
// #The api-tools API
//
// Here we make the DSP specs available in JSON so that clients
// working in non-Haskell frameworks can integrate API
// specs into their own environments.
ans :: APISpec
// an API specification consists of a list of nodes,
// each describing a named JSON thing which can be
// referenced in other (object) nodes.
= [APINode]
an :: APINode
// Each node is named (with a name that conforms to Haskell's
// Type identifier rules, starting with a capital letter) and some
// comment text (like this comment). The JSON spec is all contained
// in the {Spec}, the other fields being used behind the scenes
// to manage the Haskell name space and migrations.
= record
name :: string // the name must start with a big letter
// and conform to Haskell rules for type
// identifiers
comment :: string // natural language description of the node
prefix :: string // (Haskell side only) this prefix used to
// structure the Haskell name space
// (which is uncomfortably flat where
// record field names are concerned);
// it has no effect on the JSON representation
spec :: Spec // here we specify the JSON representation
convert :: ? Conversion // (Haskell side only) sometimes we may
// choose to not use the default internal
// representation for the JSON
// but instead supply a couple of functions
// for injecting the default representation
// into the actual type we will use and the
// and project it back again; here we can check
// some properties (which must be explained
// in the comments) and reject a request
// with a 400 error; has no effect on the
// JSON representation
sp :: Spec
// the JSON representation is specified as a simple 'newtype', a record
// type, a union type, an enumerated type or a (mere) type synonym.
= union
| newtype :: SpecNewtype // here we have a basic string or number type
| 'record' :: [Field] // an object representing a record
| 'union' :: [Field] // an object representing a number of alternatives
| 'enum' :: [string] // a string type which must contain a number of
// discrete values
| synonym :: APIType // is just an alias for another type
sn :: SpecNewtype
// 'newtype' specs are a basic type and an optional filter specification
= record
type :: BasicType
filter :: ? Filter
ft :: Filter
= union
| 'string' :: RegularExpression
| 'integer' :: IntRange
| 'utc' :: UTCRange
re :: RegularExpression
// regular expressions are represented by simple strings
= basic string
ir :: IntRange
// integer ranges are specified with their bounds and may open at
// the bottom and top
= record
lo :: ? integer
hi :: ? integer
ur :: UTCRange
// UTC ranges are specified with their bounds and may open at
// the bottom and top
= record
lo :: ? utc
hi :: ? utc
cv :: Conversion
// Conversions are just used on the Haskell side to map the concrete JSON
// representation into an internal type and back again
= record
injection :: string // the injection function for injecting
// representations into the internal
// representation; may return a failure
// indicating that some API precondition
// was not met
projection:: string // the projection function converts the
// internal type back into the JSON
// representation for communication
// back to the client
fd :: Field
// a field represent both a field in a record object and an alternative in
// a union object (in which exactly one of the 'fields' is ever present in
// the object)
= record
name :: string // the name of the method
type :: APIType // the JSON type of the field
readonly :: boolean // read-only status
default :: ? DefaultValue // the default value of the field
comment :: string // a comment describing the field (like
// this one)
ty :: APIType
// this is used to represent JSON types in fields (or synonyms) and is one
// one of the following:
= union
| list :: APIType // a JSON list of the given type
| maybe :: APIType // either the given type or the null value
| ref :: TypeRef // a named type (node) with possible example
| 'basic':: BasicType // a basic JSON type
| 'json' :: integer // a generic JSON value
tr :: TypeRef
// reference to a type name
= basic string
bt :: BasicType
// finally we get down to the basic JSON types ('binary' is a string
// in which the byte string has been encoded with base-64, safe for
// embedding in a UTF-8-encoded JSON string
= enum
| 'string'
| 'binary'
| 'boolean'
| 'integer'
| 'utc'
dv :: DefaultValue
// a default value
= union
| 'list' :: integer
| 'maybe' :: integer
| 'string' :: string
| 'boolean' :: boolean
| 'integer' :: integer
| 'utc' :: utc
|]