@@ -204,7 +204,7 @@ And that's it! You can run this example in the same way that we showed for
204204
205205Fine, we can write trivial webservices easily, but none of the two above use
206206any "fancy" combinator from servant. Let's address this and use `QueryParam`,
207−`Capture` and `ReqBody` right away. You'll see how each occurence of these
207+`Capture` and `ReqBody` right away. You'll see how each occurrence of these
208208combinators in an endpoint makes the corresponding handler receive an
209209argument of the appropriate type automatically. You don't have to worry about
210210manually looking up URL captures or query string parameters, or
@@ -1092,7 +1092,7 @@ We can write some simple webservice with the handlers running in `Reader String`
10921092
10931093``` haskell
10941094type ReaderAPI = "a" :> Get '[JSON] Int
1095− :<|> "b" :> ReqBody '[JSON] Double :> Get '[JSON] Bool
1095+ :<|> "b" :> ReqBody '[JSON] Double :> Get '[JSON] Bool
10961096
10971097readerAPI :: Proxy ReaderAPI
10981098readerAPI = Proxy
@@ -1114,7 +1114,7 @@ We unfortunately can't use `readerServerT` as an argument of `serve`, because
11141114That's right. We have just written `readerToHandler`, which is exactly what we
11151115would need to apply to all handlers to make the handlers have the
11161116right type for `serve`. Being cumbersome to do by hand, we provide a function
1117−`hoistServer` which takes a natural transformation between two parametrized types `m`
1117+`hoistServer` which takes a natural transformation between two parameterized types `m`
11181118and `n` and a `ServerT someapi m`, and returns a `ServerT someapi n`.
11191119
11201120In our case, we can wrap up our little webservice by using
@@ -1164,6 +1164,27 @@ app5 :: Application
11641164app5 = serve readerAPI (hoistServer readerAPI funToHandler funServerT)
11651165```
11661166
1167+## Streaming endpoints
1168+
1169+We can create endpoints that don't just give back a single result, but give back a *stream* of results, served one at a time. Stream endpoints only provide a single content type, and also specify what framing strategy is used to delineate the results. To serve these results, we need to give back a stream producer. Adapters can be written to `Pipes`, `Conduit` and the like, or written directly as `StreamGenerator`s. StreamGenerators are IO-based continuations that are handed two functions -- the first to write the first result back, and the second to write all subsequent results back. (This is to allow handling of situations where the entire stream is prefixed by a header, or where a boundary is written between elements, but not prior to the first element). The API of a streaming endpoint needs to explicitly specify which sort of generator it produces. Note that the generator itself is returned by a `Handler` action, so that additional IO may be done in the creation of one.
1170+
1171+``` haskell
1172+type StreamAPI = "userStream" :> StreamGet NewlineFraming JSON (StreamGenerator User)
1173+streamAPI :: Proxy StreamAPI
1174+streamAPI = Proxy
1175+
1176+streamUsers :: StreamGenerator User
1177+streamUsers = StreamGenerator $ \sendFirst sendRest -> do
1178+ sendFirst isaac
1179+ sendRest albert
1180+ sendRest albert
1181+
1182+app6 :: Application
1183+app6 = serve streamAPI (return streamUsers)
1184+```
1185+
1186+This simple application returns a stream of `User` values encoded in JSON format, with each value separated by a newline. In this case, the stream will consist of the value of `isaac`, followed by the value of `albert`, then the value of `albert` a third time. Importantly, the stream is written back as results are produced, rather than all at once. This means first that results are delivered when they are available, and second, that if an exception interrupts production of the full stream, nonetheless partial results have already been written back.
1187+
11671188## Conclusion
11681189
11691190You're now equipped to write webservices/web-applications using