Skip to content

Commit b11960c

Browse files
committed
Client-side support for server-sent events (SSE)
1 parent 1f1f7f3 commit b11960c

File tree

9 files changed

+551
-1
lines changed

9 files changed

+551
-1
lines changed

servant-client-core/servant-client-core.cabal

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ library
4646
Servant.Client.Core.Request
4747
Servant.Client.Core.Response
4848
Servant.Client.Core.RunClient
49+
Servant.Client.Core.ServerSentEvents
4950

5051
other-modules:
5152
Servant.Client.Core.Internal
@@ -83,6 +84,7 @@ library
8384
, http-types >= 0.12.2 && < 0.13
8485
, network-uri >= 2.6.1.0 && < 2.7
8586
, safe >= 0.3.17 && < 0.4
87+
, attoparsec >= 0.13.2.2 && < 0.14
8688

8789
hs-source-dirs: src
8890
default-language: Haskell2010
@@ -97,11 +99,15 @@ test-suite spec
9799
other-modules:
98100
Servant.Client.Core.Internal.BaseUrlSpec
99101
Servant.Client.Core.RequestSpec
102+
Servant.Client.Core.ServerSentEventsSpec
100103

101104
-- Dependencies inherited from the library. No need to specify bounds.
102105
build-depends:
103106
base
104107
, base-compat
108+
, bytestring
109+
, transformers
110+
, servant
105111
, servant-client-core
106112

107113
-- Additional dependencies

servant-client-core/src/Servant/Client/Core/HasClient.hs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,21 @@ import Servant.API
5454
contentType, getHeadersHList, getResponse, toQueryParam,
5555
toUrlPiece)
5656
import Servant.API.ContentTypes
57-
(contentTypes)
57+
(EventStream, contentTypes)
5858
import Servant.API.Modifiers
5959
(FoldRequired, RequiredArgument, foldRequiredArgument)
60+
import Servant.API.ServerSentEvents
61+
(EventKind (JsonEvent, RawEvent), ServerSentEvents')
62+
import Servant.API.Stream
63+
(NoFraming)
6064

6165
import Servant.Client.Core.Auth
6266
import Servant.Client.Core.BasicAuth
6367
import Servant.Client.Core.ClientError
6468
import Servant.Client.Core.Request
6569
import Servant.Client.Core.Response
6670
import Servant.Client.Core.RunClient
71+
import Servant.Client.Core.ServerSentEvents
6772

6873
-- * Accessing APIs as a Client
6974

@@ -332,6 +337,63 @@ instance {-# OVERLAPPING #-}
332337
, requestMethod = reflectMethod (Proxy :: Proxy method)
333338
}
334339

340+
type SseClientDelegate method status =
341+
Stream method status NoFraming EventStream
342+
343+
instance
344+
( RunClient m
345+
, HasClient m (SseClientDelegate method status (EventMessageStreamT IO))
346+
)
347+
=> HasClient m (ServerSentEvents' method status 'RawEvent EventMessage) where
348+
type Client m (ServerSentEvents' method status 'RawEvent EventMessage) =
349+
Client m (SseClientDelegate method status (EventMessageStreamT IO))
350+
351+
hoistClientMonad p _ =
352+
hoistClientMonad
353+
p
354+
(Proxy :: Proxy (SseClientDelegate method status (EventMessageStreamT IO)))
355+
356+
clientWithRoute p _ =
357+
clientWithRoute
358+
p
359+
(Proxy :: Proxy (SseClientDelegate method status (EventMessageStreamT IO)))
360+
361+
instance
362+
( RunClient m
363+
, HasClient m (SseClientDelegate method status (EventStreamT IO))
364+
)
365+
=> HasClient m (ServerSentEvents' method status 'RawEvent (Event a)) where
366+
type Client m (ServerSentEvents' method status 'RawEvent (Event a)) =
367+
Client m (SseClientDelegate method status (EventStreamT IO))
368+
369+
hoistClientMonad p _ =
370+
hoistClientMonad
371+
p
372+
(Proxy :: Proxy (SseClientDelegate method status (EventStreamT IO)))
373+
374+
clientWithRoute p _ =
375+
clientWithRoute
376+
p
377+
(Proxy :: Proxy (SseClientDelegate method status (EventStreamT IO)))
378+
379+
instance
380+
( RunClient m
381+
, HasClient m (SseClientDelegate method status (JsonEventStreamT IO a))
382+
)
383+
=> HasClient m (ServerSentEvents' method status 'JsonEvent a) where
384+
type Client m (ServerSentEvents' method status 'JsonEvent a) =
385+
Client m (SseClientDelegate method status (JsonEventStreamT IO a))
386+
387+
hoistClientMonad p _ =
388+
hoistClientMonad
389+
p
390+
(Proxy :: Proxy (SseClientDelegate method status (JsonEventStreamT IO a)))
391+
392+
clientWithRoute p _ =
393+
clientWithRoute
394+
p
395+
(Proxy :: Proxy (SseClientDelegate method status (JsonEventStreamT IO a)))
396+
335397
-- | If you use a 'Header' in one of your endpoints in your API,
336398
-- the corresponding querying function will automatically take
337399
-- an additional argument of the type specified by your 'Header',

0 commit comments

Comments
 (0)