servant-polysemy 0.1.1 → 0.1.2
raw patch · 7 files changed
+101/−3 lines, 7 filesdep +servantnew-component:exe:example-server-genericPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: servant
API changes (from Hackage documentation)
- Paths_servant_polysemy: getBinDir :: IO FilePath
- Paths_servant_polysemy: getDataDir :: IO FilePath
- Paths_servant_polysemy: getDataFileName :: FilePath -> IO FilePath
- Paths_servant_polysemy: getDynLibDir :: IO FilePath
- Paths_servant_polysemy: getLibDir :: IO FilePath
- Paths_servant_polysemy: getLibexecDir :: IO FilePath
- Paths_servant_polysemy: getSysconfDir :: IO FilePath
- Paths_servant_polysemy: version :: Version
- Servant.Polysemy.Client: runClient' :: forall r_aoiK o_Xn1t. (MemberWithError ServantClient r_aoiK, NFData o_Xn1t) => ClientM o_Xn1t -> Sem r_aoiK (Either ClientError o_Xn1t)
+ Servant.Polysemy.Client: runClient' :: forall r_ao68 o_XmMC. (MemberWithError ServantClient r_ao68, NFData o_XmMC) => ClientM o_XmMC -> Sem r_ao68 (Either ClientError o_XmMC)
- Servant.Polysemy.Client: runClientStreaming :: forall r_apgK o_aoiU. MemberWithError ServantClientStreaming r_apgK => ClientM o_aoiU -> Sem r_apgK o_aoiU
+ Servant.Polysemy.Client: runClientStreaming :: forall r_ap4i o_ao6i. MemberWithError ServantClientStreaming r_ap4i => ClientM o_ao6i -> Sem r_ap4i o_ao6i
Files
- CHANGELOG.md +5/−0
- README.md +1/−0
- example/Client.hs +9/−0
- example/Server.hs +8/−0
- example/ServerGeneric.hs +43/−0
- example/ServerWithSwagger.hs +15/−0
- servant-polysemy.cabal +20/−3
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for servant-polysemy +## 0.1.2 -- 2021-02-23++* Remove Paths_servant_polysemy from exported modules.+* Add an example of using Servant.API.Generic API types.+ ## 0.1.1 -- 2020-12-11 * Relax constraint on polysemy dependency to allow version 1.5.
README.md view
@@ -7,6 +7,7 @@ Check out these examples for how to use it: - [Server](https://github.com/AJChapman/servant-polysemy/blob/master/example/Server.hs)+- [Server using Servant.API.Generic](https://github.com/AJChapman/servant-polysemy/blob/master/example/ServerGeneric.hs) - [Server with Swagger docs](https://github.com/AJChapman/servant-polysemy/blob/master/example/ServerWithSwagger.hs) - [Client](https://github.com/AJChapman/servant-polysemy/blob/master/example/Client.hs)
example/Client.hs view
@@ -11,11 +11,19 @@ import Servant.Client.Streaming (ClientM, client) import Servant.Polysemy.Client (ServantClient, runClient, runServantClient) +{-+This is an example client for connecting to the API defined in each of Server.hs, ServerGeneric.hs, and ServerWithSwagger.hs.+-}++-- This is the same path defined in the server.+-- Typically you would have this in a common place rather than reproducing it here. type MyApi = "api" :> "v1" :> "version" :> Get '[JSON] Version +-- The client is automatically generated from the API type. versionClient :: ClientM Version versionClient = client (Proxy @MyApi) +-- This program runs the client and then handles the response by printing info to stdout. program :: Members '[ServantClient, Embed IO] r => Sem r () program = do ev <- runClient versionClient & runError@@ -25,6 +33,7 @@ Right v -> embed $ putStrLn $ "Received version: " <> showVersion v +-- This runs the client, connecting to localhost:8080. main :: IO () main = program & runServantClient "localhost:8080"
example/Server.hs view
@@ -13,13 +13,21 @@ import Servant import Servant.Polysemy.Server +{-+This is a very simple server with only one endpoint.+-}++-- This is the endpoint, which responds to a GET at /api/v1/version with the server's version in JSON format. type MyApi = "api" :> "v1" :> "version" :> Get '[JSON] Version +-- This is the implementation of the API.+-- It also does some IO to print to the terminal. myServer :: Member (Embed IO) r => ServerT MyApi (Sem (Error ServerError ': r)) myServer = do embed $ putStrLn $ "Returning version " <> showVersion Paths.version pure Paths.version +-- This runs Warp (a Haskell web server), serving up our API. main :: IO () main = runWarpServer @MyApi 8080 True myServer
+ example/ServerGeneric.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DeriveGeneric #-}+module Main (main) where++import Control.Lens.Operators+import Data.Version (Version, showVersion)+import Paths_servant_polysemy as Paths+import Polysemy+import Polysemy.Error+import Servant+import Servant.Polysemy.Server+import Servant.API.Generic (ToServantApi, (:-), Generic)++{-+This example is of the same server as defined in Server.hs, but it uses Servant.API.Generic to define the path.+-}++-- This is the Servant.API.Generic style of creating an API.+data Routes route = Routes+ { _version :: route :- "api" :> "v1" :> "version" :> Get '[JSON] Version+ } deriving (Generic)++-- This is the endpoint, which responds to a GET at /api/v1/version with the server's version in JSON format.+type MyApi = ToServantApi Routes++-- This is the implementation of the API.+-- It also does some IO to print to the terminal.+myServer :: Member (Embed IO) r => ServerT MyApi (Sem (Error ServerError ': r))+myServer = do+ embed $ putStrLn $ "Returning version " <> showVersion Paths.version+ pure Paths.version++-- This runs Warp (a Haskell web server), serving up our API.+main :: IO ()+main =+ runWarpServer @MyApi 8080 True myServer+ & runM++
example/ServerWithSwagger.hs view
@@ -19,10 +19,21 @@ import Servant.Swagger (toSwagger) import Servant.Swagger.UI (SwaggerSchemaUI, swaggerSchemaUIServer) +{-+This is the same server as in Server.hs, but is self-documenting.+-}++-- The same API type as in Server.hs. type MyApi = "api" :> "v1" :> "version" :> Get '[JSON] Version +-- This API has the swagger docs at /api/v1/swagger-ui type SwaggerDocs = "api" :> "v1" :> SwaggerSchemaUI "swagger-ui" "swagger.json" +-- Now we combine the two APIs into one, and also add redirects:+-- / -> /api/v1/swagger-ui+-- /api -> /api/v1/swagger-ui+-- /api/v1 -> /api/v1/swagger-ui+-- The redirects are just to help people find the documentation. type MyApiWithSwagger = MyApi :<|> SwaggerDocs@@ -30,11 +41,13 @@ :<|> "api" :> Redirect 302 Text -- Redirect /api to the swagger docs :<|> Redirect 302 Text -- Redirect / to the swagger docs +-- The same server from Server.hs myServer :: Member (Embed IO) r => ServerT MyApi (Sem (Error ServerError ': r)) myServer = do embed $ putStrLn $ "Returning version " <> showVersion Paths.version pure Paths.version +-- The swagger endpoint implementation. mySwagger :: Swagger mySwagger = toSwagger (Proxy @MyApi) & info.title .~ "My API"@@ -43,6 +56,7 @@ & info.license ?~ "Public Domain" & host ?~ "localhost:8080" +-- This server adds the Swagger docs and redirects to the 'myServer' implementation. mySwaggerServer :: Member (Embed IO) r => ServerT MyApiWithSwagger (Sem (Error ServerError ': r)) mySwaggerServer = myServer@@ -51,6 +65,7 @@ :<|> redirect "/api/v1/swagger-ui" :<|> redirect "/api/v1/swagger-ui" +-- Run 'mySwaggerServer' on port 8080. main :: IO () main = runWarpServer @MyApiWithSwagger 8080 True mySwaggerServer
servant-polysemy.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: servant-polysemy-version: 0.1.1+version: 0.1.2 synopsis: Utilities for using servant in a polysemy stack description: It's possible to use servant and polysemy together without this library, but it's not easy. This library makes it easy. homepage: https://github.com/AJChapman/servant-polysemy#readme@@ -15,6 +15,7 @@ extra-source-files: CHANGELOG.md README.md extra-doc-files: example/Server.hs+ example/ServerGeneric.hs example/ServerWithSwagger.hs example/Client.hs tested-with: GHC == 8.8.4@@ -64,12 +65,12 @@ default-language: Haskell2010 exposed-modules: Servant.Polysemy.Client Servant.Polysemy.Server- Paths_servant_polysemy- autogen-modules: Paths_servant_polysemy executable example-server import: deps main-is: Server.hs+ autogen-modules: Paths_servant_polysemy+ other-modules: Paths_servant_polysemy hs-source-dirs: example default-language: Haskell2010 ghc-options: -threaded@@ -78,9 +79,25 @@ build-depends: servant-polysemy , lens +executable example-server-generic+ import: deps+ main-is: ServerGeneric.hs+ autogen-modules: Paths_servant_polysemy+ other-modules: Paths_servant_polysemy+ hs-source-dirs: example+ default-language: Haskell2010+ ghc-options: -threaded+ -rtsopts+ -with-rtsopts=-N+ build-depends: servant-polysemy+ , lens+ , servant+ executable example-server-with-swagger import: deps main-is: ServerWithSwagger.hs+ autogen-modules: Paths_servant_polysemy+ other-modules: Paths_servant_polysemy hs-source-dirs: example default-language: Haskell2010 ghc-options: -threaded