### GET /hello Endpoint Examples Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Docs.md Shows example JSON responses for the GET /hello endpoint, both when a 'name' parameter is provided and when it is not. ```json {"msg":"Hello, Alp"} ``` ```json {"msg":"Hello, anonymous coward"} ``` -------------------------------- ### Setup and Build with Stack Source: https://github.com/haskell-servant/servant/blob/master/CONTRIBUTING.md Commands to set up the environment, install dependencies, and build packages using Stack. ```shell stack setup stack build --fast stack test ``` -------------------------------- ### Setting up the test database Source: https://github.com/haskell-servant/servant/blob/master/servant-quickcheck/doc/posts/announcement.md These commands are necessary to set up the PostgreSQL database for the servant-quickcheck example. Ensure you have PostgreSQL installed and running. ```bash createdb servant-quickcheck psql --file schema.sql -d servant-quickcheck ``` -------------------------------- ### Main function to run the example Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/db-sqlite-simple/DBConnection.md Initializes the database, starts the server in a separate thread, and uses the client to post and retrieve messages, printing the result. ```haskell main :: IO () main = do -- you could read this from some configuration file, -- environment variable or somewhere else instead. let dbfile = "test.db" initDB dbfile mgr <- newManager defaultManagerSettings bracket (forkIO $ runApp dbfile) killThread $ \_ -> do ms <- flip runClientM (mkClientEnv mgr (BaseUrl Http "localhost" 8080 "")) $ do postMsg "hello" postMsg "world" getMsgs print ms ``` -------------------------------- ### Example JSON Response for Users Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Server.md Illustrates the expected JSON output for a GET request to the /users endpoint. ```json [ {"name": "Isaac Newton", "age": 372, "email": "isaac@newton.co.uk", "registration_date": "1683-03-01"} , {"name": "Albert Einstein", "age": 136, "email": "ae@mc2.org", "registration_date": "1905-12-01"} ] ``` -------------------------------- ### Example API Usage with cURL Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Server.md Demonstrates how to interact with the defined API endpoints using cURL commands. Shows examples for GET requests with captures and query parameters, and a POST request with a JSON body. ```bash $ curl http://localhost:8081/position/1/2 {"xCoord":1,"yCoord":2} $ curl http://localhost:8081/hello {"msg":"Hello, anonymous coward"} $ curl http://localhost:8081/hello?name=Alp {"msg":"Hello, Alp"} $ curl -X POST -d '{"clientName":"Alp Mestanogullari", "clientEmail" : "alp@foo.com", "clientAge": 25, "clientInterestedIn": ["haskell", "mathematics"]}' -H 'Accept: application/json' -H 'Content-type: application/json' http://localhost:8081/marketing {"subject":"Hey Alp Mestanogullari, we miss you!","body":"Hi Alp Mestanogullari,\n\nSince you've recently turned 25, have you checked out our latest haskell, mathematics products? Give us a visit!","to":"alp@foo.com","from":"great@company.com"} ``` -------------------------------- ### POST /marketing Request and Response Examples Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Docs.md Provides example JSON for the POST /marketing endpoint's request body and its corresponding response. ```json {"clientAge":26,"clientEmail":"alp@foo.com","clientName":"Alp","clientInterestedIn":["haskell","mathematics"]} ``` ```json {"subject":"Hey Alp, we miss you!","body":"Hi Alp,\n\nSince you've recently turned 26, have you checked out our latest haskell, mathematics products? Give us a visit!","to":"alp@foo.com","from":"great@company.com"} ``` -------------------------------- ### GET /position/:x/:y Response Example Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Docs.md An example JSON response for the GET /position/:x/:y endpoint, showing coordinate values. ```json {"yCoord":14,"xCoord":3} ``` -------------------------------- ### Response Headers Example (JSON) Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/golden/comprehensive.md Illustrates a GET endpoint that returns a JSON response with custom headers. The 'foo' header is set to '17'. ```json ``` -------------------------------- ### Request Body Example (JSON) Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/golden/comprehensive.md Demonstrates sending a JSON request body for a GET endpoint. Ensure the client sends 'application/json' content type. ```json 17 ``` -------------------------------- ### Application Startup Log Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/hoist-server-with-context/HoistServerWithContext.md This is the initial log output when the application starts. ```json {"message":"My app starting up!","timestamp":"2018-10-04T00:33:12.482568Z","level":"info","lversion":"1.0.0","lenvironment":"dev"} ``` -------------------------------- ### Haskell Main Function for Authentication Examples Source: https://github.com/haskell-servant/servant/blob/master/servant-auth/servant-auth-server/README.md This Haskell code defines the main entry point for the README examples. It parses command-line arguments to select between running JWT or Cookie authentication examples. ```haskell main :: IO () main = do args <- getArgs let usage = "Usage: readme (JWT|Cookie)" case args of ["JWT"] -> mainWithJWT ["Cookie"] -> mainWithCookies e -> putStrLn $ "Arguments: \"" ++ unwords e ++ "\" not understood\n" ++ usage ``` -------------------------------- ### Install Haskell Toolchain with ghcup Bootstrap Script Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/install.md Run the ghcup bootstrap script to install up-to-date versions of the Haskell toolchain on Ubuntu. ```bash $ curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh ``` -------------------------------- ### Vanilla JavaScript XMLHttpRequest Example Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Javascript.md Demonstrates making GET requests using XMLHttpRequest, handling success and error callbacks, and parsing JSON responses. ```javascript var getPoint = function(onSuccess, onError) { var xhr = new XMLHttpRequest(); xhr.open('GET', '/point', true); xhr.setRequestHeader("Accept","application/json"); xhr.onreadystatechange = function (e) { if (xhr.readyState == 4) { if (xhr.status == 204 || xhr.status == 205) { onSuccess(); } else if (xhr.status >= 200 && xhr.status < 300) { var value = JSON.parse(xhr.responseText); onSuccess(value); } else { var value = JSON.parse(xhr.responseText); onError(value); } } } xhr.send(null); } var getBooks = function(q, onSuccess, onError) { var xhr = new XMLHttpRequest(); xhr.open('GET', '/books' + '?q=' + encodeURIComponent(q), true); xhr.setRequestHeader("Accept","application/json"); xhr.onreadystatechange = function (e) { if (xhr.readyState == 4) { if (xhr.status == 204 || xhr.status == 205) { onSuccess(); } else if (xhr.status >= 200 && xhr.status < 300) { var value = JSON.parse(xhr.responseText); onSuccess(value); } else { var value = JSON.JSON.parse(xhr.responseText); onError(value); } } } xhr.send(null); } ``` -------------------------------- ### Example API with Capture Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/ApiType.md This example demonstrates how to use the Capture combinator to define API endpoints that include integer captures in the URL path. ```haskell type UserAPI5 = "user" :> Capture "userid" Integer :> Get '[JSON] User -- equivalent to 'GET /user/:userid' -- except that we explicitly say that "userid" -- must be an integer :<|> "user" :> Capture "userid" Integer :> DeleteNoContent -- equivalent to 'DELETE /user/:userid' ``` -------------------------------- ### Providing Sample for ClientInfo Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Docs.md Defines a sample 'ClientInfo' record, used for generating documentation examples for request bodies. ```haskell ci :: ClientInfo ci = ClientInfo "Alp" "alp@foo.com" 26 ["haskell", "mathematics"] instance ToSample ClientInfo where toSamples _ = singleSample ci ``` -------------------------------- ### Example Output Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/using-custom-monad/UsingCustomMonad.md The expected output when the main program is run, showing the state of the book list after each operation. ```text [] [Book "Harry Potter and the Order of the Phoenix"] [Book "To Kill a Mockingbird",Book "Harry Potter and the Order of the Phoenix"] [Book "The Picture of Dorian Gray",Book "To Kill a Mockingbird",Book "Harry Potter and the Order of the Phoenix"] ``` -------------------------------- ### Sample cURL Request for GET /hello/:name Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/example/greet.md This cURL command demonstrates how to send a GET request to the /hello/:name endpoint, including the 'X-Num-Fairies' header and specifying the 'capital' parameter. ```bash curl -XGET \ -H "X-Num-Fairies: 1729" \ http://localhost:80/hello/:name ``` -------------------------------- ### Example API Usage with curl Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Server.md Demonstrates how to interact with the webservice using curl commands, showing expected outputs for different endpoints. ```bash $ curl http://localhost:8081/a 1797 $ curl http://localhost:8081/b -X GET -d '42.0' -H 'Content-Type: application/json' true ``` -------------------------------- ### Curl Request Example Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Server.md Demonstrates how to query the running web service using curl to retrieve the list of users. ```bash $ curl http://localhost:8081/users ``` -------------------------------- ### Example API with QueryParam Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/ApiType.md This example shows an API endpoint that uses QueryParam to specify a sorting parameter in the URL's query string. ```haskell type UserAPI6 = "users" :> QueryParam "sortby" SortBy :> Get '[JSON] [User] -- equivalent to 'GET /users?sortby={age, name}' ``` -------------------------------- ### Example of a Bad Request with Custom Error Formatting Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/custom-errors/CustomErrors.md This example demonstrates the output received when a POST request to the /greet endpoint fails due to incorrect body formatting, showcasing the custom error message. ```http $ http -j POST localhost:8000/greet 'foo=bar' HTTP/1.1 400 Bad Request Content-Type: application/json Date: Fri, 17 Jul 2020 13:34:18 GMT Server: Warp/3.3.12 Transfer-Encoding: chunked { "combinator": "ReqBody'", "error": "Error in $: parsing Main.Greet(Greet) failed, key \"_msg\" not found" } ``` -------------------------------- ### Build and Test with Cabal Source: https://github.com/haskell-servant/servant/blob/master/CONTRIBUTING.md Commands to install dependencies, build packages, and run all tests using Cabal. ```shell cabal build all cabal test all ``` -------------------------------- ### Example Output of Request and Response Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/using-free-client/UsingFreeClient.md Illustrates the expected output when running the test against a server, showing the formatted HTTP request and the received response. ```text Making request: Request { host = "localhost" port = 8000 secure = False requestHeaders = [("Accept","application/json")] path = "/square/42" queryString = "" method = "GET" proxy = Nothing rawBody = False redirectCount = 10 responseTimeout = ResponseTimeoutDefault requestVersion = HTTP/1.1 } Got response: Response { responseStatus = Status {statusCode = 200, statusMessage = "OK"} , responseVersion = HTTP/1.1 , responseHeaders = [ ("Transfer-Encoding","chunked") , ("Date","Thu, 05 Jul 2018 21:12:41 GMT") , ("Server","Warp/3.2.22") , ("Content-Type","application/json") ] , responseBody = "1764" , responseCookieJar = CJ {expose = []} , responseClose' = ResponseClose } Expected 1764, got 1764 ``` -------------------------------- ### Run the Web Server Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Server.md Starts the web server using Warp on port 8081, serving the WAI Application defined previously. ```haskell main :: IO () main = run 8081 app1 ``` -------------------------------- ### Run Web Application Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/db-postgres-pool/PostgresPool.md Starts the web server using Warp, serving the defined API with the provided connection pool. ```haskell runApp :: Pool Connection -> IO () runApp conns = run 8080 (serve api $ server conns) ``` -------------------------------- ### POST /greet Request Body Source: https://github.com/haskell-servant/servant/blob/master/servant-server/example/greet.md Example of the JSON request body for the POST /greet endpoint. ```javascript {"msg":"Hello, haskeller!"} ``` -------------------------------- ### Manual AsUnion Implementation Example Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/multiverb/MultiVerb.md Demonstrates a manual implementation of the AsUnion typeclass using Peano numbers for encoding and decoding responses. ```haskell instance AsUnion MultipleChoicesIntResponses MultipleChoicesIntResult where toUnion NegativeNumber = Z (I ()) toUnion (Even b) = S (Z (I b)) toUnion (Odd i) = S (S (Z (I i))) fromUnion (Z (I ())) = NegativeNumber fromUnion (S (Z (I b))) = Even b fromUnion (S (S (Z (I i)))) = Odd i fromUnion (S (S (S x))) = case x of {} ``` -------------------------------- ### GET /operation-id Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/golden/comprehensive.md An example endpoint with an operation ID. ```APIDOC ## GET /operation-id ### OperationId: foo ### Response: - Status code 200 - Headers: [] - Supported content types are: - `application/json` - Response body as below. ```json ``` ``` -------------------------------- ### Changelog Entry Format Source: https://github.com/haskell-servant/servant/blob/master/CONTRIBUTING.md Example structure for a changelog entry file, including synopsis, PR and issue references, and a detailed description. ```cabal synopsis: One sentence summary of the change. prs: #1219 issues: #1028 description: { A longer description. Small changes don't need this. Bigger ones definitely do, for example we try to include migration hints for breaking changes. However if you don't know what to write, that's ok too. By the way, the braces around are omitted when the file is parsed. They can be used so the field doesn't need to be indented, which is handy for prose. } ``` -------------------------------- ### Main Application Entry Point Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/hoist-server-with-context/HoistServerWithContext.md Sets up the Servant application, including configuration, logging, context, and server settings, then runs the `Warp` server. ```haskell main :: IO () main = do -- typically, we'd create our config from environment variables -- but we're going to just make one here let config = SiteConfig "dev" "1.0.0" "admin" "secretPassword" warpLogger <- jsonRequestLogger appLogger <- newStdoutLoggerSet defaultBufSize tstamp <- getCurrentTime myKey <- generateKey let lgmsg = LogMessage { message = "My app starting up!" , timestamp = tstamp , level = "info" , lversion = version config , lenvironment = environment config } pushLogStrLn appLogger (toLogStr lgmsg) >> flushLogStr appLogger let ctx = AppCtx config appLogger warpSettings = Warp.defaultSettings portSettings = Warp.setPort port warpSettings settings = Warp.setTimeout 55 portSettings jwtCfg = defaultJWTSettings myKey cookieCfg = if environment config == "dev" then defaultCookieSettings{cookieIsSecure=SAS.NotSecure} else defaultCookieSettings cfg = cookieCfg :. jwtCfg :. EmptyContext Warp.runSettings settings $ warpLogger $ mkApp cfg cookieCfg jwtCfg ctx ``` -------------------------------- ### Enter Nix Tutorial Shell Source: https://github.com/haskell-servant/servant/blob/master/README.md Run this command to enter the Nix shell specifically configured for the Servant tutorial and cookbook. ```sh $ nix develop '#tutorial' ``` -------------------------------- ### Build Docs Locally Source: https://github.com/haskell-servant/servant/blob/master/doc/README.md Instructions for building the documentation locally using virtual environment and make. ```none $ virtualenv venv $ . ./venv/bin/activate $ pip install -r requirements.txt $ make html ``` -------------------------------- ### Initialize Servant Project with stack Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/install.md Create a new project using the Servant stack template and build it. ```bash $ stack new myproj servant $ cd myproj # build $ stack build # start server $ stack exec myproj-exe ``` -------------------------------- ### Axios JavaScript Promise Example Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Javascript.md Demonstrates making GET requests using Axios, which returns promises and does not use explicit success/error callbacks. ```javascript var getPoint = function() { return axios({ url: '/point' , method: 'get' }); } var getBooks = function(q) { return axios({ url: '/books' + '?q=' + encodeURIComponent(q) , method: 'get' }); } ``` -------------------------------- ### Build Servant with cabal-install Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/install.md Clone the Servant repository and build the tutorial project using cabal-install. ```bash $ git clone https://github.com/haskell-servant/servant.git $ cd servant # build $ cabal new-build tutorial # load in ghci to play with it $ cabal new-repl tutorial ``` -------------------------------- ### API Query Outputs Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Client.md These are example outputs from querying an API. They show the structure of data returned for different types, including custom data structures. ```text Position {xCoord = 10, yCoord = 10} ``` ```text HelloMessage {msg = "Hello, servant"} ``` ```text Email {from = "great@company.com", to = "alp@foo.com", subject = "Hey Alp, we miss you!", body = "Hi Alp,\n\nSince you've recently turned 26, have you checked out our latest haskell, mathematics products? Give us a visit!"} ``` -------------------------------- ### Serving API and Docs with a Simple Server Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Docs.md Sets up a basic Wai Application that serves both the API endpoints and the generated API documentation. The documentation is served as plain text. ```haskell type DocsAPI = ExampleAPI :<|> Raw api :: Proxy DocsAPI api = Proxy server :: Server DocsAPI server = Server.server3 :<|> Tagged serveDocs where serveDocs _ respond = respond $ responseLBS ok200 [plain] docsBS plain = ("Content-Type", "text/plain") app :: Application app = serve api server ``` -------------------------------- ### Generating API Docs with Introduction Sections Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Docs.md Demonstrates how to generate API documentation in UTF-8 ByteString format, including custom introduction sections. ```haskell docsBS :: ByteString docsBS = encodeUtf8 . pack . markdown $ docsWithIntros [intro] exampleAPI where intro = DocIntro "Welcome" ["This is our super webservice's API.", "Enjoy!"] ``` -------------------------------- ### Example generated curl calls Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/curl-mock/CurlMock.md Illustrates the output of the curl generation process for GET and POST requests, including sample data for the POST request. ```curl curl -X GET localhost:8081/users ``` ```curl curl -X POST -d '{"email":"wV򝣀_b򆎘:z񁊞򲙲!(3DM V","age":10,"name":"=|W"}' -H 'Content-Type: application/json' localhost:8081/new/user ``` -------------------------------- ### Project Setup and Imports Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/hoist-server-with-context/HoistServerWithContext.md This snippet includes necessary language extensions and imports for setting up a Servant server with a custom monad, context, authentication, and logging. ```haskell {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-) import Prelude () import Prelude.Compat import Control.Monad.Reader import Data.Aeson import Data.Default (def) import Data.Proxy import Data.Text import Data.Time.Clock ( UTCTime, getCurrentTime ) import GHC.Generics import Network.Wai (Middleware) import Network.Wai.Handler.Warp as Warp import Network.Wai.Middleware.RequestLogger import Network.Wai.Middleware.RequestLogger.JSON import Servant as S import Servant.Auth as SA import Servant.Auth.Server as SAS hiding (def) import System.Log.FastLogger ( ToLogStr(..) , LoggerSet , defaultBufSize , newStdoutLoggerSet , flushLogStr , pushLogStrLn ) ``` -------------------------------- ### Main Execution: Swagger, Server, and Client Interaction Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/uverb/UVerb.md Demonstrates generating Swagger documentation, running the server, and interacting with the client to test API responses. ```haskell main :: IO () main = do putStrLn . cs . encodePretty $ toSwagger (Proxy @API) _ <- async . Warp.run 8080 $ serve (Proxy @API) (fisx :<|> arian) threadDelay 50000 mgr <- Client.newManager Client.defaultManagerSettings let cenv = mkClientEnv mgr (BaseUrl Http "localhost" 8080 "") result <- runClientM (fisxClient True) cenv print $ foldMapUnion (Proxy @Show) show <$> result print $ matchUnion @FisxUser <$> result print $ matchUnion @(WithStatus 303 String) <$> result pure () ``` -------------------------------- ### Generated Javascript AJAX Call for getPoint Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Javascript.md This is an example of the Javascript code generated by `jsForAPI`. It shows how to make an AJAX GET request to the '/point' endpoint using jQuery. ```javascript var getPoint = function(onSuccess, onError) { $.ajax( { url: '/point' , success: onSuccess , error: onError } ); } ``` -------------------------------- ### Defining the Example API Type Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Docs.md Defines a Servant API type with three endpoints: 'position', 'hello', and 'marketing', using various combinators like Capture, QueryParam, ReqBody, and Get. ```haskell type ExampleAPI = "position" :> Capture "x" Int :> Capture "y" Int :> Get '[JSON] Position :<|> "hello" :> QueryParam "name" String :> Get '[JSON] HelloMessage :<|> "marketing" :> ReqBody '[JSON] ClientInfo :> Post '[JSON] Email exampleAPI :: Proxy ExampleAPI exampleAPI = Proxy ``` -------------------------------- ### Main Application and Client Execution Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/using-custom-monad/UsingCustomMonad.md The main function sets up the application, initializes the state, and runs the server. It also includes client code to interact with the API, demonstrating GET and POST requests and printing the results. ```haskell main :: IO () main = do let port = 8080 mgr <- newManager defaultManagerSettings initialBooks <- atomically $ newTVar [] let runApp = run port $ app $ State initialBooks bracket (forkIO runApp) killThread $ \_ -> do let getBooksClient :<|> addBookClient = client api let printBooks = getBooksClient >>= liftIO . print _ <- flip runClientM (mkClientEnv mgr (BaseUrl Http "localhost" port "")) $ do _ <- printBooks _ <- addBookClient $ Book "Harry Potter and the Order of the Phoenix" _ <- printBooks _ <- addBookClient $ Book "To Kill a Mockingbird" _ <- printBooks _ <- addBookClient $ Book "The Picture of Dorian Gray" printBooks pure () ``` -------------------------------- ### hspec-wai Tests for Backend Application Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/testing/Testing.md Example tests using hspec-wai to interact with a backend application. It demonstrates making GET requests and asserting responses, including handling different error scenarios and custom requests. ```haskell thirdPartyResourcesSpec :: Spec thirdPartyResourcesSpec = around_ withElasticsearch $ do -- we call `with` from `hspec-wai` and pass *real* `Application` with (pure $ docsApp "localhost" "9999") $ do describe "GET /docs" $ do it "should be able to get a document" $ -- `get` is a function from hspec-wai`. get "/docs/1" `shouldRespondWith` 200 it "should be able to handle connection failures" $ get "/docs/1001" `shouldRespondWith` 404 it "should be able to handle parsing failures" $ get "/docs/501" `shouldRespondWith` 400 it "should be able to handle odd HTTP requests" $ -- we can also make all kinds of arbitrary custom requests to see how -- our server responds using the `request` function: -- request :: Method -> ByteString -> [Header] -- -> LB.ByteString -> WaiSession SResponse request methodPost "/docs/501" [] "{" `shouldRespondWith` 405 it "we can also do more with the Response using hspec-wai's matchers" $ -- see also `MatchHeader` and JSON-matching tools as well... get "/docs/1" `shouldRespondWith` 200 { matchBody = MatchBody bodyMatcher } ``` -------------------------------- ### Derive Client Functions for Servant API Source: https://github.com/haskell-servant/servant/blob/master/servant-client/README.md Use the 'client' function to generate operations for querying a servant API. This example defines a simple API with GET and POST endpoints for books and demonstrates how to run the generated client functions. ```haskell #!/usr/bin/env cabal {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeOperators #-} import Data.Proxy import Data.Text (Text) import Network.HTTP.Client (newManager, defaultManagerSettings) import Servant.API import Servant.Client type Book = Text type MyApi = "books" :> Get '[JSON] [Book] -- GET /books :<|> "books" :> ReqBody '[JSON] Book :> Post '[JSON] Book -- POST /books myApi :: Proxy MyApi myApi = Proxy -- 'client' allows you to produce operations to query an API from a client. postNewBook :: Book -> ClientM Book getAllBooks :: ClientM [Book] (getAllBooks :<|> postNewBook) = client myApi main :: IO () main = do manager' <- newManager defaultManagerSettings res <- runClientM getAllBooks (mkClientEnv manager' (BaseUrl Http "localhost" 8081 "")) case res of Left err -> putStrLn $ "Error: " ++ show err Right books -> print books ``` -------------------------------- ### Server Implementation for ProductsAPI Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Server.md Provides the server implementation for the ProductsAPI, handling product listing, creation, and individual product operations. ```haskell productsServer :: Server ProductsAPI productsServer = getProducts :<|> newProduct :<|> productOperations where getProducts :: Handler [Product] getProducts = error "..." newProduct :: Product -> Handler NoContent newProduct = error "..." productOperations productid = viewProduct productid :<|> updateProduct productid :<|> deleteProduct productid where viewProduct :: Int -> Handler Product viewProduct = error "..." updateProduct :: Int -> Product -> Handler NoContent updateProduct = error "..." deleteProduct :: Int -> Handler NoContent deleteProduct = error "..." ``` -------------------------------- ### GET /resource Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/golden/comprehensive.md A basic GET endpoint that returns a successful response with no specific content or headers. ```APIDOC ## GET /resource ### Description A basic GET endpoint that returns a successful response with no specific content or headers. ### Method GET ### Endpoint /resource ### Response #### Success Response (200) - Headers: [] - Supported content types: - `application/json` - Response body as below. ```json ``` ``` -------------------------------- ### Example Natural Transformation: listToMaybe' Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Server.md An example of a natural transformation from list to Maybe, using the listToMaybe function from Data.Maybe. ```haskell listToMaybe' :: [] ~> Maybe listToMaybe' = listToMaybe -- from Data.Maybe ``` -------------------------------- ### Define Server and Application Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Server.md Sets up the server logic by defining a list of Person values and creating a Servant server and a WAI Application. The server simply returns the list of people. ```haskell people :: [Person] people = [ Person "Isaac" "Newton" , Person "Albert" "Einstein" ] personAPI :: Proxy PersonAPI personAPI = Proxy server4 :: Server PersonAPI server4 = pure people app2 :: Application app2 = serve personAPI server4 ``` -------------------------------- ### Deriving and Running a Client for Basic Auth Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/basic-auth/BasicAuth.md This snippet demonstrates how to derive a client for the API and run it with basic authentication credentials. It includes setting up the `ClientEnv` and making a request to the authenticated endpoint. ```haskell getSite :: BasicAuthData -> ClientM Website getSite = client api main :: IO () main = do mgr <- newManager defaultManagerSettings bracket (forkIO $ runApp userDB) killThread $ \_ -> runClientM (getSite u) (mkClientEnv mgr (BaseUrl Http "localhost" 8080 "")) >>= print where u = BasicAuthData "foo" "bar" ``` -------------------------------- ### API with Multiple GET Endpoints Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/ApiType.md Defines an API with two separate endpoints, one for 'users' and another for 'admins', both using GET requests. ```haskell type UserAPI4 = "users" :> Get '[JSON] [User] :<|> "admins" :> Get '[JSON] [User] ``` -------------------------------- ### Main Execution Function Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/db-postgres-pool/PostgresPool.md Sets up the database connection pool, initializes the database, runs the web application in a separate thread, and then uses the client to post and retrieve messages. ```haskell main :: IO () main = do -- you could read this from some configuration file, -- environment variable or somewhere else instead. -- you will need to either change this connection string OR -- set some environment variables (see -- https://www.postgresql.org/docs/9.5/static/libpq-envars.html) -- to point to a running PostgreSQL server for this example to work. let connStr = "" pool <- initConnectionPool connStr initDB connStr mgr <- newManager defaultManagerSettings bracket (forkIO $ runApp pool) killThread $ \_ -> do ms <- flip runClientM (mkClientEnv mgr (BaseUrl Http "localhost" 8080 "")) $ do postMsg "hello" postMsg "world" getMsgs print ms ``` -------------------------------- ### Main Execution: Server and Client Interaction Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/infinite-streams/InfiniteStreams.md Sets up and runs the server, then connects as a client to consume the infinite stream. It handles potential client errors and processes the stream elements, printing them to the console. ```haskell main :: IO () main = do mgr <- newManager defaultManagerSettings let url = (BaseUrl Http "localhost" 8080 "") bracket (forkIO (Warp.run 8080 server)) killThread (\_ -> do threadDelay 100_000 withClientM getInfiniteIntegers (mkClientEnv mgr url) (\case Left clientError -> throwIO clientError Right stream -> SourceT.unSourceT stream go ) ) where go (SourceT.Yield !incoming next) = print incoming >> go next go (SourceT.Effect !x) = x >>= go go (SourceT.Skip !next) = go next -- This cookbook recipe is concerned with infinite streams. While -- the following two cases should be unreachable, we handle -- them for completeness. go (SourceT.Error err) = throwIO (userError err) go (SourceT.Stop) = pure () ``` -------------------------------- ### Get All Persons using cURL Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/db-mysql-basics/MysqlBasics.md This cURL command performs a GET request to retrieve all person records from the database. It is useful for fetching a list of all entries. ```bash curl -X GET \ http://localhost:8080/person \ -H 'Accept: */*' \ -H 'Accept-Encoding: gzip, deflate' \ -H 'Cache-Control: no-cache' \ -H 'Connection: keep-alive' \ -H 'Content-Length: 33' \ -H 'Content-Type: application/json' \ -H 'Host: localhost:8080' \ -H 'cache-control: no-cache' ``` -------------------------------- ### Example OpenAPI 3.0 JSON Schema Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/openapi3/OpenAPI.md This is an example of the generated OpenAPI 3.0 JSON schema for a simple TODO API, including definitions for 'Todo' items and 'TodoId'. ```json { "openapi": "3.0.0", "info": { "title": "", "version": "" }, "paths": { "/todo": { "get": { "description": "Get all TODO items", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/Todo" }, "type": "array" } } }, "description": "" } } } } }, "components": { "schemas": { "Todo": { "required": [ "created", "summary" ], "properties": { "summary": { "type": "string" }, "created": { "minimum": -9223372036854775808, "type": "integer", "maximum": 9223372036854775807 } }, "type": "object" }, "TodoId": { "minimum": -9223372036854775808, "type": "integer", "maximum": 9223372036854775807 } } } } ``` -------------------------------- ### Server and Application Setup Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Javascript.md Defines the Servant API, server implementation, and the WAI application. This includes serving static files and handling API requests. ```haskell api :: Proxy API api = Proxy api' :: Proxy API' api' = Proxy server :: Server API server = randomPoint :<|> searchBook server' :: Server API' server' = server :<|> serveDirectoryFileServer "static" app :: Application app = serve api' server' main :: IO () main = run 8000 app ``` -------------------------------- ### Define Product Server with SimpleAPI Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/structuring-apis/StructuringApis.md This snippet defines a server for product-related API endpoints using the generic `simpleServer` function. It provides dummy implementations for listing, getting, and posting products. ```haskell productServer :: Server (SimpleAPI "products" Product ProductId) productServer = simpleServer (pure []) (\ _productid -> pure $ Product "Great stuff") (\ _product -> pure NoContent) ``` -------------------------------- ### REST Actions for People Resource Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/db-mysql-basics/MysqlBasics.md Defines the available RESTful endpoints for managing 'people' resources: getting all people, getting a person by ID, inserting a new person, and deleting a person. ```text /people GET ``` ```text /people/:id GET ``` ```text /people POST { "name": "NewName", "age": 24 } ``` ```text /people/:id DELETE ``` -------------------------------- ### Implement User Server and Application Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/testing/Testing.md Provides a sample handler, server, and Application for the UserApi endpoint, including basic validation. ```haskell userApp :: Application userApp = serve (Proxy :: Proxy UserApi) userServer userServer :: Server UserApi userServer = createUser createUser :: Integer -> Handler User createUser userId = do if userId > 5000 then pure $ User { name = "some user", user_id = userId } else throwError $ err400 { errBody = "userId is too small" } ``` -------------------------------- ### Generate Javascript GET Request Function Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Javascript.md This Javascript function makes a GET request to a specified URL. It uses jQuery's AJAX method and accepts success and error callbacks. Ensure jQuery is loaded before this function. ```javascript var getBooks = function(q, onSuccess, onError) { $.ajax( { url: '/books' + '?q=' + encodeURIComponent(q) , success: onSuccess , error: onError , type: 'GET' }); } ``` -------------------------------- ### Set up Test Environment with Warp Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/testing/Testing.md Configures a test environment using Warp's testWithApplication to run the server and execute actions against it. ```haskell withUserApp :: (Warp.Port -> IO ()) -> IO () withUserApp action = -- testWithApplication makes sure the action is executed after the server has -- started and is being properly shutdown. Warp.testWithApplication (pure userApp) action ``` -------------------------------- ### Get All Persons Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/db-mysql-basics/MysqlBasics.md Retrieves a list of all persons from the database. ```APIDOC ## GET /person ### Description Retrieves a list of all persons. ### Method GET ### Endpoint /person ### Response #### Success Response (200) - **body** (array) - A list of Person objects. #### Response Example ```json [ { "name": "John Doe", "age": "30" } ] ``` ``` -------------------------------- ### Get All People Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/db-mysql-basics/MysqlBasics.md Retrieves a list of all people from the database. ```APIDOC ## GET /people ### Description Retrieves a list of all people. ### Method GET ### Endpoint /people ``` -------------------------------- ### GET /remote-host Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/golden/comprehensive.md Endpoint for accessing remote host information. ```APIDOC ## GET /remote-host ### Response: - Status code 200 - Headers: [] - Supported content types are: - `application/json` - Response body as below. ```json ``` ``` -------------------------------- ### GET /param-lenient Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/golden/comprehensive.md Endpoint demonstrating a lenient query parameter. ```APIDOC ## GET /param-lenient ### GET Parameters: - bar - **Values**: *1, 2, 3* - **Description**: QueryParams Int ### Response: - Status code 200 - Headers: [] - Supported content types are: - `application/json` - Response body as below. ```json ``` ``` -------------------------------- ### GET /param Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/golden/comprehensive.md Endpoint demonstrating a single query parameter. ```APIDOC ## GET /param ### GET Parameters: - foo - **Values**: *1, 2, 3* - **Description**: QueryParams Int ### Response: - Status code 200 - Headers: [] - Supported content types are: - `application/json` - Response body as below. ```json ``` ``` -------------------------------- ### GET /foo Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/golden/comprehensive.md A simple endpoint that returns a JSON response. ```APIDOC ## GET /foo ### Description A simple endpoint that returns a JSON response. ### Method GET ### Endpoint /foo ### Response #### Success Response (200) - Supported content types are: `application/json` - Response body is empty. ``` -------------------------------- ### Implementing ToCapture for 'x' Capture Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Docs.md Provides documentation for the 'x' capture parameter, specifying its name and a human-readable description. ```haskell instance ToCapture (Capture "x" Int) where toCapture _ = DocCapture "x" -- name "(integer) position on the x axis" -- description ``` -------------------------------- ### JWT Token Generation and Usage Example Source: https://github.com/haskell-servant/servant/blob/master/servant-auth/README.md Demonstrates the command-line interaction for generating a JWT token and then using it with curl to access a protected API endpoint. Shows the unauthorized response without a token and the successful response with a valid token. ```bash ./readme JWT Started server on localhost:7249 Enter name and email separated by a space for a new token alice alice@gmail.com New token: "eyJhbGciOiJIUzI1NiJ9.eyJkYXQiOnsiZW1haWwiOiJhbGljZUBnbWFpbC5jb20iLCJuYW1lIjoiYWxpY2UifX0.xzOIrx_A9VOKzVO-R1c1JYKBqK9risF625HOxpBzpzE" curl localhost:7249/name -v * Hostname was NOT found in DNS cache * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 7249 (#0) > GET /name HTTP/1.1 > User-Agent: curl/7.35.0 > Host: localhost:7249 > Accept: */* > < HTTP/1.1 401 Unauthorized < Transfer-Encoding: chunked < Date: Wed, 07 Sep 2016 20:17:17 GMT * Server Warp/3.2.7 is not blacklisted < Server: Warp/3.2.7 > * Connection #0 to host localhost left intact curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJkYXQiOnsiZW1haWwiOiJhbGljZUBnbWFpbC5jb20iLCJuYW1lIjoiYWxpY2UifX0.xzOIrx_A9VOKzVO-R1c1JYKBqK9risF625HOxpBzpzE" \ localhost:7249/name -v * Hostname was NOT found in DNS cache * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 7249 (#0) > GET /name HTTP/1.1 > User-Agent: curl/7.35.0 > Host: localhost:7249 > Accept: */* > Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJkYXQiOnsiZW1haWwiOiJhbGljZUBnbWFpbC5jb20iLCJuYW1lIjoiYWxpY2UifX0.xzOIrx_A9VOKzVO-R1c1JYKBqK9risF625HOxpBzpzE > < HTTP/1.1 200 OK < Transfer-Encoding: chunked < Date: Wed, 07 Sep 2016 20:16:11 GMT * Server Warp/3.2.7 is not blacklisted < Server: Warp/3.2.7 < Content-Type: application/json < Set-Cookie: JWT-Cookie=eyJhbGciOiJIUzI1NiJ9.eyJkYXQiOnsiZW1haWwiOiJhbGljZUBnbWFpbC5jb20iLCJuYW1lIjoiYWxpY2UifX0.xzOIrx_A9VOKzVO-R1c1JYKBqK9risF625HOxpBzpzE; HttpOnly; Secure < Set-Cookie: XSRF-TOKEN=TWcdPnHr2QHcVyTw/TTBLQ==; Secure > * Connection #0 to host localhost left intact "alice"% ``` -------------------------------- ### GET /is-secure Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/golden/comprehensive.md An endpoint related to security, returning a JSON response. ```APIDOC ## GET /is-secure ### Description An endpoint related to security, returning a JSON response. ### Method GET ### Endpoint /is-secure ### Response #### Success Response (200) - Supported content types are: `application/json` - Response body is empty. ``` -------------------------------- ### GET /get-int Source: https://github.com/haskell-servant/servant/blob/master/servant-docs/golden/comprehensive.md An endpoint that returns a JSON response containing an integer. ```APIDOC ## GET /get-int ### Description An endpoint that returns a JSON response containing an integer. ### Method GET ### Endpoint /get-int ### Response #### Success Response (200) - Supported content types are: `application/json` - Response body: `17` ``` -------------------------------- ### Get All Persons Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/db-mysql-basics/MysqlBasics.md This endpoint retrieves a list of all person records from the database. ```APIDOC ## GET /person ### Description Retrieves all person records. ### Method GET ### Endpoint /person ### Response #### Success Response (200) (No specific response fields documented in source) #### Response Example (No specific response example documented in source) ``` -------------------------------- ### Main Function for Server or Client Execution Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/using-free-client/UsingFreeClient.md Implements the main entry point, allowing the program to run either as a server or as a client test based on command-line arguments. ```haskell main :: IO () main = do args <- getArgs case args of ("server":_) -> do putStrLn "Starting cookbook-using-free-client at http://localhost:8000" run 8000 $ serve api $ \n -> pure (n * n) ("client":_) -> test _ -> do putStrLn "Try:" putStrLn "cabal run cookbook-using-free-client server" putStrLn "cabal run cookbook-using-free-client client" ``` -------------------------------- ### Get Person by ID Source: https://github.com/haskell-servant/servant/blob/master/doc/cookbook/db-mysql-basics/MysqlBasics.md Retrieves a specific person from the database by their ID. ```APIDOC ## GET /person/{id} ### Description Retrieves a specific person by their unique identifier. ### Method GET ### Endpoint /person/{id} ### Parameters #### Path Parameters - **id** (int) - Required - The unique identifier of the person. ### Response #### Success Response (200) - **body** (object) - The Person object. #### Response Example ```json { "name": "Jane Doe", "age": "25" } ``` #### Error Response (404) - **body** (string) - "Person with ID not found." ``` -------------------------------- ### Basic JSON Data Source: https://github.com/haskell-servant/servant/blob/master/doc/tutorial/Server.md Example of JSON data that might be served by an API. ```json [{"email":"isaac@newton.co.uk","registration_date":"1683-03-01","age":372,"name":"Isaac Newton"},{"email":"ae@mc2.org","registration_date":"1905-12-01","age":136,"name":"Albert Einstein"}] ```