Skip to content

HTTP · gRPC · CLI · Docker

vlatteAPI mocking for Go

Real HTTP and gRPC servers for your tests, that answer the way you tell them to. Match any part of a request, reply with templates, record real APIs and break things on purpose. Then serve the same mocks from files.

go get github.com/caffeine-projects/vlatte
go
func TestCharge(t *testing.T) {
	m := mockhttp.MustNew()
	m.MustStart()
	t.Cleanup(m.Close)

	paid := m.MustMock(mockhttp.Postf("/payments").
		Header("Authorization", match.HasPrefix("Bearer ")).
		Body(match.JSONPath("$.amount", match.GreaterThan(0))).
		Reply(mockhttp.Created().
			JSON(map[string]any{"id": "pay_1"})))

	client := payments.NewClient(m.URL(), "token")
	_, err := client.Charge(t.Context(), 42)

	require.NoError(t, err)
	paid.AssertCalled(t)
}
go
func TestGreeter(t *testing.T) {
	m := mockgrpc.MustNew()
	m.MustStart()
	t.Cleanup(m.Close)

	m.MustMock(mockgrpc.Method("greeter.Greeter/SayHello").
		Field("name", match.HasPrefix("a")).
		Reply(mockgrpc.Message(&pb.HelloReply{Message: "hi ann"})))

	client := pb.NewGreeterClient(m.MustDial())
	res, err := client.SayHello(t.Context(), &pb.HelloRequest{Name: "ann"})

	require.NoError(t, err)
	require.Equal(t, "hi ann", res.GetMessage())
}
yaml
# testdata/vlatte/_mocks/payments_mock.yaml
request:
  method: POST
  path: /payments
  header:
    authorization: [hasprefix, "Bearer "]
  body: [jsonpath, $.amount, [gt, 0]]
response:
  status: 201
  header:
    content-type: application/json
  body: {id: pay_1}
sh
vlatte --https --addr=:8443

curl -k https://localhost:8443/payments \
  -H 'Authorization: Bearer token' \
  -H 'Content-Type: application/json' \
  -d '{"amount": 42}'
# 201 {"id":"pay_1"}
  • 2protocolsHTTP and gRPC, one API
  • 49matchersin Go and in mock files
  • 12faultsresets, latency, garbage
  • 1binaryand a Docker image

Mocks that behave like the real thing

Everything a test needs from a server it doesn't own: the right answer, the wrong one, and the slow one.

Run it your way

The same mocks, in a test, from files, or in a container.

  • In Go tests

    A server per test, on a free port, closed when the test ends.

  • From mock files

    The vlatte command serves the YAML or JSON files of a folder.

  • In Docker Compose

    The image serves your mock files next to the app that calls them.

go
// go get github.com/caffeine-projects/vlatte
m := mockhttp.MustNew()
m.MustStart()
t.Cleanup(m.Close)

m.MustMock(mockhttp.Getf("/health").Reply(mockhttp.OK()))
sh
brew install caffeine-projects/tap/vlatte # or go install github.com/caffeine-projects/vlatte/cmd/vlatte@latest

# Serves the mock files of testdata/vlatte/_mocks.
vlatte --addr=:8080
yaml
services:
  payments:
    image: ghcr.io/caffeine-projects/vlatte:v0.1.0-rc.1
    ports: ["8080:8080"]
    volumes:
      - ./mocks:/vlatte/testdata/vlatte/_mocks:ro

HTTPS without the certificate dance

MustStartTLS serves HTTPS, or gRPC over TLS, with a certificate built in: no openssl, no files to keep.

Bring your own certificate when you need one, or ask clients for theirs with mutual TLS. The CLI and the Docker image do the same with a flag.

TLS →
go
m := mockhttp.MustNew()
m.MustStartTLS() // m.URL() starts with https://
t.Cleanup(m.Close)
go
m := mockgrpc.MustNew()
m.MustStartTLS()
t.Cleanup(m.Close)

conn := m.MustDial() // trusts the server's certificate
go
m := mockhttp.MustNew(mockhttp.Setup().
	TLSMutual("localhost.pem", "localhost-key.pem", "ca.pem"))
m.MustStartTLS()
sh
vlatte --https

Break things on purpose

Clients fail in the ways their servers do. Faults make a mock reset the connection, trickle its body, send garbage or never answer, so you see your retries and timeouts work before production does.

Chaos testing →
go
m.MustMock(
	// The first call loses its connection.
	mockhttp.Getf("/report").Once().
		WirePipe(fault.ConnectionResetByPeer()).
		Reply(mockhttp.OK()),
	// The retry gets its body over a 3G link.
	mockhttp.Getf("/report").Priority(1).
		Pipe(fault.Bandwidth(fault.Bandwidth3G)).
		Reply(mockhttp.OK().BodyFile("testdata/report.csv")),
)
yaml
request: {method: GET, path: /report}
response: {status: 200, body_file: report.csv}
pipes:
  - type: bandwidth
    rate: 3g

Mocks your AI agent can drive

Over MCP, a coding agent sees every mock, writes new ones, records a real service and checks what your client sent, with the tools the admin API serves.

Start vlatte mcp from the agent's settings, or point it at /mcp on a server that runs already.

MCP →
json
{"mcpServers": {"vlatte": {"command": "vlatte", "args": ["mcp", "--mock-files=mocks/*.yaml"]}}}
go
api := admin.MustNew(admin.MCP())
m := mockhttp.MustNew(mockhttp.Setup().Admin(api))
m.MustStart()

fmt.Println(m.AdminURL() + "/mcp") // Streamable HTTP

Toolbox

More of what comes in the box.

Ready to mock?

Write your first mock in a Go test, or serve one from a file.