From ff6c04cf1adf389978efb9f8b2bbec58b2735c24 Mon Sep 17 00:00:00 2001 From: Alp Mestanogullari Date: Thu, 14 May 2015 00:52:37 +0200 Subject: [PATCH 1/2] update examples in servant-client. fixes #75 --- servant-client/README.md | 11 ++-- servant-client/src/Servant/Client.hs | 91 ++++++++++++++++------------ 2 files changed, 57 insertions(+), 45 deletions(-) diff --git a/servant-client/README.md b/servant-client/README.md index 0a2f1e32..6fa5a8c3 100644 --- a/servant-client/README.md +++ b/servant-client/README.md @@ -7,14 +7,15 @@ This library lets you automatically derive Haskell functions that let you query ## Example ``` haskell -type MyApi = "books" :> Get [Book] -- GET /books - :<|> "books" :> ReqBody Book :> Post Book -- POST /books +type MyApi = "books" :> Get '[JSON] [Book] -- GET /books + :<|> "books" :> ReqBody Book :> Post '[JSON] Book -- POST /books myApi :: Proxy MyApi myApi = Proxy -getAllBooks :: BaseUrl -> EitherT String IO [Book] -postNewBook :: Book -> BaseUrl -> EitherT String IO Book +getAllBooks :: EitherT String IO [Book] +postNewBook :: Book -> EitherT String IO Book -- 'client' allows you to produce operations to query an API from a client. -(getAllBooks :<|> postNewBook) = client myApi +(getAllBooks :<|> postNewBook) = client myApi host + where host = BaseUrl Http "localhost" 8080 ``` diff --git a/servant-client/src/Servant/Client.hs b/servant-client/src/Servant/Client.hs index 42e05daf..9505b5a0 100644 --- a/servant-client/src/Servant/Client.hs +++ b/servant-client/src/Servant/Client.hs @@ -43,15 +43,16 @@ import Servant.Common.Req -- | 'client' allows you to produce operations to query an API from a client. -- --- > type MyApi = "books" :> Get [Book] -- GET /books --- > :<|> "books" :> ReqBody Book :> Post Book -- POST /books +-- > type MyApi = "books" :> Get '[JSON] [Book] -- GET /books +-- > :<|> "books" :> ReqBody '[JSON] Book :> Post Book -- POST /books -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > getAllBooks :: BaseUrl -> EitherT String IO [Book] --- > postNewBook :: Book -> BaseUrl -> EitherT String IO Book --- > (getAllBooks :<|> postNewBook) = client myApi +-- > getAllBooks :: EitherT String IO [Book] +-- > postNewBook :: Book -> EitherT String IO Book +-- > (getAllBooks :<|> postNewBook) = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 client :: HasClient layout => Proxy layout -> BaseUrl -> Client layout client p baseurl = clientWithRoute p defReq baseurl @@ -68,15 +69,16 @@ class HasClient layout where -- one function for querying @a@ and another one for querying @b@, -- stitching them together with ':<|>', which really is just like a pair. -- --- > type MyApi = "books" :> Get [Book] -- GET /books --- > :<|> "books" :> ReqBody Book :> Post Book -- POST /books +-- > type MyApi = "books" :> Get '[JSON] [Book] -- GET /books +-- > :<|> "books" :> ReqBody '[JSON] Book :> Post Book -- POST /books -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > getAllBooks :: BaseUrl -> EitherT String IO [Book] --- > postNewBook :: Book -> BaseUrl -> EitherT String IO Book --- > (getAllBooks :<|> postNewBook) = client myApi +-- > getAllBooks :: EitherT String IO [Book] +-- > postNewBook :: Book -> EitherT String IO Book +-- > (getAllBooks :<|> postNewBook) = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 instance (HasClient a, HasClient b) => HasClient (a :<|> b) where type Client (a :<|> b) = Client a :<|> Client b clientWithRoute Proxy req baseurl = @@ -94,13 +96,14 @@ instance (HasClient a, HasClient b) => HasClient (a :<|> b) where -- -- Example: -- --- > type MyApi = "books" :> Capture "isbn" Text :> Get Book +-- > type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > getBook :: Text -> BaseUrl -> EitherT String IO Book --- > getBook = client myApi +-- > getBook :: Text -> EitherT String IO Book +-- > getBook = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 -- > -- then you can just use "getBook" to query that endpoint instance (KnownSymbol capture, ToText a, HasClient sublayout) => HasClient (Capture capture a :> sublayout) where @@ -205,19 +208,20 @@ instance -- -- Example: -- --- > newtype Referer = Referer Text --- > deriving (Eq, Show, FromText, ToText) +-- > newtype Referer = Referer { referrer :: Text } +-- > deriving (Eq, Show, Generic, FromText, ToText) -- > -- > -- GET /view-my-referer --- > type MyApi = "view-my-referer" :> Header "Referer" Referer :> Get Referer +-- > type MyApi = "view-my-referer" :> Header "Referer" Referer :> Get '[JSON] Referer -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > viewReferer :: Maybe Referer -> BaseUrl -> EitherT String IO Book --- > viewReferer = client myApi +-- > viewReferer :: Maybe Referer -> EitherT String IO Book +-- > viewReferer = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 -- > -- then you can just use "viewRefer" to query that endpoint --- > -- specifying Nothing or Just "http://haskell.org/" as arguments +-- > -- specifying Nothing or e.g Just "http://haskell.org/" as arguments instance (KnownSymbol sym, ToText a, HasClient sublayout) => HasClient (Header sym a :> sublayout) where @@ -366,13 +370,14 @@ instance -- -- Example: -- --- > type MyApi = "books" :> QueryParam "author" Text :> Get [Book] +-- > type MyApi = "books" :> QueryParam "author" Text :> Get '[JSON] [Book] -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > getBooksBy :: Maybe Text -> BaseUrl -> EitherT String IO [Book] --- > getBooksBy = client myApi +-- > getBooksBy :: Maybe Text -> EitherT String IO [Book] +-- > getBooksBy = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 -- > -- then you can just use "getBooksBy" to query that endpoint. -- > -- 'getBooksBy Nothing' for all books -- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov @@ -411,13 +416,14 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout) -- -- Example: -- --- > type MyApi = "books" :> QueryParams "authors" Text :> Get [Book] +-- > type MyApi = "books" :> QueryParams "authors" Text :> Get '[JSON] [Book] -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > getBooksBy :: [Text] -> BaseUrl -> EitherT String IO [Book] --- > getBooksBy = client myApi +-- > getBooksBy :: [Text] -> EitherT String IO [Book] +-- > getBooksBy = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 -- > -- then you can just use "getBooksBy" to query that endpoint. -- > -- 'getBooksBy []' for all books -- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]' @@ -451,13 +457,14 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout) -- -- Example: -- --- > type MyApi = "books" :> QueryFlag "published" :> Get [Book] +-- > type MyApi = "books" :> QueryFlag "published" :> Get '[JSON] [Book] -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > getBooks :: Bool -> BaseUrl -> EitherT String IO [Book] --- > getBooks = client myApi +-- > getBooks :: Bool -> EitherT String IO [Book] +-- > getBooks = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 -- > -- then you can just use "getBooks" to query that endpoint. -- > -- 'getBooksBy False' for all books -- > -- 'getBooksBy True' to only get _already published_ books @@ -492,13 +499,14 @@ instance (KnownSymbol sym, HasClient sublayout) -- -- Example: -- --- > type MyApi = "books" :> MatrixParam "author" Text :> Get [Book] +-- > type MyApi = "books" :> MatrixParam "author" Text :> Get '[JSON] [Book] -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > getBooksBy :: Maybe Text -> BaseUrl -> EitherT String IO [Book] --- > getBooksBy = client myApi +-- > getBooksBy :: Maybe Text -> EitherT String IO [Book] +-- > getBooksBy = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 -- > -- then you can just use "getBooksBy" to query that endpoint. -- > -- 'getBooksBy Nothing' for all books -- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov @@ -536,13 +544,14 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout) -- -- Example: -- --- > type MyApi = "books" :> MatrixParams "authors" Text :> Get [Book] +-- > type MyApi = "books" :> MatrixParams "authors" Text :> Get '[JSON] [Book] -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > getBooksBy :: [Text] -> BaseUrl -> EitherT String IO [Book] --- > getBooksBy = client myApi +-- > getBooksBy :: [Text] -> EitherT String IO [Book] +-- > getBooksBy = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 -- > -- then you can just use "getBooksBy" to query that endpoint. -- > -- 'getBooksBy []' for all books -- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]' @@ -576,13 +585,14 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout) -- -- Example: -- --- > type MyApi = "books" :> MatrixFlag "published" :> Get [Book] +-- > type MyApi = "books" :> MatrixFlag "published" :> Get '[JSON] [Book] -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > getBooks :: Bool -> BaseUrl -> EitherT String IO [Book] --- > getBooks = client myApi +-- > getBooks :: Bool -> EitherT String IO [Book] +-- > getBooks = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 -- > -- then you can just use "getBooks" to query that endpoint. -- > -- 'getBooksBy False' for all books -- > -- 'getBooksBy True' to only get _already published_ books @@ -621,13 +631,14 @@ instance HasClient Raw where -- -- Example: -- --- > type MyApi = "books" :> ReqBody Book :> Post Book +-- > type MyApi = "books" :> ReqBody '[JSON] Book :> Post '[JSON] Book -- > -- > myApi :: Proxy MyApi -- > myApi = Proxy -- > --- > addBook :: Book -> BaseUrl -> EitherT String IO Book --- > addBook = client myApi +-- > addBook :: Book -> EitherT String IO Book +-- > addBook = client myApi host +-- > where host = BaseUrl Http "localhost" 8080 -- > -- then you can just use "addBook" to query that endpoint instance (MimeRender ct a, HasClient sublayout) => HasClient (ReqBody (ct ': cts) a :> sublayout) where From 46d48946b0482fcaf8e7e7f84bbe7ce9d1ddbcdc Mon Sep 17 00:00:00 2001 From: Alp Mestanogullari Date: Thu, 14 May 2015 01:01:41 +0200 Subject: [PATCH 2/2] update examples for servant-docs. fixes #76 --- servant-docs/README.md | 4 ++-- servant-docs/src/Servant/Docs.hs | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/servant-docs/README.md b/servant-docs/README.md index ed088802..2c81b2a5 100644 --- a/servant-docs/README.md +++ b/servant-docs/README.md @@ -32,7 +32,7 @@ instance ToJSON Greet -- We can also implement 'MimeRender' explicitly for additional formats. instance MimeRender PlainText Greet where - toByteString Proxy (Greet s) = "

" <> cs s <> "

" + mimeRender Proxy (Greet s) = "

" <> cs s <> "

" -- we provide a sample value for the 'Greet' type instance ToSample Greet where @@ -56,7 +56,7 @@ instance ToCapture (Capture "greetid" Text) where type TestApi = "hello" :> Capture "name" Text :> QueryParam "capital" Bool :> Get '[JSON,PlainText] Greet :<|> "greet" :> RQBody '[JSON] Greet :> Post '[JSON] Greet - :<|> "delete" :> Capture "greetid" Text :> Delete + :<|> "delete" :> Capture "greetid" Text :> Delete '[] () testApi :: Proxy TestApi testApi = Proxy diff --git a/servant-docs/src/Servant/Docs.hs b/servant-docs/src/Servant/Docs.hs index 627f9593..14f116d1 100644 --- a/servant-docs/src/Servant/Docs.hs +++ b/servant-docs/src/Servant/Docs.hs @@ -30,6 +30,7 @@ -- > {-# LANGUAGE OverloadedStrings #-} -- > {-# LANGUAGE TypeOperators #-} -- > {-# OPTIONS_GHC -fno-warn-orphans #-} +-- > import Control.Lens -- > import Data.Aeson -- > import Data.Proxy -- > import Data.String.Conversions @@ -51,7 +52,7 @@ -- > -- > -- | We can also implement 'MimeRender' for additional formats like 'PlainText'. -- > instance MimeRender PlainText Greet where --- > toByteString Proxy (Greet s) = "\"" <> cs s <> "\"" +-- > mimeRender Proxy (Greet s) = "\"" <> cs s <> "\"" -- > -- > -- We add some useful annotations to our captures, -- > -- query parameters and request body to make the docs @@ -111,7 +112,7 @@ -- > :<|> "greet" :> ReqBody '[JSON] Greet :> Post '[JSON] Greet -- > -- > -- DELETE /greet/:greetid --- > :<|> "greet" :> Capture "greetid" Text :> Delete +-- > :<|> "greet" :> Capture "greetid" Text :> Delete '[JSON] () -- > -- > testApi :: Proxy TestApi -- > testApi = Proxy @@ -121,7 +122,7 @@ -- > -- notes. -- > extra :: ExtraInfo TestApi -- > extra = --- > extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete)) $ +-- > extraInfo (Proxy :: Proxy ("greet" :> Capture "greetid" Text :> Delete '[JSON] ())) $ -- > defAction & headers <>~ ["unicorns"] -- > & notes <>~ [ DocNote "Title" ["This is some text"] -- > , DocNote "Second secton" ["And some more"]