---
id: "example"
title: "Usage Example: Haberdasher"
sidebar_label: "Usage Example"
---

Let's make the canonical Twirp service: a `Haberdasher`.

The `Haberdasher` service makes hats. It has only one RPC method, `MakeHat`,
which makes a new hat of a particular size.

Make sure to [Install Protobuf and Twirp](install.md) before starting.

By the end of this, we'll run a Haberdasher service with a strongly typed client.

There are 5 steps here:

 1. [Write a Protobuf service definition](#write-a-protobuf-service-definition)
 2. [Generate code](#generate-code)
 3. [Implement the server](#implement-the-server)
 4. [Mount and run the server](#mount-and-run-the-server)
 5. [Use the client](#use-the-client)

## Write a Protobuf Service Definition

Start with the proto definition file, placed in `rpc/haberdasher/service.proto`:

```protobuf
syntax = "proto3";

package twirp.example.haberdasher;
option go_package = "github.com/example/rpc/haberdasher";

// Haberdasher service makes hats for clients.
service Haberdasher {
  // MakeHat produces a hat of mysterious, randomly-selected color!
  rpc MakeHat(Size) returns (Hat);
}

// Size of a Hat, in inches.
message Size {
  int32 inches = 1; // must be > 0
}

// A Hat is a piece of headwear made by a Haberdasher.
message Hat {
  int32 inches = 1;
  string color = 2; // anything but "invisible"
  string name = 3; // i.e. "bowler"
}
```

It's a good idea to add comments on your Protobuf file. These files can work as
the primary documentation of your API. The comments also show up in the generated
Go types.

## Generate code

To generate code run the `protoc` compiler pointed at your service's `.proto`
files:

```sh
$ protoc --twirp_out=. --go_out=paths=. rpc/haberdasher/service.proto
```

See [Generator Command Line Arguments](command_line.md) for details about running the generator.

The code should be generated in the same directory as the `.proto` files.

```text
/rpc
  /haberdasher
    service.proto
    service.pb.go     # generated by protoc-gen-go
    service.twirp.go  # generated by protoc-gen-twirp
```

If you open the generated `.twirp.go` file, you should see a Go interface like this:

```go
// A Haberdasher makes hats for clients.
type Haberdasher interface {
    // MakeHat produces a hat of mysterious, randomly-selected color!
    MakeHat(context.Context, *Size) (*Hat, error)
}
```

along with code to instantiate clients and servers.


## Implement the Server

Now, our job is to write code that fulfills the `Haberdasher` interface. This
will be the "backend" logic to handle the requests.

The implementation could go in `internal/haberdasherserver/server.go`:

```go
package haberdasherserver

import (
    "context"
    "math/rand"

    "github.com/twitchtv/twirp"
    pb "github.com/example/rpc/haberdasher"
)

// Server implements the Haberdasher service
type Server struct {}

func (s *Server) MakeHat(ctx context.Context, size *pb.Size) (hat *pb.Hat, err error) {
    if size.Inches <= 0 {
        return nil, twirp.InvalidArgumentError("inches", "I can't make a hat that small!")
    }
    return &pb.Hat{
        Inches:  size.Inches,
        Color: []string{"white", "black", "brown", "red", "blue"}[rand.Intn(5)],
        Name:  []string{"bowler", "baseball cap", "top hat", "derby"}[rand.Intn(4)],
    }, nil
}
```

## Mount and run the server

To serve our Haberdasher over HTTP, use the generated server constructor
`New{{Service}}Server`. For Haberdasher, it is:

```go
func NewHaberdasherServer(svc Haberdasher, opts ...interface{}) TwirpServer
```

This constructor wraps your interface implementation as an `TwirpServer`, which
is a `http.Handler` with a few extra bells and whistles.

The `http.Handler` can be mounted like any other HTTP handler. For example,
using the standard library `http.ListenAndServe` method.

In `cmd/server/main.go`:

```go
package main

import (
    "net/http"

    "github.com/example/internal/haberdasherserver"
    "github.com/example/rpc/haberdasher"
)

func main() {
  server := &haberdasherserver.Server{} // implements Haberdasher interface
  twirpHandler := haberdasher.NewHaberdasherServer(server)

  http.ListenAndServe(":8080", twirpHandler)
}
```

If you `go run ./cmd/server/main.go`, you'll be running your server at
`localhost:8080`. All that's left is to create a client!

## Use the Client

Client stubs are automatically generated, hooray!

For each service, there are 2 client constructors:

 * `New{{Service}}ProtobufClient` for Protobuf requests.
 * `New{{Service}}JSONClient` for JSON requests.

You should use the ProtobufClient. See
[Protobuf vs JSON](protobuf_and_json.md) for comparison.

Clients in other languages can also be generated by using the respective
`protoc` plugins defined by their languages, for example [--twirp_ruby_out](https://github.com/twitchtv/twirp-ruby/wiki/Code-Generation#code-generation).

To use the `Haberdasher` service from another Go project, import the
auto-generated client.

For example, in `cmd/client/main.go`:

```go
package main

import (
    "context"
    "net/http"
    "os"
    "fmt"
    "github.com/example/rpc/haberdasher"
)

func main() {
    client := haberdasher.NewHaberdasherProtobufClient("http://localhost:8080", &http.Client{})

    hat, err := client.MakeHat(context.Background(), &haberdasher.Size{Inches: 12})
    if err != nil {
        fmt.Printf("oh no: %v", err)
        os.Exit(1)
    }
    fmt.Printf("I have a nice new hat: %+v", hat)
}
```

If you have the server running in another terminal, try running this client with
`go run ./cmd/client/main.go`. Enjoy the new hat!
