@hackage json-rpc0.6.0.0

Fully-featured JSON-RPC 2.0 library

json-rpc

Fully-featured JSON-RPC 2.0 library for Haskell programs.

This JSON-RPC library is fully-compatible with JSON-RPC 2.0 and 1.0. It provides an interface that combines a JSON-RPC client and server. It can set and keep track of request ids to parse responses. There is support for sending and receiving notifications. You may use any underlying transport. Basic TCP client and server provided.

A JSON-RPC application using this interface is considered to be peer-to-peer, as it can send and receive all types of JSON-RPC message independent of whether it originated the connection.

Hackage documentation

Server Example

This JSON-RPC server returns the current time.

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
import Control.Monad.Trans
import Control.Monad.Logger
import Data.Aeson.Types hiding (Error)
import Data.Conduit.Network
import Data.Time.Clock
import Data.Time.Format
import Network.JsonRpc
import System.Locale

data TimeReq = TimeReq
data TimeRes = TimeRes { timeRes :: UTCTime }

instance FromRequest TimeReq where
    parseParams "time" = Just $ const $ return TimeReq 
    parseParams _      = Nothing

instance ToJSON TimeRes where
    toJSON (TimeRes t) = toJSON $ formatTime defaultTimeLocale "%c" t

respond :: MonadLoggerIO m => Respond TimeReq m TimeRes
respond TimeReq = do
    t <- liftIO getCurrentTime
    return . Right $ TimeRes t

main :: IO ()
main = runStderrLoggingT $ do
    let ss = serverSettings 31337 "::1"
    jsonRpcTcpServer V2 False ss srv

srv :: MonadLoggerIO m => JsonRpcT m ()
srv = do
    $(logDebug) "listening for new request"
    qM <- receiveRequest
    case qM of
        Nothing -> do
            $(logDebug) "closed request channel, exting"
            return ()
        Just q -> do
            $(logDebug) "got request"
            rM <- buildResponse respond q
            case rM of
                Nothing -> do
                    $(logDebug) "no response for this request"
                    srv
                Just r -> do
                    $(logDebug) "sending response"
                    sendResponse r >> srv

Client Example

Corresponding TCP client to get time from server.

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
import Control.Concurrent
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Logger
import Data.Aeson
import Data.Aeson.Types hiding (Error)
import Data.Conduit.Network
import qualified Data.Text as T
import Data.Time.Clock
import Data.Time.Format
import Network.JsonRpc
import System.Locale

data TimeReq = TimeReq
data TimeRes = TimeRes { timeRes :: UTCTime } deriving Show

instance ToRequest TimeReq where
    requestMethod TimeReq = "time"
    requestIsNotif = const False

instance ToJSON TimeReq where
    toJSON TimeReq = emptyArray

instance FromResponse TimeRes where
    parseResult "time" = Just $ withText "time" $ \t -> case f t of
        Just t' -> return $ TimeRes t'
        Nothing -> mzero
      where
        f t = parseTime defaultTimeLocale "%c" (T.unpack t)
    parseResult _ = Nothing

req :: MonadLoggerIO m => JsonRpcT m (Either String UTCTime)
req = do
    $(logDebug) "sending time request"
    ts <- sendRequest TimeReq
    $(logDebug) "received response"
    case ts of
        Nothing -> return $ Left "could not parse response"
        Just (Left e) -> return . Left $ fromError e
        Just (Right (TimeRes r)) -> return $ Right r

main :: IO ()
main = runStderrLoggingT $
    jsonRpcTcpClient V2 True (clientSettings 31337 "::1") $ do
        $(logDebug) "sending four time requests one second apart"
        replicateM_ 4 $ do
            req >>= liftIO . print
            liftIO (threadDelay 1000000)