diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Ryotaro NAKAMURA
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/digitalocean-kzs.cabal b/digitalocean-kzs.cabal
new file mode 100644
--- /dev/null
+++ b/digitalocean-kzs.cabal
@@ -0,0 +1,113 @@
+-- Initial digitalocean-kzs.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+-- The name of the package.
+name:                digitalocean-kzs
+
+-- The package version.  See the Haskell package versioning policy (PVP) 
+-- for standards guiding when and how versions should be incremented.
+-- http://www.haskell.org/haskellwiki/Package_versioning_policy
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             0.1.0.0
+
+-- A short (one-line) description of the package.
+synopsis:            digitalocean api for haskell
+description: DigitalOcean api for haskell
+        
+-- A longer description of the package.
+-- description:         
+
+-- URL for the project homepage or repository.
+homepage:            https://github.com/KazumaSATO/digitalocean-kzs
+
+-- The license under which the package is released.
+license:             MIT
+
+-- The file containing the license text.
+license-file:        LICENSE
+
+-- The package author(s).
+author:              Ryotaro NAKAMURA
+
+-- An email address to which users can send suggestions, bug reports, and 
+-- patches.
+maintainer:          r.nakamura1989@gmail.com
+
+-- A copyright notice.
+-- copyright:           
+
+category:            Web
+
+build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or a 
+-- README.
+-- extra-source-files:  
+
+-- Constraint on the version of Cabal needed to build this package.
+cabal-version:       >=1.10
+
+source-repository head
+  type: git
+  location: https://github.com/KazumaSATO/digitalocean-kzs
+                     
+library
+        
+  -- Modules exported by the library.        
+  exposed-modules:
+                  DigitalOcean
+                  DigitalOcean.Account
+                  DigitalOcean.Base
+                  DigitalOcean.Image
+                  DigitalOcean.Droplet
+                  DigitalOcean.Region
+                  DigitalOcean.SSHKey
+                  DigitalOcean.Size
+                  DigitalOcean.NewDroplet
+                  
+  -- Modules included in this library but not exported.                  
+  -- other-modules:
+  
+  -- LANGUAGE extensions used by modules in this package.  
+  -- other-extensions:
+
+  
+  -- Other library packages from which modules are imported.
+  build-depends:
+                base >=4.7 && <4.8,
+                aeson        >= 0.6  && < 0.9,
+                text         >= 0.10 && < 2,
+                bytestring   >= 0.10 && < 0.11,
+                transformers >= 0.3  && < 0.5,
+                HTTP         >= 4000 && < 4001,
+                http-conduit >= 2.1  && < 2.2,
+                http-types   >= 0.8.6
+                
+  -- Directories containing source files.
+  hs-source-dirs:      src
+  Ghc-Options:          -Wall
+  -- Base language which the package is written in.  
+  default-language:    Haskell2010
+
+Test-Suite spec
+  Type:                 exitcode-stdio-1.0
+  Default-Language:     Haskell2010
+  Hs-Source-Dirs:       test
+  Ghc-Options:          -Wall
+  Main-Is:              Spec.hs
+  Other-Modules:        DigitalOceanSpec
+  Build-Depends:        base
+                      , hspec >= 1.3
+                      , digitalocean-kzs
+
+Test-Suite doctest
+  Type:                 exitcode-stdio-1.0
+  Default-Language:     Haskell2010
+  HS-Source-Dirs:       test
+  Ghc-Options:          -threaded -Wall
+  Main-Is:              doctests.hs
+  Build-Depends:        base
+                      , doctest >= 0.9.3
+         
diff --git a/src/DigitalOcean.hs b/src/DigitalOcean.hs
new file mode 100644
--- /dev/null
+++ b/src/DigitalOcean.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module DigitalOcean (
+  module DigitalOcean.Base,
+  module DigitalOcean.Account,
+  module DigitalOcean.Image,
+  module DigitalOcean.Droplet,
+  module DigitalOcean.Region,
+  module DigitalOcean.Size,
+  module DigitalOcean.SSHKey,
+  module DigitalOcean.NewDroplet
+                    ) where
+import DigitalOcean.Base
+import DigitalOcean.Account
+import DigitalOcean.Droplet
+import DigitalOcean.Image
+import DigitalOcean.Region
+import DigitalOcean.Size
+import DigitalOcean.SSHKey
+import DigitalOcean.NewDroplet
+
diff --git a/src/DigitalOcean/Account.hs b/src/DigitalOcean/Account.hs
new file mode 100644
--- /dev/null
+++ b/src/DigitalOcean/Account.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+
+module DigitalOcean.Account (
+  Account(..),
+  account
+                            ) where
+
+import Control.Applicative ((<$>), (<*>))
+import Control.Monad (liftM, mzero)
+import Control.Monad.IO.Class
+import Data.Aeson ((.:), FromJSON(..), Value(..), decode)
+
+import DigitalOcean.Base(Authentication, requestGet)
+
+-- $setup
+-- >>> import System.Environment
+-- >>> import DigitalOcean.Base(Authentication(..))
+-- >>> import Data.Maybe(isJust)
+
+data Account = Account {
+  dropletLimit :: Integer,
+  email :: String,
+  uuid :: String,
+  emailVerified :: Bool
+} deriving (Show, Read)
+
+newtype RawAccount = RawAccount Account
+
+instance FromJSON RawAccount where
+  parseJSON (Object v) = RawAccount <$> v .: "account"
+  parseJSON _ = mzero
+
+instance FromJSON Account where
+  parseJSON (Object v) =
+    Account <$>
+    (v .: "droplet_limit") <*>
+    (v .: "email") <*>
+    (v .: "uuid") <*>
+    (v .: "email_verified")
+  parseJSON _ = mzero
+
+-- | Get User Information
+-- >>> :{
+-- do
+--   tkn <- getEnv "DIGITAL_OCEAN_PERSONAL_ACCESS_TOKEN"
+--   mayBeAcnt <- account $ Authentication tkn
+--   print $ show $ isJust mayBeAcnt
+-- :}
+-- "True"
+account :: Authentication -> (MonadIO m) => m (Maybe Account)
+account a = liftM toAccount $ liftM decode (requestGet "account" a)
+
+toAccount :: Maybe RawAccount -> Maybe Account
+toAccount = \ra ->  case ra of Just(RawAccount a) -> Just a
+                               Nothing            -> Nothing
diff --git a/src/DigitalOcean/Base.hs b/src/DigitalOcean/Base.hs
new file mode 100644
--- /dev/null
+++ b/src/DigitalOcean/Base.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module DigitalOcean.Base (
+  Authentication(..),
+  requestGet,
+  requestPost
+                         ) where
+
+import Control.Applicative ((<$>))
+
+import Control.Monad.IO.Class
+import Data.Aeson ( ToJSON, encode)
+import qualified Data.ByteString.Lazy.Char8 as BS
+import Data.ByteString.Lazy(ByteString)
+import Network.HTTP.Conduit
+import Network.HTTP.Types.Header
+import Data.ByteString.Char8(pack)
+import Network.HTTP.Types.Method(methodPost, methodGet, Method)
+
+-- Authentication "api token"
+data Authentication = Authentication {
+  token    :: String
+} deriving (Show)
+
+
+url :: String
+url = "https://api.digitalocean.com/v2"
+
+simpleHttp' :: MonadIO m => String -> Authentication -> Method -> Maybe(ByteString) -> m BS.ByteString
+simpleHttp' url' auth reqMethod reqBody = liftIO $ withManager $ \man -> do  
+  initReq <- liftIO $ parseUrl url'
+  let req = initReq {
+        method = reqMethod,
+        requestHeaders = [(hContentType, Data.ByteString.Char8.pack "application/json"),
+                         (hAuthorization,  Data.ByteString.Char8.pack $ "Bearer " ++ (token auth))],
+        responseTimeout = Just 10000000, -- 10 seconds
+        requestBody = case reqBody of Just b  -> RequestBodyLBS b
+                                      Nothing -> requestBody initReq
+  }
+  responseBody <$> httpLbs req man
+
+
+--dumpP :: (ToJSON j) =>  String -> Authentication -> j -> (MonadIO m) => m (BS.ByteString)
+--dumpP   suburl auth body = simpleHttp' (url ++ "/" ++ suburl) auth methodPost $ Just (encode body)
+
+--dumpG ::   String -> Authentication -> (MonadIO m) => m (BS.ByteString)
+--dumpG   suburl auth = simpleHttp' (url ++ "/" ++ suburl) auth methodGet  Nothing
+
+requestGet ::  String -> Authentication -> (MonadIO m) => m BS.ByteString
+requestGet suburl auth = simpleHttp' (url ++ "/" ++ suburl)  auth methodGet Nothing
+
+
+requestPost :: (ToJSON b) =>  String -> Authentication -> b -> (MonadIO m) => m BS.ByteString
+requestPost suburl auth  body = simpleHttp' (url ++ "/" ++ suburl)  auth methodPost $ Just (encode body)
diff --git a/src/DigitalOcean/Droplet.hs b/src/DigitalOcean/Droplet.hs
new file mode 100644
--- /dev/null
+++ b/src/DigitalOcean/Droplet.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+
+module DigitalOcean.Droplet(
+  Droplet(..),
+  droplets
+                           ) where
+
+import Control.Applicative ((<$>), (<*>))
+import Control.Monad (liftM, mzero)
+import Control.Monad.IO.Class
+import Data.Aeson ((.:),  FromJSON(..), Value(..), decode)
+import DigitalOcean.Base
+
+-- $setup
+-- >>> import System.Environment
+-- >>> import DigitalOcean.Base(Authentication(..))
+-- >>> import Data.Maybe(isJust)
+
+data Droplet = Droplet {
+  did :: Integer,
+  dname :: String,
+  dmemory :: Integer,
+  dvcpus :: Integer,
+  disk :: Integer,
+  dlocked :: Bool,
+  createdAtv2 :: String,
+  dstatus :: String,
+  backupIds :: [Integer]
+} deriving (Show, Read)
+
+newtype Droplets = Droplets [Droplet]
+
+instance FromJSON Droplets where
+  parseJSON (Object v) = Droplets <$> v.: "droplets"
+  parseJSON _          = mzero
+  
+
+instance FromJSON Droplet where
+  parseJSON (Object v) =
+    Droplet <$>
+    (v .: "id") <*>
+    (v .: "name") <*>
+    (v .: "memory") <*>
+    (v .: "vcpus") <*>
+    (v .: "disk") <*>
+    (v .: "locked") <*>
+    (v .: "created_at") <*>
+    (v .: "status") <*>
+    (v .: "backup_ids")
+  parseJSON _ = mzero
+
+
+-- | List all Droplets
+--  :{
+-- do
+--   tkn <- getEnv "DIGITAL_OCEAN_PERSONAL_ACCESS_TOKEN"
+--   maybeDroplets <- droplets $ Authentication tkn
+--   print $ show $ isJust maybeDroplets
+-- :}
+-- "True"
+droplets :: Authentication -> (MonadIO m) => m (Maybe [Droplet])
+droplets a = liftM toList $ liftM decode (requestGet "droplets?page=1&per_page=100" a)
+
+toList :: Maybe Droplets -> Maybe [Droplet]
+toList = \ds ->  case ds of Just(Droplets l) -> Just l
+                            Nothing          -> Nothing
diff --git a/src/DigitalOcean/Image.hs b/src/DigitalOcean/Image.hs
new file mode 100644
--- /dev/null
+++ b/src/DigitalOcean/Image.hs
@@ -0,0 +1,79 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module DigitalOcean.Image(
+  Image(..),
+  images,
+  listAllDistributionImages
+                         ) where
+
+import Control.Applicative ((<$>), (<*>))
+import Control.Monad (liftM, mzero)
+import Control.Monad.IO.Class
+import Data.Aeson ((.:), FromJSON(..), Value(..), decode)
+import DigitalOcean.Base(Authentication, requestGet)
+
+-- $setup
+-- >>> import System.Environment
+-- >>> import DigitalOcean.Base(Authentication(..))
+-- >>> import Data.Maybe(isJust)
+
+
+data Image = Image {
+  imgId :: Integer,
+  imgName :: String,
+  imgDistribution :: String,
+  imgType :: String,
+  imgSlug :: Maybe String,
+  imgPublic :: Bool,
+  imgRegions :: [String],
+  imgMinDiskSize :: Integer,
+  imgCreatedAt :: String
+} deriving(Show, Read)
+
+-- | List all Images
+-- >>> :{
+-- do
+--   tkn <- getEnv "DIGITAL_OCEAN_PERSONAL_ACCESS_TOKEN"
+--   maybeImages <- images $ Authentication tkn
+--   print $ show $ isJust maybeImages
+-- :}
+-- "True"
+images :: Authentication -> (MonadIO m) => m (Maybe [Image])
+images a = liftM toList $ liftM decode (requestGet "images?page=1&per_page=1" a)
+
+-- | List all Distribution Images
+-- >>> :{
+-- do
+--   tkn <- getEnv "DIGITAL_OCEAN_PERSONAL_ACCESS_TOKEN"
+--   maybeImages <- listAllDistributionImages $ Authentication tkn
+--   print $ show $ isJust maybeImages
+-- :}
+-- "True"
+listAllDistributionImages :: Authentication -> (MonadIO m) => m (Maybe [Image])
+listAllDistributionImages a = liftM toList $ liftM decode (requestGet "images?page=1&per_page=100&type=distribution" a)
+
+toList :: Maybe Images -> Maybe [Image]
+toList = \ds ->  case ds of Just(Images l) -> Just l
+                            Nothing -> Nothing
+
+
+newtype Images = Images [Image]
+
+instance FromJSON Images where
+  parseJSON (Object v) = Images <$> v.: "images"
+  parseJSON _          = mzero
+
+instance FromJSON Image where
+  parseJSON (Object v) =
+    Image <$>
+    (v .: "id") <*>
+    (v .: "name") <*>
+    (v .: "distribution") <*>
+    (v .: "type") <*>
+    (v .: "slug") <*>
+    (v .: "public") <*>
+    (v .: "regions") <*>
+    (v .: "min_disk_size") <*>
+    (v .: "created_at")
+  parseJSON _ = mzero
diff --git a/src/DigitalOcean/NewDroplet.hs b/src/DigitalOcean/NewDroplet.hs
new file mode 100644
--- /dev/null
+++ b/src/DigitalOcean/NewDroplet.hs
@@ -0,0 +1,78 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+module DigitalOcean.NewDroplet(
+  newDroplet
+) where
+
+import Control.Applicative ((<$>))
+import Control.Monad (liftM, mzero)
+import Control.Monad.IO.Class
+import Data.Aeson ((.:),  FromJSON(..), Value(..), ToJSON(..), (.=), object, decode)
+
+import DigitalOcean.Droplet(Droplet(..))
+import DigitalOcean.Base
+
+-- $setup
+-- >>> {-# LANGUAGE OverloadedStrings #-}
+-- >>> import Data.ByteString.Char8
+-- >>> import System.Environment
+-- >>> import DigitalOcean.Base(Authentication(..))
+-- >>> import Data.Maybe(isJust)
+
+
+instance ToJSON NewDropletRequest where
+  toJSON v = object ["name" .= ndname v,
+                     "region" .= region v,
+                     "size" .= size v,
+                     "image" .= image v,
+                     "ssh_keys" .= ndsshKeys v,
+                     "backups" .= backups v,
+                     "ipv6" .= ipv6 v,
+                     "user_data" .= userData v,
+                     "private_networking" .= privateNetworking v
+             ]
+
+data NewDropletRequest  = NewDropletRequest {
+  ndname :: String,
+  region :: String, 
+  size :: String,
+  image :: Integer,
+  ndsshKeys :: [String],
+  backups :: Bool,
+  ipv6 :: Bool,
+  userData :: Maybe(String),
+  privateNetworking :: Bool
+} deriving (Show, Read)
+
+newtype OuterDroplet = OuterDroplet Droplet deriving(Show)
+
+instance FromJSON OuterDroplet where
+  parseJSON (Object v) = OuterDroplet <$> v .: "droplet"
+  parseJSON _          = mzero
+
+
+-- | create new Droplet
+-- :{
+-- do
+--   let d = NewDropletRequest {
+--     ndname="hoge",
+--     region="nyc3",
+--     size="512mb",
+--     image=12241402,
+--     ndsshKeys=[],
+--     backups = False,
+--     ipv6=True,
+--     userData = Nothing,
+--     privateNetworking=False
+--   }
+--   tkn <- getEnv "DIGITAL_OCEAN_PERSONAL_ACCESS_TOKEN"
+--   maybeNewDroplet <- newDroplet ( Authentication tkn) d
+--   print $ show $ isJust maybeNewDroplet 
+-- :}
+-- "True"
+newDroplet :: Authentication -> NewDropletRequest -> (MonadIO m) => m (Maybe Droplet)
+newDroplet a d = liftM toDroplet $ liftM decode (requestPost "droplets" a  d)
+
+toDroplet :: Maybe OuterDroplet -> Maybe Droplet
+toDroplet = \od -> case od of Just(OuterDroplet d) -> Just d
+                              Nothing              -> Nothing
diff --git a/src/DigitalOcean/Region.hs b/src/DigitalOcean/Region.hs
new file mode 100644
--- /dev/null
+++ b/src/DigitalOcean/Region.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module DigitalOcean.Region(
+  Region(..),
+  regions
+                          ) where
+
+import Control.Applicative ((<$>), (<*>))
+import Control.Monad (liftM, mzero)
+import Control.Monad.IO.Class
+import Data.Aeson ((.:), FromJSON(..), Value(..), decode)
+import DigitalOcean.Base(Authentication, requestGet)
+
+-- $setup
+-- >>> import System.Environment
+-- >>> import DigitalOcean.Base(Authentication(..))
+-- >>> import Data.Maybe(isJust)
+
+data Region = Region {
+  regionName :: String,
+  slug :: String,
+  available :: Bool
+} deriving (Show, Read)
+
+
+-- | List all Regions
+-- >>> :{
+-- do
+--   tkn <- getEnv "DIGITAL_OCEAN_PERSONAL_ACCESS_TOKEN"
+--   maybeRegions <- regions $ Authentication tkn
+--   print $ show $ isJust maybeRegions
+-- :}
+-- "True"
+regions :: Authentication -> (MonadIO m) => m (Maybe [Region])
+regions a = liftM toList $ liftM decode (requestGet "regions" a)
+
+
+newtype Regions = Regions [Region]
+
+instance FromJSON Regions where
+  parseJSON (Object v) = Regions <$> v.: "regions"
+  parseJSON _          = mzero
+
+instance FromJSON Region where
+  parseJSON (Object v) =
+    Region <$>
+    (v .: "name") <*>
+    (v .: "slug") <*>
+    (v .: "available")
+  parseJSON _ = mzero
+    
+
+toList :: Maybe Regions -> Maybe [Region]
+toList = \rs ->  case rs of Just(Regions l) -> Just l
+                            Nothing          -> Nothing
diff --git a/src/DigitalOcean/SSHKey.hs b/src/DigitalOcean/SSHKey.hs
new file mode 100644
--- /dev/null
+++ b/src/DigitalOcean/SSHKey.hs
@@ -0,0 +1,55 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module DigitalOcean.SSHKey (
+  SSHKey(..),
+  listAllKeys
+                            ) where
+
+import Control.Applicative ((<$>), (<*>))
+import Control.Monad (liftM, mzero)
+import Control.Monad.IO.Class
+import Data.Aeson ((.:), FromJSON(..), Value(..), decode)
+import DigitalOcean.Base(Authentication, requestGet)
+
+-- $setup
+-- >>> import System.Environment
+-- >>> import DigitalOcean.Base(Authentication(..))
+-- >>> import Data.Maybe(isJust)
+
+data SSHKey = SSHKey {
+  id :: Integer,
+  fingerprint  :: String,
+  publicKey :: String,
+  sshkeyName :: String
+} deriving (Show, Read)
+
+newtype SSHKeys = SSHKeys [SSHKey]
+
+instance FromJSON SSHKeys where
+  parseJSON (Object v) = SSHKeys <$> v .: "ssh_keys"
+  parseJSON _ = mzero
+
+instance FromJSON SSHKey where
+  parseJSON (Object v) =
+    SSHKey <$>
+    (v .: "id") <*>
+    (v .: "fingerprint") <*>
+    (v .: "public_key") <*>
+    (v .: "name")
+  parseJSON _ = mzero
+
+-- | List all Keys
+-- >>> :{
+-- do
+--   tkn <- getEnv "DIGITAL_OCEAN_PERSONAL_ACCESS_TOKEN"
+--   maybeKeys <- listAllKeys $ Authentication tkn
+--   print $ show $ isJust maybeKeys
+-- :}
+-- "True"
+listAllKeys :: Authentication -> (MonadIO m) => m (Maybe [SSHKey])
+listAllKeys a = liftM toList $ liftM decode (requestGet "account/keys" a)
+
+toList :: Maybe SSHKeys -> Maybe [SSHKey]
+toList = \sks ->  case sks of Just(SSHKeys l)  -> Just l
+                              Nothing          -> Nothing
diff --git a/src/DigitalOcean/Size.hs b/src/DigitalOcean/Size.hs
new file mode 100644
--- /dev/null
+++ b/src/DigitalOcean/Size.hs
@@ -0,0 +1,63 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+
+module DigitalOcean.Size(
+  Size(..),
+  sizes
+                        ) where
+
+import Control.Applicative ((<$>), (<*>))
+import Control.Monad (liftM, mzero)
+import Control.Monad.IO.Class
+import Data.Aeson ((.:), FromJSON(..), Value(..), decode)
+import DigitalOcean.Base(Authentication,  requestGet)
+
+-- $setup
+-- >>> import System.Environment
+-- >>> import DigitalOcean.Base(Authentication(..))
+-- >>> import Data.Maybe(isJust)
+
+data Size = Size {
+  sizSlug :: String,
+  sizAvailable  :: Bool,
+  sizTransfer :: Integer,
+  sizPriceMonthly :: Float,
+  sizHourly :: Float,
+  sizMemory :: Integer,
+  sizVcpus :: Integer,
+  sizDisk :: Integer
+} deriving(Show, Read)
+
+newtype Sizes = Sizes [Size]
+
+instance FromJSON Sizes where
+  parseJSON (Object v) = Sizes <$> v.: "sizes"
+  parseJSON _          = mzero
+
+-- | List all Sizes
+-- >>> :{
+-- do
+--   tkn <- getEnv "DIGITAL_OCEAN_PERSONAL_ACCESS_TOKEN"
+--   maybeSizes <- sizes $ Authentication tkn
+--   print $ show $ isJust maybeSizes
+-- :}
+-- "True"
+sizes :: Authentication -> (MonadIO m) => m (Maybe [Size])
+sizes  a = liftM toList $ liftM decode (requestGet "sizes" a)
+
+instance FromJSON Size where
+  parseJSON (Object v) =
+    Size <$>
+    (v .: "slug") <*>
+    (v .: "available") <*>
+    (v .: "transfer") <*>
+    (v .: "price_monthly") <*>
+    (v .: "price_hourly") <*>
+    (v .: "memory") <*>
+    (v .: "vcpus") <*>
+    (v .: "disk")
+  parseJSON _ = mzero
+   
+toList :: Maybe Sizes -> Maybe [Size]
+toList = \ss ->  case ss of Just(Sizes l) -> Just l
+                            Nothing          -> Nothing
diff --git a/test/DigitalOceanSpec.hs b/test/DigitalOceanSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/DigitalOceanSpec.hs
@@ -0,0 +1,11 @@
+module DigitalOceanSpec where
+
+import Test.Hspec
+
+spec :: Spec
+spec = do
+  describe "TODO" $ do
+    it "is empty" $ do
+      "foo" `shouldBe` "foo"
+      
+
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/test/doctests.hs b/test/doctests.hs
new file mode 100644
--- /dev/null
+++ b/test/doctests.hs
@@ -0,0 +1,21 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Main where
+
+import Test.DocTest
+
+main :: IO ()
+main = do
+  doctest ["-isrc", "src/DigitalOcean.hs"]
+{-
+  doctest [
+             "-isrc",
+             "src/DigitalOcean/Droplet.hs",
+             "src/DigitalOcean/Account.hs",
+             "src/DigitalOcean/SSHKey.hs",
+             "src/DigitalOcean/Image.hs",
+             "src/DigitalOcean/Region.hs",
+             "src/DigitalOcean/Size.hs"
+-}
+--             "src/DigitalOcean/NewDroplet.hs"
+--             ]
