Skip to content

Commit

Permalink
first shot at a server package
Browse files Browse the repository at this point in the history
  • Loading branch information
alpmestan committed Dec 10, 2014
0 parents commit e43532b
Show file tree
Hide file tree
Showing 14 changed files with 1,159 additions and 0 deletions.
30 changes: 30 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Copyright (c) 2014, Zalora South East Asia Pte Ltd

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.

* Neither the name of Zalora South East Asia Pte Ltd nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# servant

[![Build Status](https://secure.travis-ci.org/haskell-servant/servant.svg)](http://travis-ci.org/haskell-servant/servant)

![servant](https://raw.githubusercontent.com/haskell-servant/servant/master/servant.png)

These libraries provides a family of combinators to define webservices and automatically generate the documentation and client-side querying functions for each endpoint.

In order to minimize the dependencies depending on your needs, we provide these features under different packages.

- `servant`, which contains everything you need to *declare* a webservice and *implement* an HTTP server with handlers for each endpoint.
- `servant-client`, which lets you derive automatically Haskell functions that let you query each endpoint of a *servant* webservice.
- `servant-docs`, which lets you generate API docs for your webservice.
- `servant-jquery`, which lets you derive Javascript functions (based on jquery) to query your API's endpoints, in the same spirit as `servant-client`.

## Getting started

We've written a [Getting Started](http://haskell-servant.github.io/getting-started/) guide that introduces the core types and features of servant. After this article, you should be able to write your first servant webservices, learning the rest from the haddocks' examples.

## Repositories and Haddocks

- The core [servant](http://github.com/haskell-servant) package - [docs](http://haskell-servant.github.io/servant/)
- (Haskell) client-side function generation with [servant-client](http://github.com/haskell-servant/servant-client) - [docs](http://haskell-servant.github.io/servant-client/)
- (Javascript) client-side function generation with [servant-jquery](http://github.com/haskell-servant/servant-jquery) - [docs](http://haskell-servant.github.io/servant-jquery/)
- API docs generation with [servant-docs](http://github.com/haskell-servant/servant-docs) - [docs](http://haskell-servant.github.io/servant-docs/)
2 changes: 2 additions & 0 deletions Setup.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain
2 changes: 2 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- `greet.hs` shows how to write a simple webservice, run it, query it with automatically-derived haskell functions and print the (generated) markdown documentation for the API.
- `greet.md` contains the aforementionned generated documentation.
72 changes: 72 additions & 0 deletions example/greet.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}

import Data.Aeson
import Data.Monoid
import Data.Proxy
import Data.Text
import GHC.Generics
import Network.Wai
import Network.Wai.Handler.Warp

import Servant

-- * Example

-- | A greet message data type
newtype Greet = Greet { msg :: Text }
deriving (Generic, Show)

instance FromJSON Greet
instance ToJSON Greet

-- API specification
type TestApi =
-- GET /hello/:name?capital={true, false} returns a Greet as JSON
"hello" :> Capture "name" Text :> QueryParam "capital" Bool :> Get Greet

-- POST /greet with a Greet as JSON in the request body,
-- returns a Greet as JSON
:<|> "greet" :> ReqBody Greet :> Post Greet

-- DELETE /greet/:greetid
:<|> "greet" :> Capture "greetid" Text :> Delete

testApi :: Proxy TestApi
testApi = Proxy

-- Server-side handlers.
--
-- There's one handler per endpoint, which, just like in the type
-- that represents the API, are glued together using :<|>.
--
-- Each handler runs in the 'EitherT (Int, String) IO' monad.
server :: Server TestApi
server = helloH :<|> postGreetH :<|> deleteGreetH

where helloH name Nothing = helloH name (Just False)
helloH name (Just False) = return . Greet $ "Hello, " <> name
helloH name (Just True) = return . Greet . toUpper $ "Hello, " <> name

postGreetH greet = return greet

deleteGreetH _ = return ()

-- Turn the server into a WAI app. 'serve' is provided by servant,
-- more precisely by the Servant.Server module.
test :: Application
test = serve testApi server

-- Run the server.
--
-- 'run' comes from Network.Wai.Handler.Warp
runTestServer :: Port -> IO ()
runTestServer port = run port test

-- Put this all to work!
main :: IO ()
main = runTestServer 8001
52 changes: 52 additions & 0 deletions example/greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
POST /greet
-----------

**Request Body**:

``` javascript
{"msg":"Hello, haskeller!"}
```

**Response**:

- Status code 201
- Response body as below.

``` javascript
{"msg":"Hello, haskeller!"}
```

GET /hello/:name
----------------

**Captures**:

- *name*: name of the person to greet

**GET Parameters**:

- capital
- **Values**: *true, false*
- **Description**: Get the greeting message in uppercase (true) or not (false). Default is false.


**Response**:

- Status code 200
- Response body as below.

``` javascript
{"msg":"Hello, haskeller!"}
```

DELETE /greet/:greetid
----------------------

**Captures**:

- *greetid*: identifier of the greet msg to remove

**Response**:

- Status code 204
- No response body
95 changes: 95 additions & 0 deletions servant-server.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: servant-server
version: 0.2.1
synopsis: A family of combinators for defining webservices APIs and serving them
description:
A family of combinators for defining webservices APIs and serving them
.
You can learn about the basics in <http://haskell-servant.github.io/getting-started/ the getting started> guide.
.
<https://github.com/haskell-servant/servant-server/blob/master/example/greet.hs Here>'s a runnable example, with comments, that defines a dummy API and
implements a webserver that serves this API, using this package.
homepage: http://haskell-servant.github.io/
Bug-reports: http://github.com/haskell-servant/servant-server/issues
license: BSD3
license-file: LICENSE
author: Alp Mestanogullari, Sönke Hahn, Julian K. Arni
maintainer: [email protected]
copyright: 2014 Zalora South East Asia Pte Ltd
category: Web
build-type: Simple
cabal-version: >=1.10
tested-with: GHC >= 7.8
source-repository head
type: git
location: http://github.com/haskell-servant/servant-server.git

library
exposed-modules:
Servant
Servant.Server
Servant.Utils.StaticFiles
other-modules: Servant.Server.Internal
build-depends:
base >=4.7 && <5
, aeson
, attoparsec
, bytestring
, either
, http-types
, network-uri >= 2.6
, safe
, servant >= 0.2
, split
, string-conversions
, system-filepath
, text
, transformers
, wai
, wai-app-static
, warp
hs-source-dirs: src
default-language: Haskell2010
ghc-options: -Wall

executable greet
main-is: greet.hs
hs-source-dirs: example
ghc-options: -Wall
default-language: Haskell2010
build-depends:
base
, servant
, servant-server
, aeson
, warp
, wai
, text

test-suite spec
type: exitcode-stdio-1.0
ghc-options:
-Wall -fno-warn-name-shadowing -fno-warn-missing-signatures
default-language: Haskell2010
hs-source-dirs: test
main-is: Spec.hs
build-depends:
base == 4.*
, aeson
, bytestring
, directory
, either
, exceptions
, hspec == 2.*
, hspec-wai
, http-types
, network >= 2.6
, QuickCheck
, parsec
, servant
, string-conversions
, temporary
, text
, transformers
, wai
, wai-extra
, warp
24 changes: 24 additions & 0 deletions src/Servant.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Servant (
-- | This module and its submodules can be used to define servant APIs. Note
-- that these API definitions don't directly implement a server (or anything
-- else).
module Servant.API,
-- | For implementing servers for servant APIs.
module Servant.Server,
-- | Using your types in request paths and query string parameters
module Servant.Common.Text,
-- | Utilities on top of the servant core
module Servant.QQ,
module Servant.Utils.Links,
module Servant.Utils.StaticFiles,
-- | Useful re-exports
Proxy(..),
) where

import Data.Proxy
import Servant.API
import Servant.Common.Text
import Servant.Server
import Servant.QQ
import Servant.Utils.Links
import Servant.Utils.StaticFiles
39 changes: 39 additions & 0 deletions src/Servant/Server.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}

-- | This module lets you implement 'Server's for defined APIs. You'll
-- most likely just need 'serve'.
module Servant.Server
( -- * Implementing an API
serve

, -- * Handlers for all standard combinators
HasServer(..)
) where

import Data.Proxy
import Network.Wai
import Servant.Server.Internal

-- * Implementing Servers

-- | 'serve' allows you to implement an API and produce a wai 'Application'.
--
-- Example:
--
-- > type MyApi = "books" :> Get [Book] -- GET /books
-- > :<|> "books" :> ReqBody Book :> Post Book -- POST /books
-- >
-- > server :: Server MyApi
-- > server = listAllBooks :<|> postBook
-- > where listAllBooks = ...
-- > postBook book = ...
-- >
-- > app :: Application
-- > app = serve myApi server
-- >
-- > main :: IO ()
-- > main = Network.Wai.Handler.Warp.run 8080 app
serve :: HasServer layout => Proxy layout -> Server layout -> Application
serve p server = toApplication (route p server)

Loading

0 comments on commit e43532b

Please sign in to comment.