servant-0.11: A family of combinators for defining webservices APIs

Safe Haskell | None
Language | Haskell2010

Servant.API.ContentTypes

Contents

- Provided Content-Types
- Building your own Content-Type
- NoContent
- Internal

Description

A collection of basic Content-Types (also known as Internet Media Types, or MIME types). Additionally, this module provides classes that encapsulate how to serialize or deserialize values to or from a particular Content-Type.

Content-Types are used in `ReqBody` and the method combinators:

    >>> type MyEndpoint = ReqBody '[JSON, PlainText] Book :> Get '[JSON, PlainText] Book

Meaning the endpoint accepts requests of Content-Type `application/json` or `text/plain;charset-utf8`, and returns data in either one of those formats (depending on the `Accept` header).

If you would like to support Content-Types beyond those provided here, then:

1. Declare a new data type with no constructors (e.g. `data HTML`).
2. Make an instance of it for `Accept`.
3. If you want to be able to serialize data *into* that Content-Type, make an instance of it for `MimeRender`.
4. If you want to be able to deserialize data *from* that Content-Type, make an instance of it for `MimeUnrender`.

Note that roles are reversed in `servant-server` and `servant-client`: to be able to serve (or even typecheck) a `Get '[JSON, XML] MyData`, you'll need to have the appropriate `MimeRender` instances in scope, whereas to query that endpoint with `servant-client`, you'll need a `MimeUnrender` instance in scope.

Synopsis

- data JSON
- data PlainText
- data FormUrlEncoded
- data OctetStream
- class Accept ctype where
- class Accept ctype => MimeRender ctype a where
- class Accept ctype => MimeUnrender ctype a where
- data NoContent = NoContent
- newtype AcceptHeader = AcceptHeader ByteString
- class AllMime list => AllCTRender list a where
- class AllCTUnrender list a where
- class AllMime list where
- class AllMime list => AllMimeRender list a where
- class AllMime list => AllMimeUnrender list a where
- eitherDecodeLenient :: FromJSON a => ByteString -> Either String a
- canHandleAcceptH :: AllMime list => Proxy list -> AcceptHeader -> Bool

# Provided Content-Types

data JSON Source #

Instances

Accept * JSON Source #

    application/json

Methods contentType :: Proxy JSON ctype -> MediaType Source # contentTypes :: Proxy JSON ctype -> NonEmpty MediaType Source #
FromJSON a => MimeUnrender * JSON a Source # | `eitherDecode`
Methods mimeUnrender :: Proxy JSON a -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy JSON a -> MediaType -> ByteString -> Either String a Source #
ToJSON a => MimeRender * JSON a Source # | `encode`
Methods mimeRender :: Proxy JSON a -> a -> ByteString Source #

data PlainText Source #

Instances

Accept * PlainText Source #

    text/plain;charset=utf-8

Methods contentType :: Proxy PlainText ctype -> MediaType Source # contentTypes :: Proxy PlainText ctype -> NonEmpty MediaType Source #

MimeUnrender * PlainText String Source #

    Right . BC.unpack

Methods mimeUnrender :: Proxy PlainText String -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy PlainText String -> MediaType -> ByteString -> Either String a Source #

MimeUnrender * PlainText Text Source #

    left show . TextS.decodeUtf8' . toStrict

Methods mimeUnrender :: Proxy PlainText Text -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy PlainText Text -> MediaType -> ByteString -> Either String a Source #

MimeUnrender * PlainText Text Source #

    left show . TextL.decodeUtf8'

Methods mimeUnrender :: Proxy PlainText Text -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy PlainText Text -> MediaType -> ByteString -> Either String a Source #

MimeRender * PlainText String Source #

    BC.pack

Methods mimeRender :: Proxy PlainText String -> a -> ByteString Source #

MimeRender * PlainText Text Source #

    fromStrict . TextS.encodeUtf8

Methods mimeRender :: Proxy PlainText Text -> a -> ByteString Source #
MimeRender * PlainText Text Source # | `encodeUtf8`
Methods mimeRender :: Proxy PlainText Text -> a -> ByteString Source #

data FormUrlEncoded Source #

Instances

Accept * FormUrlEncoded Source #

    application/x-www-form-urlencoded

Methods contentType :: Proxy FormUrlEncoded ctype -> MediaType Source # contentTypes :: Proxy FormUrlEncoded ctype -> NonEmpty MediaType Source #
FromForm a => MimeUnrender * FormUrlEncoded a Source # | `urlDecodeAsForm` Note that the `mimeUnrender p (mimeRender p x) == Right x` law only holds if every element of x is non-null (i.e., not `("", "")`)
Methods mimeUnrender :: Proxy FormUrlEncoded a -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy FormUrlEncoded a -> MediaType -> ByteString -> Either String a Source #
ToForm a => MimeRender * FormUrlEncoded a Source # | `urlEncodeAsForm` Note that the `mimeUnrender p (mimeRender p x) == Right x` law only holds if every element of x is non-null (i.e., not `("", "")`)
Methods mimeRender :: Proxy FormUrlEncoded a -> a -> ByteString Source #

data OctetStream Source #

Instances

Accept * OctetStream Source #

    application/octet-stream

Methods contentType :: Proxy OctetStream ctype -> MediaType Source # contentTypes :: Proxy OctetStream ctype -> NonEmpty MediaType Source #

MimeUnrender * OctetStream ByteString Source #

    Right . toStrict

Methods mimeUnrender :: Proxy OctetStream ByteString -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy OctetStream ByteString -> MediaType -> ByteString -> Either String a Source #

MimeUnrender * OctetStream ByteString Source #

    Right . id

Methods mimeUnrender :: Proxy OctetStream ByteString -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy OctetStream ByteString -> MediaType -> ByteString -> Either String a Source #
MimeRender * OctetStream ByteString Source # | `fromStrict`
Methods mimeRender :: Proxy OctetStream ByteString -> a -> ByteString Source #

MimeRender * OctetStream ByteString Source #

    id

Methods mimeRender :: Proxy OctetStream ByteString -> a -> ByteString Source #

# Building your own Content-Type

class Accept ctype where Source #

Instances of `Accept` represent mimetypes. They are used for matching against the `Accept` HTTP header of the request, and for setting the `Content-Type` header of the response

Example:

    >>> import Network.HTTP.Media ((//), (/:))
    >>> data HTML
    >>> :{
    instance Accept HTML where
       contentType _ = "text" // "html" /: ("charset", "utf-8")
    :}

Minimal complete definition

contentType | contentTypes

Methods

contentType :: Proxy ctype -> MediaType Source #

contentTypes :: Proxy ctype -> NonEmpty MediaType Source #

Instances

Accept * OctetStream Source #

    application/octet-stream

Methods contentType :: Proxy OctetStream ctype -> MediaType Source # contentTypes :: Proxy OctetStream ctype -> NonEmpty MediaType Source #

Accept * FormUrlEncoded Source #

    application/x-www-form-urlencoded

Methods contentType :: Proxy FormUrlEncoded ctype -> MediaType Source # contentTypes :: Proxy FormUrlEncoded ctype -> NonEmpty MediaType Source #

Accept * PlainText Source #

    text/plain;charset=utf-8

Methods contentType :: Proxy PlainText ctype -> MediaType Source # contentTypes :: Proxy PlainText ctype -> NonEmpty MediaType Source #

Accept * JSON Source #

    application/json

Methods contentType :: Proxy JSON ctype -> MediaType Source # contentTypes :: Proxy JSON ctype -> NonEmpty MediaType Source #

class Accept ctype => MimeRender ctype a where Source #

Instantiate this class to register a way of serializing a type based on the `Accept` header.

Example:

    data MyContentType

    instance Accept MyContentType where
       contentType _ = "example" // "prs.me.mine" /: ("charset", "utf-8")

    instance Show a => MimeRender MyContentType a where
       mimeRender _ val = pack ("This is MINE! " ++ show val)

    type MyAPI = "path" :> Get '[MyContentType] Int

Minimal complete definition

mimeRender

Methods

mimeRender :: Proxy ctype -> a -> ByteString Source #

Instances

MimeRender * OctetStream ByteString Source # | `fromStrict`
Methods mimeRender :: Proxy OctetStream ByteString -> a -> ByteString Source #

MimeRender * OctetStream ByteString Source #

    id

Methods mimeRender :: Proxy OctetStream ByteString -> a -> ByteString Source #
ToForm a => MimeRender * FormUrlEncoded a Source # | `urlEncodeAsForm` Note that the `mimeUnrender p (mimeRender p x) == Right x` law only holds if every element of x is non-null (i.e., not `("", "")`)
Methods mimeRender :: Proxy FormUrlEncoded a -> a -> ByteString Source #

MimeRender * PlainText String Source #

    BC.pack

Methods mimeRender :: Proxy PlainText String -> a -> ByteString Source #

MimeRender * PlainText Text Source #

    fromStrict . TextS.encodeUtf8

Methods mimeRender :: Proxy PlainText Text -> a -> ByteString Source #
MimeRender * PlainText Text Source # | `encodeUtf8`
Methods mimeRender :: Proxy PlainText Text -> a -> ByteString Source #
ToJSON a => MimeRender * JSON a Source # | `encode`
Methods mimeRender :: Proxy JSON a -> a -> ByteString Source #

class Accept ctype => MimeUnrender ctype a where Source #

Instantiate this class to register a way of deserializing a type based on the request's `Content-Type` header.

    >>> import Network.HTTP.Media hiding (Accept)
    >>> import qualified Data.ByteString.Lazy.Char8 as BSC
    >>> data MyContentType = MyContentType String

    >>> :{
    instance Accept MyContentType where
       contentType _ = "example" // "prs.me.mine" /: ("charset", "utf-8")
    :}

    >>> :{
    instance Read a => MimeUnrender MyContentType a where
       mimeUnrender _ bs = case BSC.take 12 bs of
         "MyContentType" -> return . read . BSC.unpack $ BSC.drop 12 bs
         _ -> Left "didn't start with the magic incantation"
    :}

    >>> type MyAPI = "path" :> ReqBody '[MyContentType] Int :> Get '[JSON] Int

Minimal complete definition

mimeUnrender | mimeUnrenderWithType

Methods

mimeUnrender :: Proxy ctype -> ByteString -> Either String a Source #

mimeUnrenderWithType :: Proxy ctype -> MediaType -> ByteString -> Either String a Source #

Variant which is given the actual `MediaType` provided by the other party.

In the most cases you don't want to branch based on the `MediaType`. See pr552 for a motivating example.

Instances

MimeUnrender * OctetStream ByteString Source #

    Right . toStrict

Methods mimeUnrender :: Proxy OctetStream ByteString -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy OctetStream ByteString -> MediaType -> ByteString -> Either String a Source #

MimeUnrender * OctetStream ByteString Source #

    Right . id

Methods mimeUnrender :: Proxy OctetStream ByteString -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy OctetStream ByteString -> MediaType -> ByteString -> Either String a Source #
FromForm a => MimeUnrender * FormUrlEncoded a Source # | `urlDecodeAsForm` Note that the `mimeUnrender p (mimeRender p x) == Right x` law only holds if every element of x is non-null (i.e., not `("", "")`)
Methods mimeUnrender :: Proxy FormUrlEncoded a -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy FormUrlEncoded a -> MediaType -> ByteString -> Either String a Source #

MimeUnrender * PlainText String Source #

    Right . BC.unpack

Methods mimeUnrender :: Proxy PlainText String -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy PlainText String -> MediaType -> ByteString -> Either String a Source #

MimeUnrender * PlainText Text Source #

    left show . TextS.decodeUtf8' . toStrict

Methods mimeUnrender :: Proxy PlainText Text -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy PlainText Text -> MediaType -> ByteString -> Either String a Source #

MimeUnrender * PlainText Text Source #

    left show . TextL.decodeUtf8'

Methods mimeUnrender :: Proxy PlainText Text -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy PlainText Text -> MediaType -> ByteString -> Either String a Source #
FromJSON a => MimeUnrender * JSON a Source # | `eitherDecode`
Methods mimeUnrender :: Proxy JSON a -> ByteString -> Either String a Source # mimeUnrenderWithType :: Proxy JSON a -> MediaType -> ByteString -> Either String a Source #

# NoContent

data NoContent Source #

A type for responses without content-body.

Constructors

NoContent |

Instances

Eq NoContent Source # |
Methods (==) :: NoContent -> NoContent -> Bool # (/=) :: NoContent -> NoContent -> Bool #
Read NoContent Source # |
Methods readsPrec :: Int -> ReadS NoContent # readList :: ReadS [NoContent] # readPrec :: ReadPrec NoContent # readListPrec :: ReadPrec [NoContent] #
Show NoContent Source # |
Methods showsPrec :: Int -> NoContent -> ShowS # show :: NoContent -> String # showList :: [NoContent] -> ShowS #
Generic NoContent Source # |
Associated Types type Rep NoContent :: * -> * # Methods from :: NoContent -> Rep NoContent x # to :: Rep NoContent x -> NoContent #
AllMime ((:) * ctyp ((:) * ctyp' ctyps)) => AllMimeRender ((:) * ctyp ((:) * ctyp' ctyps)) NoContent Source # |
Methods allMimeRender :: Proxy [*] ((* ': ctyp) ((* ': ctyp') ctyps)) -> NoContent -> [(MediaType, ByteString)] Source #
Accept * ctyp => AllMimeRender ((:) * ctyp ([] *)) NoContent Source # |
Methods allMimeRender :: Proxy [*] ((* ': ctyp) [*]) -> NoContent -> [(MediaType, ByteString)] Source #
type Rep NoContent Source # |
type Rep NoContent = D1 (MetaData "NoContent" "Servant.API.ContentTypes" "servant-0.11-4V2Kat1ZPa65cYjlpXcD7T" False) (C1 (MetaCons "NoContent" PrefixI False) U1)

# Internal

newtype AcceptHeader Source #

Constructors

AcceptHeader ByteString |

Instances

Eq AcceptHeader Source # |
Methods (==) :: AcceptHeader -> AcceptHeader -> Bool # (/=) :: AcceptHeader -> AcceptHeader -> Bool #
Read AcceptHeader Source # |
Methods readsPrec :: Int -> ReadS AcceptHeader # readList :: ReadS [AcceptHeader] # readPrec :: ReadPrec AcceptHeader # readListPrec :: ReadPrec [AcceptHeader] #
Show AcceptHeader Source # |
Methods showsPrec :: Int -> AcceptHeader -> ShowS # show :: AcceptHeader -> String # showList :: [AcceptHeader] -> ShowS #
Generic AcceptHeader Source # |
Associated Types type Rep AcceptHeader :: * -> * # Methods from :: AcceptHeader -> Rep AcceptHeader x # to :: Rep AcceptHeader x -> AcceptHeader #
type Rep AcceptHeader Source # |
type Rep AcceptHeader = D1 (MetaData "AcceptHeader" "Servant.API.ContentTypes" "servant-0.11-4V2Kat1ZPa65cYjlpXcD7T" True) (C1 (MetaCons "AcceptHeader" PrefixI False) (S1 (MetaSel (Nothing Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 ByteString)))

class AllMime list => AllCTRender list a where Source #

Minimal complete definition

handleAcceptH

Methods

handleAcceptH :: Proxy list -> AcceptHeader -> a -> Maybe (ByteString, ByteString) Source #

Instances

TypeError Constraint (Text "No instance for (), use NoContent instead.") => AllCTRender ([] *) () Source # |
Methods handleAcceptH :: Proxy [*] [*] -> AcceptHeader -> () -> Maybe (ByteString, ByteString) Source #
(Accept * ct, AllMime cts, AllMimeRender ((:) * ct cts) a) => AllCTRender ((:) * ct cts) a Source # |
Methods handleAcceptH :: Proxy [*] ((* ': ct) cts) -> AcceptHeader -> a -> Maybe (ByteString, ByteString) Source #

class AllCTUnrender list a where Source #

Minimal complete definition

canHandleCTypeH

Methods

canHandleCTypeH :: Proxy list -> ByteString -> Maybe (ByteString -> Either String a) Source #

handleCTypeH :: Proxy list -> ByteString -> ByteString -> Maybe (Either String a) Source #

Instances

AllMimeUnrender ctyps a => AllCTUnrender ctyps a Source # |
Methods canHandleCTypeH :: Proxy [*] ctyps -> ByteString -> Maybe (ByteString -> Either String a) Source # handleCTypeH :: Proxy [*] ctyps -> ByteString -> ByteString -> Maybe (Either String a) Source #

class AllMime list where Source #

Minimal complete definition

allMime

Methods

allMime :: Proxy list -> [MediaType] Source #

Instances

AllMime ([] *) Source # |
Methods allMime :: Proxy [*] [*] -> [MediaType] Source #
(Accept * ctyp, AllMime ctyps) => AllMime ((:) * ctyp ctyps) Source # |
Methods allMime :: Proxy [*] ((* ': ctyp) ctyps) -> [MediaType] Source #

class AllMime list => AllMimeRender list a where Source #

Minimal complete definition

allMimeRender

Methods

allMimeRender :: Proxy list -> a -> [(MediaType, ByteString)] Source #

Instances

AllMime ((:) * ctyp ((:) * ctyp' ctyps)) => AllMimeRender ((:) * ctyp ((:) * ctyp' ctyps)) NoContent Source # |
Methods allMimeRender :: Proxy [*] ((* ': ctyp) ((* ': ctyp') ctyps)) -> NoContent -> [(MediaType, ByteString)] Source #
Accept * ctyp => AllMimeRender ((:) * ctyp ([] *)) NoContent Source # |
Methods allMimeRender :: Proxy [*] ((* ': ctyp) [*]) -> NoContent -> [(MediaType, ByteString)] Source #
(MimeRender * ctyp a, AllMimeRender ((:) * ctyp' ctyps) a) => AllMimeRender ((:) * ctyp ((:) * ctyp' ctyps)) a Source # |
Methods allMimeRender :: Proxy [*] ((* ': ctyp) ((* ': ctyp') ctyps)) -> a -> [(MediaType, ByteString)] Source #
MimeRender * ctyp a => AllMimeRender ((:) * ctyp ([] *)) a Source # |
Methods allMimeRender :: Proxy [*] ((* ': ctyp) [*]) -> a -> [(MediaType, ByteString)] Source #

class AllMime list => AllMimeUnrender list a where Source #

Minimal complete definition

allMimeUnrender

Methods

allMimeUnrender :: Proxy list -> [(MediaType, ByteString -> Either String a)] Source #

Instances

AllMimeUnrender ([] *) a Source # |
Methods allMimeUnrender :: Proxy [*] [*] -> [(MediaType, ByteString -> Either String a)] Source #
(MimeUnrender * ctyp a, AllMimeUnrender ctyps a) => AllMimeUnrender ((:) * ctyp ctyps) a Source # |
Methods allMimeUnrender :: Proxy [*] ((* ': ctyp) ctyps) -> [(MediaType, ByteString -> Either String a)] Source #

eitherDecodeLenient :: FromJSON a => ByteString -> Either String a Source #

Like `eitherDecode` but allows all JSON values instead of just objects and arrays.

Will handle trailing whitespace, but not trailing junk. ie.

    >>> eitherDecodeLenient "1 " :: Either String Int
    Right 1

    >>> eitherDecodeLenient "1 junk" :: Either String Int
    Left "trailing junk after valid JSON: endOfInput"

canHandleAcceptH :: AllMime list => Proxy list -> AcceptHeader -> Bool Source #