# twirp-haskell Very, very alpha implementation of Twirp service generation for Haskell. This project provides a number of things: 1. A protoc plugin for generating a Haskell Twirp service (based on Servant) for Services defined in a proto file. 2. A haskell library, `twirp` for quickly serving up the generated application. It requires the use of [proto-lens](https://github.com/google/proto-lens) to generate haskell datatypes from proto messages. An example, end-to-end application is included in `app`. ## Requirements 1. Install `protoc` (e.g., `brew install protoc`) 2. Install the required protoc plugins: - `cabal install proto-lens-protoc` - `go get github.com/tclem/twirp-haskell/protoc-gen-twirp_haskell` - `go get github.com/tclem/proto-lens-jsonpb/protoc-gen-jsonpb_haskell` ## Usage Use the protoc plugin to generate a twirp service and associated protobuf types from a proto file. ``` protoc -I=. --proto_path=./proto \ --plugin=protoc-gen-haskell=`which proto-lens-protoc` --haskell_out=./app \ --jsonpb_haskell_out=./app \ --plugin=protoc-gen-twirp_haskell=./script/run-twirp_haskell --twirp_haskell_out=./app/Twirp/Example/Haberdasher \ haberdasher.proto ``` The result is a couple of files that describe your service. First, here are the types that define a Servant API: ``` haskell -- Code generated by protoc-gen-twirp_haskell 0.1.0, DO NOT EDIT. {-# LANGUAGE TypeOperators #-} module Twirp.Example.Haberdasher.Haberdasher where import Servant import Twirp import Proto.Haberdasher -- This is an example set of twirp services. type HaberdasherAPI = "twirp" :> "twirp.example.haberdasher.Haberdasher" :> HaberdasherService :<|> "twirp" :> "twirp.example.haberdasher.Health" :> HealthService -- Haberdasher service makes hats for clients. type HaberdasherService -- MakeHat produces a hat of mysterious, randomly-selected color! = "MakeHat" :> ReqBody [Protobuf, JSON] Size :> Post '[Protobuf, JSON] Hat -- Get paid :<|> "GetBill" :> ReqBody [Protobuf, JSON] Hat :> Post '[Protobuf, JSON] Bill -- Health check service type HealthService = "Check" :> ReqBody [Protobuf, JSON] Ping :> Post '[Protobuf, JSON] Pong ``` The datatypes are defined in [`Proto.Haberdasher`](app/Proto/Haberdasher.hs). Plugging this into an existing warp/wai server is straightforward. See [`app/Main.hs`](app/Main.hs) for the full details: ``` haskell type RequestID = String type API = Header "X-Request-Id" RequestID :> HaberdasherAPI main :: IO () main = run 8003 app app :: Application app = twirpErrorResponses apiApp apiApp :: Application apiApp = serve (Proxy :: Proxy API) server server :: Server API server _requestID = (makeHat :<|> getBill) :<|> checkHealth ```