Comments (2)
I made a record to represent data like this:
data GenericRPC =
GenericRPC {
service :: ByteString,
method :: ByteString
}
deriving (Eq, Show)
instance IsRPC GenericRPC where
path rpc = "/" <> service rpc <> "/" <> method rpc
and my RPC is then represented as follows:
GenericRPC "Greeter" "SayHello"
However, when I run the server and client together, this error occurs.
Right (Right ([(":status","200"),("content-type","application/grpc+proto"),("trailer","Grpc-Status"),("trailer","Grpc-Message"),("trailer","Grpc-Status-Details-Bin")],Just [("grpc-message","unknown service Greeter"),("grpc-status","12")],Left "not enough bytes"))
I made sure that both the client and server was given the same GenericRPC that I created. Not sure why the server cannot find the service.
from http2-grpc-haskell.
I think I got it. It was just me being stupid all along... But anyway, I suppose I should provide a simple example of how to use this library since there isn't any up to date examples I can find.
Since the library is expecting breaking changes, this might not work in the near future. so the versions are documented below:
http2-client-grpc - 0.8.0.0
warp-grpc - 0.3.0.0
This example demonstrates:
- How to represent RPC.
- How to create a simple unary request.
- How to encode and decode request and response.
To use this example, you need to generate your certificate and key using the following command:
openssl genrsa -out key.pem 2048
openssl req -new -key key.pem -out certificate.csr
openssl x509 -req -in certificate.csr -signkey key.pem -out certificate.pem
In Protobuf File
syntax = "proto3";
package default.v1;
service Greeter {
rpc SayHello(HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string content = 1;
}
message HelloResponse {
string content = 1;
}
The following haskell code contains a module called Proto.Greeter
and Proto.Greeter_Fields
. This is just the auto-generated code using protoc compiler on our protobuf file shown above.
The Client Code:
import qualified Network.GRPC.Client as GC
import qualified Network.HTTP2.Client as HC
import qualified Network.GRPC.Client.Helpers as GCH
import Network.GRPC.Client.Helpers (GrpcClient)
import qualified Data.ProtoLens.Message as PLM
import Network.HTTP2.Client.Exceptions (ClientIO)
import qualified Proto.Greeter as PD
import qualified Proto.Greeter_Fields as PDF
import Proto.Greeter (Greeter(..))
import Control.Monad.IO.Class (liftIO)
import qualified RPC as R
import RPC (GenericRPC)
import Proto.Greeter ( Greeter(..)
, HelloRequest(..)
, HelloResponse(..)
)
import Network.GRPC.HTTP2.Types (IsRPC(..))
mkClient :: ClientIO GrpcClient
mkClient = GCH.setupGrpcClient $ GCH.grpcClientConfigSimple "127.0.0.1" 8000 True
runClient :: ClientIO ()
runClient = do
client <- mkClient
ret <- (GCH.rawUnary sayHelloRPC client request) :: ClientIO (Either HC.TooMuchConcurrency (GC.RawReply HelloResponse))
liftIO $ print ret
return ()
where
sayHelloRPC = R.createRPC "Greeter" "SayHello"
request :: HelloRequest
request = R.createHelloRequest "CLIENT REQUEST"
The Server Code:
{-# LANGUAGE OverloadedStrings #-}
import qualified Network.GRPC.Server as S
import Network.GRPC.Server ( ServiceHandler
, UnaryHandler
)
import qualified Network.Wai.Handler.WarpTLS as WT
import Network.Wai.Handler.WarpTLS (TLSSettings)
import qualified Network.Wai.Handler.Warp as W
import Network.Wai.Handler.Warp (Settings)
import qualified Proto.Greeter as PD
import qualified Proto.Greeter_Fields as PDF
import Proto.Greeter (Greeter(..))
import Data.ProtoLens.Message as PLM
import qualified Network.GRPC.HTTP2.Encoding as GE
import qualified RPC as R
import RPC (GenericRPC)
import Proto.Greeter ( Greeter(..)
, HelloRequest(..)
, HelloResponse(..)
)
-- Some useful data types.
type TLSKeyPath = FilePath
type TLSCertPath = FilePath
-- Create a custom tls certificate given path to the key and certificate.
loadTlsSettings :: TLSCertPath -> TLSKeyPath -> TLSSettings
loadTlsSettings = WT.tlsSettings
-- Create a default tls certificate.
defaultTlsSettings :: TLSSettings
defaultTlsSettings = loadTlsSettings cp kp
where
kp = "/path/to/key.pem"
cp = "/path/to/certificate.pem"
-- Create a default warp setting.
defaultWarpSetting :: Settings
defaultWarpSetting = W.setHost "127.0.0.1" $ W.setPort 8000 W.defaultSettings
-- Create a set of handlers.
handlers :: [ServiceHandler]
handlers =
[ S.unary sayHelloRPC handleSayHello
]
where
sayHelloRPC = R.createRPC "Greeter" "SayHello"
handleSayHello :: UnaryHandler HelloRequest HelloResponse
handleSayHello _ input = do
print ("sayHello")
print $ show input
return $ R.createHelloResponse "SERVER RESPONSE"
-- Start a grpc server.
runServer :: IO ()
runServer = do
print "Server Started"
runGrpc defaultTlsSettings defaultWarpSetting handlers [GE.gzip]
print "Server Terminated"
The RPC Representation:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLabels #-}
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Data.ByteString.Builder (Builder)
import Proto3.Wire as W
import qualified Proto3.Wire.Encode as Enc
import qualified Proto3.Wire.Decode as Dec
import qualified Proto.Greeter_Fields as PDF
import qualified Proto.Greeter as PD
import qualified Data.Monoid as MND
import Proto.Greeter ( Greeter(..)
, HelloRequest(..)
, HelloResponse(..)
)
import Network.GRPC.HTTP2.Encoding ( GRPCInput(..)
, GRPCOutput(..)
, Compression(..)
, Decoder
)
import Network.GRPC.HTTP2.Types (IsRPC(..))
import qualified Data.Binary.Get as BG
import Data.Binary.Builder as BB
import Data.Bifunctor as BF
import qualified Data.ProtoLens.Labels as PLL
import Lens.Micro ( (^.)
, (&)
, (.~)
)
import qualified Data.ProtoLens.Message as PLM
import qualified Data.Text.Lazy as TL
-- A representation of an RPC.
data GenericRPC =
GenericRPC {
service :: ByteString,
method :: ByteString
}
deriving (Eq, Show)
createRPC :: ByteString -> ByteString -> GenericRPC
createRPC = GenericRPC
instance IsRPC GenericRPC where
path rpc = "/" <> service rpc <> "/" <> method rpc
-- Encoder and Decoder
class GenericEncoder a where
encode :: a -> Enc.MessageBuilder
decode :: Dec.Parser Dec.RawMessage a
instance GenericEncoder a => GRPCInput GenericRPC a where
encodeInput _ = genericEncode
decodeInput _ = genericDecode
instance GenericEncoder a => GRPCOutput GenericRPC a where
encodeOutput _ = genericEncode
decodeOutput _ = genericDecode
genericEncode :: GenericEncoder m => Compression -> m -> Builder
genericEncode compression plain =
mconcat [ BB.singleton (if _compressionByteSet compression then 1 else 0)
, BB.putWord32be (fromIntegral $ BS.length bin)
, BB.fromByteString bin
]
where
bin = _compressionFunction compression $ BL.toStrict $ Enc.toLazyByteString (encode plain)
genericDecode :: GenericEncoder m => Compression -> Decoder (Either String m)
genericDecode compression =
BG.runGetIncremental $ do
isCompressed <- BG.getInt8
let decompress = if isCompressed == 0 then pure else _decompressionFunction compression
n <- BG.getWord32be
BF.first show . Dec.parse decode <$> (decompress =<< BG.getByteString (fromIntegral n))
createHelloRequest :: TL.Text -> HelloRequest
createHelloRequest c =
PLM.defMessage
& #content .~ (TL.toStrict c)
createHelloResponse :: TL.Text -> HelloResponse
createHelloResponse c =
PLM.defMessage
& #content .~ (TL.toStrict c)
-- Making concrete encode and decode methods.
instance GenericEncoder HelloRequest where
encode r = Enc.text 1 . TL.fromStrict $ r ^. #content
decode = createHelloRequest <$> (Dec.one Dec.text MND.mempty `Dec.at` 1)
-- Making concrete encode and decode methods.
instance GenericEncoder HelloResponse where
encode r = Enc.text 1 . TL.fromStrict $ r ^. #content
decode = createHelloResponse <$> (Dec.one Dec.text MND.mempty `Dec.at` 1)
from http2-grpc-haskell.
Related Issues (20)
- Invalid HTTP header field HOT 2
- Implement Server Reflection
- Have some logo HOT 1
- Add a set of examples HOT 6
- Add a benchmark tool HOT 1
- Add performance counter hooks
- Add some form of connection manager for the client HOT 1
- Document usage with pretty pictures HOT 1
- Remove the "forked from lucasdicioccio/http2-grpc-haskell" thing from GitHub HOT 2
- Import work around Bazel HOT 1
- InvalidState: "stream error" HOT 1
- Upper bound on proto3-wire dependency breaks current builds on Nix (Stack + Nix integration)
- include .cabal file in http2-grpc-types package HOT 7
- Support unix sockets in http2-client-grpc HOT 2
- Clarify the goals of the project
- grpc client is insecure by default but doesn't advertise it in any way. HOT 5
- Resource Safe Stream Cancellation
- http2-grpc-proto-lens on Hackage is outdated HOT 2
- Examples of using these packages
- Cannot build on GHC 9
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from http2-grpc-haskell.