{"id":41161503,"url":"https://github.com/shayanh/grpc-go-contracts","last_synced_at":"2026-01-22T19:23:53.177Z","repository":{"id":56433598,"uuid":"292571723","full_name":"shayanh/grpc-go-contracts","owner":"shayanh","description":"Verify the communication of your microservices by writing contracts for your RPCs","archived":false,"fork":false,"pushed_at":"2020-11-08T10:41:36.000Z","size":112,"stargazers_count":16,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-06-20T06:40:33.471Z","etag":null,"topics":["contracts","design-by-contract","go","grpc","microservices","rpc","verification"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shayanh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-09-03T13:02:18.000Z","updated_at":"2021-08-02T11:38:51.000Z","dependencies_parsed_at":"2022-08-15T18:40:21.005Z","dependency_job_id":null,"html_url":"https://github.com/shayanh/grpc-go-contracts","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/shayanh/grpc-go-contracts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shayanh%2Fgrpc-go-contracts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shayanh%2Fgrpc-go-contracts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shayanh%2Fgrpc-go-contracts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shayanh%2Fgrpc-go-contracts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shayanh","download_url":"https://codeload.github.com/shayanh/grpc-go-contracts/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shayanh%2Fgrpc-go-contracts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28669092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T17:07:18.858Z","status":"ssl_error","status_checked_at":"2026-01-22T17:05:02.040Z","response_time":144,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["contracts","design-by-contract","go","grpc","microservices","rpc","verification"],"created_at":"2026-01-22T19:23:53.127Z","updated_at":"2026-01-22T19:23:53.172Z","avatar_url":"https://github.com/shayanh.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gRPC Go Contracts\n\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/shayanh/grpc-go-contracts/contracts)](https://pkg.go.dev/github.com/shayanh/grpc-go-contracts/contracts)\n\nVerify the communication of your microservices by writing contracts for your RPCs.\n\ngRPC Go Contracts implements contract programming (aka Design by Contract) for gRPC methods written in go. It supports: \n\n* **Preconditions**: Preconditions are conditions that must always be true just before the execution of the RPC. In a precondition, you can access RPC's input values.\n* **Postconditions**: Postconditions are conditions that must always be true just after the execution of the RPC. In a postcondition, you can access the RPC's input and return values. Moreover, you will be able to access RPC calls made by the requested RPC during the request lifetime. This allows you to verify the execution order of RPC calls, which is amazing! For more details please see the [example](#usage-and-example) below.\n\nIn the case of contract violation, gRPC Go Contracts logs the contract error message and related parameters. At this time, just unary RPCs are supported. \n\nFor more information please see: https://en.wikipedia.org/wiki/Design_by_contract\n\n## Installation\n\n```bash\n$ go get github.com/shayanh/grpc-go-contracts/contracts\n```\n\n## Usage and Example\n\nLet's consider a very simple note-taking application named MyNote. MyNote consists of two microservices:\n\n* [**NoteService**](examples/mynote/noteservice/main.go): NoteService simply stores notes. Its only API is `GetNote(note_id, token)`. `GetNote` first authenticates the input `token` by calling AuthServices. If authentication was successful, it returns the related note.\n* [**AuthService**](examples/mynote/authservice/main.go): AuthService is responsible for authentication. Its only API is `Authenticate(token)`. `Authenticate` gets a token, and if the token was valid, it returns the related user ID.\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"img/MyNote.png?raw=true\" alt=\"MyNote diagram\" width=\"50%\"\u003e\n\u003c/p\u003e\n\nProtocol buffers definition of these services:\n\n```protobuf\npackage mynote;\n\nservice NoteService {\n    rpc GetNote(GetNoteRequest) returns (Note) {}\n}\n\nmessage GetNoteRequest {\n    int32 note_id = 1;\n    string token = 2;\n}\n\nmessage Note {\n    int32 note_id = 1;\n    string text = 2;\n}\n\nservice AuthService {\n    rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse) {}\n}\n\nmessage AuthenticateRequest {\n    string token = 1;\n}\n\nmessage AuthenticateResponse {\n    int32 user_id = 1;\n}\n```\n\nNow we want to write the following precondition for `GetNote` RPC:\n\n1. `note_id` must be non-negative.\n\nAnd we want to have the following postconditions for `GetNote` RPC:\n\n1. If `GetNote` return value has no error, then `GetNote` must successfully have called `Authenticate` RPC on AuthService. We don't want a data breach!\n2. If `GetNote` return value has no error, then output note ID must be equal to input `note_id`.\n\nFirst, we define a `UnaryRPCContract` for `GetNote`:\n\n```go\ngetNoteContract := \u0026contracts.UnaryRPCContract{\n    MethodName: \"GetNote\",\n    PreConditions: []contracts.Condition{\n        func(in *pb.GetNoteRequest) error {\n            if in.NoteId \u003c 0 {\n                return errors.New(\"NoteId must be positive\")\n            }\n            return nil\n        },\n    },\n    PostConditions: []contracts.Condition{\n        func(out *pb.Note, outErr error, in *pb.GetNoteRequest, calls contracts.RPCCallHistory) error {\n            if outErr != nil {\n                return nil\n            }\n            if calls.Filter(\"mynote.AuthService\", \"Authenticate\").Successful().Empty() {\n                return errors.New(\"no successful call to auth service\")\n            }\n            return nil\n        },\n        func(out *pb.Note, outErr error, in *pb.GetNoteRequest, calls contracts.RPCCallHistory) error {\n            if outErr != nil {\n                return nil\n            }\n            if in.NoteId != out.NoteId {\n                return errors.New(\"wrong note id in response\")\n            }\n            return nil\n        },\n    },\n}\n```\n\nNext, we define a `ServiceContract` for the NoteService service and a `ServerContract` for the gRPC server:\n\n```go\nnoteServiceContract := \u0026contracts.ServiceContract{\n    ServiceName: \"mynote.NoteService\",\n    RPCContracts: []*contracts.UnaryRPCContract{\n        getNoteContract,\n    },\n}\nserverContract := contracts.NewServerContract(log.Println)\nserverContract.RegisterServiceContract(noteServiceContract)\n```\n\nFinally, we use `serverContract`'s interceptors in the gRPC server and clients:\n\n```go\n// server\ns := grpc.NewServer(grpc.UnaryInterceptor(serverContract.UnaryServerInterceptor()))\n\n// client\nconn, err := grpc.Dial(addr, grpc.WithUnaryInterceptor(serverContract.UnaryClientInterceptor()))\n```\n\nA complete version of the MyNote example containing all of the source codes is available [here](examples/mynote/).\n\n\n## API Documentation\n\nSee complete API documentation [here](https://pkg.go.dev/github.com/shayanh/grpc-go-contracts/contracts).\n\n\n## TODO\n\n- [ ] Write tests!\n- [ ] Support streaming RPCs.\n- [ ] Add terminate option on contract violation.\n- [ ] Native support of popular logging libraries.\n- [ ] Add asynchronous contract checking option.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshayanh%2Fgrpc-go-contracts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshayanh%2Fgrpc-go-contracts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshayanh%2Fgrpc-go-contracts/lists"}