diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -1,16 +1,30 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, DeriveDataTypeable #-}
 
+import Data.Data (Data)
+import Data.Typeable (Typeable)
 import Npm.Latest (fetchLatestVersion)
-import System.Environment (getArgs)
+import System.Console.CmdArgs.Implicit (cmdArgsRun, (&=))
 
 import qualified Data.Text as T
 import qualified Data.Text.IO as TIO
+import qualified System.Console.CmdArgs.Implicit as CA
 
 
+data LatestNpmVersion = LatestNpmVersion {name :: String}
+    deriving (Show, Data, Typeable)
+
+args :: CA.Mode (CA.CmdArgs LatestNpmVersion)
+args = CA.cmdArgsMode $ LatestNpmVersion{name = CA.def &= CA.args}
+       &= CA.summary "latest-npm-version v0.1.0"
+
 main :: IO ()
 main = do
-    [name] <- getArgs
-    version <- fetchLatestVersion name
-    case version of
-        Nothing -> TIO.putStrLn "Error: fetching/parsing JSON failed"
-        Just v -> TIO.putStrLn $ T.unwords [T.pack name, v]
+    mainArgs <- cmdArgsRun args
+    let moduleName = (name mainArgs)
+    if length moduleName == 0
+        then TIO.putStrLn "Missing module name. Consult --help."
+        else do
+            version <- fetchLatestVersion moduleName
+            case version of
+                Nothing -> TIO.putStrLn "Error: fetching/parsing JSON failed"
+                Just v -> TIO.putStrLn $ T.unwords [T.pack moduleName, v]
diff --git a/Npm/Latest.hs b/Npm/Latest.hs
--- a/Npm/Latest.hs
+++ b/Npm/Latest.hs
@@ -1,39 +1,29 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-|
+Module      : Npm.Latestj
+Description : Fetch the latest version of an npm module.
+Copyright   : (c) Pascal Hartig, 2014
+License     : MIT
+Maintainer  : phartig@rdrei.net
+Stability   : experimental
+Portability : POSIX
 
+This is just an experiment of me porting a node module to Haskell and learning
+about Lenses and Pipes along the way. Use on your own risk.
+-}
 module Npm.Latest (
-    fetchLatestVersion
+    fetchLatestVersion,
+    extractVersion
 ) where
 
-import Control.Lens ((^?), _Right)
-import Control.Monad.Trans.State.Strict (evalStateT)
-import Data.Aeson (json', Value)
-import Data.Aeson.Lens (key, _String, AsValue)
-import Data.Text.Format (Format, format)
-import Network.URI (escapeURIString, isUnreserved)
-import Pipes.Attoparsec (parse, ParsingError)
-import Pipes.HTTP (parseUrl, withManager, tlsManagerSettings, withHTTP, responseBody, Request)
-
+import Npm.Latest.Internal (buildRequest, makeVersionRequest, extractVersion)
+import Data.Text.Format (Format)
 import qualified Data.Text as T
-import qualified Data.Text.Lazy as TL
 
-
 latestUrl :: Format
 latestUrl = "https://registry.npmjs.org/{}/latest"
 
-extractVersion :: AsValue s => Maybe (Either t s) -> Maybe T.Text
-extractVersion json =
-    json >>= (^? _Right . key "version" . _String)
-
-buildRequest :: String -> Format -> IO Request
-buildRequest name urlFormat =
-    parseUrl $ TL.unpack $ format urlFormat [escapeURIString isUnreserved name]
-
-makeVersionRequest :: Request -> IO (Maybe (Either ParsingError Value))
-makeVersionRequest req =
-    withManager tlsManagerSettings $ \mngr ->
-        withHTTP req mngr $ \resp ->
-            evalStateT (parse json') (responseBody resp)
-
+-- |Fetch the latest version for the given module name.
 fetchLatestVersion :: String -> IO (Maybe T.Text)
 fetchLatestVersion name = do
     req <- buildRequest name latestUrl
diff --git a/Tests/Main.hs b/Tests/Main.hs
new file mode 100644
--- /dev/null
+++ b/Tests/Main.hs
@@ -0,0 +1,22 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import Test.Hspec
+import Npm.Latest (extractVersion)
+
+import qualified Data.Text as T
+
+main :: IO ()
+main = hspec $ do
+    describe "extractVersion" $ do
+        it "returns Just for a valid JSON object" $ do
+            let json = T.unpack "{\"version\": \"1.0\"}"
+            extractVersion (Just $ Right $ json) `shouldBe` Just "1.0"
+
+        it "returns Nothing for a malformed JSON object" $ do
+            let json = T.unpack "{\"description\": \"not what we expect\"}"
+            extractVersion (Just $ Right $ json) `shouldBe` Nothing
+
+        it "returns Nothing for a malformed JSON object" $ do
+            let json = T.unpack "not even $ JSON"
+            extractVersion (Just $ Right $ json) `shouldBe` Nothing
diff --git a/latest-npm-version.cabal b/latest-npm-version.cabal
--- a/latest-npm-version.cabal
+++ b/latest-npm-version.cabal
@@ -1,5 +1,5 @@
 name:                  latest-npm-version
-version:               0.1.0
+version:               0.2.1
 synopsis:              Find the latest version of a package on npm
 homepage:              https://github.com/passy/latest-npm-version
 license:               MIT
@@ -46,5 +46,23 @@
                        aeson >= 0.7 && < 0.8,
                        pipes-attoparsec >= 0.5 && < 0.6,
                        transformers >= 0.3 && < 0.4,
-                       lens >= 4.1 && < 4.2
+                       lens >= 4.1 && < 4.2,
+                       cmdargs >= 0.10 && < 0.11
   default-language:    Haskell2010
+
+
+Test-Suite hspec-tests
+  main-is:        Tests/Main.hs
+  type:           exitcode-stdio-1.0
+  build-depends:  base,
+                  hspec,
+                  pipes-http >= 1.0 && < 1.1,
+                  pipes >= 4.1 && < 4.2,
+                  text >= 1.1 && < 1.2,
+                  text-format >= 0.3 && < 0.4,
+                  network >= 2.5 && < 2.6,
+                  pipes-bytestring >= 2.0 && < 2.1,
+                  aeson >= 0.7 && < 0.8,
+                  pipes-attoparsec >= 0.5 && < 0.6,
+                  transformers >= 0.3 && < 0.4,
+                  lens >= 4.1 && < 4.2
