Implemented NoContentVerb and server instances for it
This commit is contained in:
parent
164f75711b
commit
b440af900b
6 changed files with 46 additions and 13 deletions
|
@ -75,10 +75,12 @@ import Servant.API
|
||||||
IsSecure (..), QueryFlag, QueryParam', QueryParams, Raw,
|
IsSecure (..), QueryFlag, QueryParam', QueryParams, Raw,
|
||||||
ReflectMethod (reflectMethod), RemoteHost, ReqBody',
|
ReflectMethod (reflectMethod), RemoteHost, ReqBody',
|
||||||
SBool (..), SBoolI (..), SourceIO, Stream, StreamBody',
|
SBool (..), SBoolI (..), SourceIO, Stream, StreamBody',
|
||||||
Summary, ToSourceIO (..), Vault, Verb, WithNamedContext)
|
Summary, ToSourceIO (..), Vault, Verb, NoContentVerb,
|
||||||
|
WithNamedContext)
|
||||||
import Servant.API.ContentTypes
|
import Servant.API.ContentTypes
|
||||||
(AcceptHeader (..), AllCTRender (..), AllCTUnrender (..),
|
(AcceptHeader (..), AllCTRender (..), AllCTUnrender (..),
|
||||||
AllMime, MimeRender (..), MimeUnrender (..), canHandleAcceptH)
|
AllMime, MimeRender (..), MimeUnrender (..), canHandleAcceptH,
|
||||||
|
NoContent (NoContent))
|
||||||
import Servant.API.Modifiers
|
import Servant.API.Modifiers
|
||||||
(FoldLenient, FoldRequired, RequestArgument,
|
(FoldLenient, FoldRequired, RequestArgument,
|
||||||
unfoldRequestArgument)
|
unfoldRequestArgument)
|
||||||
|
@ -262,6 +264,17 @@ methodRouter splitHeaders method proxy status action = leafRouter route'
|
||||||
let bdy = if allowedMethodHead method request then "" else body
|
let bdy = if allowedMethodHead method request then "" else body
|
||||||
in Route $ responseLBS status ((hContentType, cs contentT) : headers) bdy
|
in Route $ responseLBS status ((hContentType, cs contentT) : headers) bdy
|
||||||
|
|
||||||
|
noContentRouter :: Method
|
||||||
|
-> Status
|
||||||
|
-> Delayed env (Handler b)
|
||||||
|
-> Router env
|
||||||
|
noContentRouter method status action = leafRouter route'
|
||||||
|
where
|
||||||
|
route' env request respond =
|
||||||
|
runAction (action `addMethodCheck` methodCheck method request)
|
||||||
|
env request respond $ \ output ->
|
||||||
|
Route $ responseLBS status [] ""
|
||||||
|
|
||||||
instance {-# OVERLAPPABLE #-}
|
instance {-# OVERLAPPABLE #-}
|
||||||
( AllCTRender ctypes a, ReflectMethod method, KnownNat status
|
( AllCTRender ctypes a, ReflectMethod method, KnownNat status
|
||||||
) => HasServer (Verb method status ctypes a) context where
|
) => HasServer (Verb method status ctypes a) context where
|
||||||
|
@ -285,6 +298,15 @@ instance {-# OVERLAPPING #-}
|
||||||
where method = reflectMethod (Proxy :: Proxy method)
|
where method = reflectMethod (Proxy :: Proxy method)
|
||||||
status = toEnum . fromInteger $ natVal (Proxy :: Proxy status)
|
status = toEnum . fromInteger $ natVal (Proxy :: Proxy status)
|
||||||
|
|
||||||
|
instance {-# OVERLAPPABLE #-}
|
||||||
|
(ReflectMethod method
|
||||||
|
) => HasServer (NoContentVerb method) context where
|
||||||
|
|
||||||
|
type ServerT (NoContentVerb method) m = m NoContent
|
||||||
|
hoistServerWithContext _ _ nt s = nt s
|
||||||
|
|
||||||
|
route Proxy _ = noContentRouter method status204
|
||||||
|
where method = reflectMethod (Proxy :: Proxy method)
|
||||||
|
|
||||||
instance {-# OVERLAPPABLE #-}
|
instance {-# OVERLAPPABLE #-}
|
||||||
( MimeRender ctype chunk, ReflectMethod method, KnownNat status,
|
( MimeRender ctype chunk, ReflectMethod method, KnownNat status,
|
||||||
|
|
|
@ -51,7 +51,7 @@ import Servant.API
|
||||||
JSON, NoContent (..), NoFraming, OctetStream, Patch,
|
JSON, NoContent (..), NoFraming, OctetStream, Patch,
|
||||||
PlainText, Post, Put, QueryFlag, QueryParam, QueryParams, Raw,
|
PlainText, Post, Put, QueryFlag, QueryParam, QueryParams, Raw,
|
||||||
RemoteHost, ReqBody, SourceIO, StdMethod (..), Stream, Verb,
|
RemoteHost, ReqBody, SourceIO, StdMethod (..), Stream, Verb,
|
||||||
addHeader)
|
NoContentVerb, addHeader)
|
||||||
import Servant.Server
|
import Servant.Server
|
||||||
(Context ((:.), EmptyContext), Handler, Server, Tagged (..),
|
(Context ((:.), EmptyContext), Handler, Server, Tagged (..),
|
||||||
emptyServer, err400, err401, err403, err404, serve, serveWithContext)
|
emptyServer, err400, err401, err403, err404, serve, serveWithContext)
|
||||||
|
@ -103,7 +103,7 @@ spec = do
|
||||||
|
|
||||||
type VerbApi method status
|
type VerbApi method status
|
||||||
= Verb method status '[JSON] Person
|
= Verb method status '[JSON] Person
|
||||||
:<|> "noContent" :> Verb method status '[JSON] NoContent
|
:<|> "noContent" :> NoContentVerb method
|
||||||
:<|> "header" :> Verb method status '[JSON] (Headers '[Header "H" Int] Person)
|
:<|> "header" :> Verb method status '[JSON] (Headers '[Header "H" Int] Person)
|
||||||
:<|> "headerNC" :> Verb method status '[JSON] (Headers '[Header "H" Int] NoContent)
|
:<|> "headerNC" :> Verb method status '[JSON] (Headers '[Header "H" Int] NoContent)
|
||||||
:<|> "accept" :> ( Verb method status '[JSON] Person
|
:<|> "accept" :> ( Verb method status '[JSON] Person
|
||||||
|
@ -140,7 +140,7 @@ verbSpec = describe "Servant.API.Verb" $ do
|
||||||
|
|
||||||
it "returns no content on NoContent" $ do
|
it "returns no content on NoContent" $ do
|
||||||
response <- THW.request method "/noContent" [] ""
|
response <- THW.request method "/noContent" [] ""
|
||||||
liftIO $ statusCode (simpleStatus response) `shouldBe` status
|
liftIO $ statusCode (simpleStatus response) `shouldBe` 204
|
||||||
liftIO $ simpleBody response `shouldBe` ""
|
liftIO $ simpleBody response `shouldBe` ""
|
||||||
|
|
||||||
-- HEAD should not return body
|
-- HEAD should not return body
|
||||||
|
|
|
@ -130,7 +130,8 @@ import Servant.API.Verbs
|
||||||
Post, PostAccepted, PostCreated, PostNoContent,
|
Post, PostAccepted, PostCreated, PostNoContent,
|
||||||
PostNonAuthoritative, PostResetContent, Put, PutAccepted,
|
PostNonAuthoritative, PostResetContent, Put, PutAccepted,
|
||||||
PutCreated, PutNoContent, PutNonAuthoritative,
|
PutCreated, PutNoContent, PutNonAuthoritative,
|
||||||
ReflectMethod (reflectMethod), StdMethod (..), Verb)
|
ReflectMethod (reflectMethod), StdMethod (..),
|
||||||
|
Verb, NoContentVerb)
|
||||||
import Servant.API.WithNamedContext
|
import Servant.API.WithNamedContext
|
||||||
(WithNamedContext)
|
(WithNamedContext)
|
||||||
import Servant.Links
|
import Servant.Links
|
||||||
|
|
|
@ -29,6 +29,12 @@ import Network.HTTP.Types.Method
|
||||||
data Verb (method :: k1) (statusCode :: Nat) (contentTypes :: [*]) (a :: *)
|
data Verb (method :: k1) (statusCode :: Nat) (contentTypes :: [*]) (a :: *)
|
||||||
deriving (Typeable, Generic)
|
deriving (Typeable, Generic)
|
||||||
|
|
||||||
|
-- | @NoContentVerb@ is a specific type to represent 'NoContent' responses.
|
||||||
|
-- It does not require either a list of content types (because there's
|
||||||
|
-- no content) or a status code (because it should always be 204).
|
||||||
|
data NoContentVerb (method :: k1)
|
||||||
|
deriving (Typeable, Generic)
|
||||||
|
|
||||||
-- * 200 responses
|
-- * 200 responses
|
||||||
--
|
--
|
||||||
-- The 200 response is the workhorse of web servers, but also fairly generic.
|
-- The 200 response is the workhorse of web servers, but also fairly generic.
|
||||||
|
@ -113,15 +119,15 @@ type PutNonAuthoritative = Verb 'PUT 203
|
||||||
-- If the document view should be reset, use @205 Reset Content@.
|
-- If the document view should be reset, use @205 Reset Content@.
|
||||||
|
|
||||||
-- | 'GET' with 204 status code.
|
-- | 'GET' with 204 status code.
|
||||||
type GetNoContent = Verb 'GET 204
|
type GetNoContent = NoContentVerb 'GET
|
||||||
-- | 'POST' with 204 status code.
|
-- | 'POST' with 204 status code.
|
||||||
type PostNoContent = Verb 'POST 204
|
type PostNoContent = NoContentVerb 'POST
|
||||||
-- | 'DELETE' with 204 status code.
|
-- | 'DELETE' with 204 status code.
|
||||||
type DeleteNoContent = Verb 'DELETE 204
|
type DeleteNoContent = NoContentVerb 'DELETE
|
||||||
-- | 'PATCH' with 204 status code.
|
-- | 'PATCH' with 204 status code.
|
||||||
type PatchNoContent = Verb 'PATCH 204
|
type PatchNoContent = NoContentVerb 'PATCH
|
||||||
-- | 'PUT' with 204 status code.
|
-- | 'PUT' with 204 status code.
|
||||||
type PutNoContent = Verb 'PUT 204
|
type PutNoContent = NoContentVerb 'PUT
|
||||||
|
|
||||||
|
|
||||||
-- ** 205 Reset Content
|
-- ** 205 Reset Content
|
||||||
|
|
|
@ -177,7 +177,7 @@ import Servant.API.TypeLevel
|
||||||
import Servant.API.Vault
|
import Servant.API.Vault
|
||||||
(Vault)
|
(Vault)
|
||||||
import Servant.API.Verbs
|
import Servant.API.Verbs
|
||||||
(Verb)
|
(Verb, NoContentVerb)
|
||||||
import Servant.API.WithNamedContext
|
import Servant.API.WithNamedContext
|
||||||
(WithNamedContext)
|
(WithNamedContext)
|
||||||
import Web.HttpApiData
|
import Web.HttpApiData
|
||||||
|
@ -546,6 +546,10 @@ instance HasLink (Verb m s ct a) where
|
||||||
type MkLink (Verb m s ct a) r = r
|
type MkLink (Verb m s ct a) r = r
|
||||||
toLink toA _ = toA
|
toLink toA _ = toA
|
||||||
|
|
||||||
|
instance HasLink (NoContentVerb m) where
|
||||||
|
type MkLink (NoContentVerb m) r = r
|
||||||
|
toLink toA _ = toA
|
||||||
|
|
||||||
instance HasLink Raw where
|
instance HasLink Raw where
|
||||||
type MkLink Raw a = a
|
type MkLink Raw a = a
|
||||||
toLink toA _ = toA
|
toLink toA _ = toA
|
||||||
|
|
|
@ -64,7 +64,7 @@ type ComprehensiveAPIWithoutStreamingOrRaw' endpoint =
|
||||||
:<|> "res-headers" :> Get '[JSON] (Headers '[Header "foo" Int] NoContent)
|
:<|> "res-headers" :> Get '[JSON] (Headers '[Header "foo" Int] NoContent)
|
||||||
:<|> "foo" :> GET
|
:<|> "foo" :> GET
|
||||||
:<|> "vault" :> Vault :> GET
|
:<|> "vault" :> Vault :> GET
|
||||||
:<|> "post-no-content" :> Verb 'POST 204 '[JSON] NoContent
|
:<|> "post-no-content" :> PostNoContent
|
||||||
:<|> "post-int" :> Verb 'POST 204 '[JSON] Int
|
:<|> "post-int" :> Verb 'POST 204 '[JSON] Int
|
||||||
:<|> "named-context" :> WithNamedContext "foo" '[] GET
|
:<|> "named-context" :> WithNamedContext "foo" '[] GET
|
||||||
:<|> "capture-all" :> CaptureAll "foo" Int :> GET
|
:<|> "capture-all" :> CaptureAll "foo" Int :> GET
|
||||||
|
|
Loading…
Reference in a new issue