Skip to main content
Kratos uses Protocol Buffers to define service APIs. This provides strong typing, automatic code generation, and support for both gRPC and HTTP protocols.

Basic API Definition

1
Create a Protobuf File
2
Create your API definition in the api/ directory:
3
syntax = "proto3";

package helloworld.v1;

option go_package = "helloworld/api/helloworld/v1;v1";

import "google/api/annotations.proto";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      get: "/helloworld/{name}"
    };
  }
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}
4
Add HTTP Annotations
5
Kratos supports HTTP bindings through Google API annotations:
6
import "google/api/annotations.proto";

service UserService {
  // GET request
  rpc GetUser (GetUserRequest) returns (User) {
    option (google.api.http) = {
      get: "/v1/users/{id}"
    };
  }
  
  // POST request with body
  rpc CreateUser (CreateUserRequest) returns (User) {
    option (google.api.http) = {
      post: "/v1/users"
      body: "*"
    };
  }
  
  // PUT request
  rpc UpdateUser (UpdateUserRequest) returns (User) {
    option (google.api.http) = {
      put: "/v1/users/{id}"
      body: "*"
    };
  }
  
  // DELETE request
  rpc DeleteUser (DeleteUserRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v1/users/{id}"
    };
  }
}
7
Define Request and Response Messages
8
Create clear, well-structured messages:
9
message GetUserRequest {
  string id = 1;
}

message CreateUserRequest {
  string name = 1;
  string email = 2;
  int32 age = 3;
}

message UpdateUserRequest {
  string id = 1;
  string name = 2;
  string email = 3;
  int32 age = 4;
}

message DeleteUserRequest {
  string id = 1;
}

message User {
  string id = 1;
  string name = 2;
  string email = 3;
  int32 age = 4;
  int64 created_at = 5;
  int64 updated_at = 6;
}

Advanced HTTP Bindings

Path Parameters

Capture variables from the URL path:
rpc GetArticle (GetArticleRequest) returns (Article) {
  option (google.api.http) = {
    get: "/v1/authors/{author_id}/articles/{article_id}"
  };
}

message GetArticleRequest {
  string author_id = 1;
  string article_id = 2;
}

Query Parameters

All fields not in the path become query parameters:
rpc ListUsers (ListUsersRequest) returns (ListUsersResponse) {
  option (google.api.http) = {
    get: "/v1/users"
  };
}

message ListUsersRequest {
  int32 page = 1;      // ?page=1
  int32 page_size = 2; // &page_size=20
  string filter = 3;   // &filter=active
}

Request Body

Specify which fields should be in the request body:
// Entire request as body
rpc CreatePost (CreatePostRequest) returns (Post) {
  option (google.api.http) = {
    post: "/v1/posts"
    body: "*"
  };
}

// Specific field as body
rpc UpdatePost (UpdatePostRequest) returns (Post) {
  option (google.api.http) = {
    patch: "/v1/posts/{id}"
    body: "post"
  };
}

message UpdatePostRequest {
  string id = 1;
  Post post = 2;
}

Multiple HTTP Bindings

Support multiple HTTP endpoints for one RPC method:
rpc Search (SearchRequest) returns (SearchResponse) {
  option (google.api.http) = {
    get: "/v1/search"
    additional_bindings {
      post: "/v1/search"
      body: "*"
    }
  };
}

Error Definitions

Define custom errors using enums with Kratos error extensions:
api/helloworld/v1/errors.proto
syntax = "proto3";

package helloworld.v1;

option go_package = "helloworld/api/helloworld/v1;v1";

import "errors/errors.proto";

enum ErrorReason {
  option (errors.default_code) = 500;
  
  USER_NOT_FOUND = 0 [(errors.code) = 404];
  USER_ALREADY_EXISTS = 1 [(errors.code) = 409];
  INVALID_ARGUMENT = 2 [(errors.code) = 400];
  UNAUTHORIZED = 3 [(errors.code) = 401];
  PERMISSION_DENIED = 4 [(errors.code) = 403];
}

Validation Rules

Add validation rules using protoc-gen-validate:
import "validate/validate.proto";

message CreateUserRequest {
  string name = 1 [(validate.rules).string = {
    min_len: 2
    max_len: 50
  }];
  
  string email = 2 [(validate.rules).string.email = true];
  
  int32 age = 3 [(validate.rules).int32 = {
    gte: 0
    lte: 150
  }];
  
  string password = 4 [(validate.rules).string = {
    min_len: 8
    pattern: "^[a-zA-Z0-9@$!%*?&]+$"
  }];
}

Metadata Service

Kratos provides a built-in metadata service for API introspection:
api/metadata/metadata.proto
syntax = "proto3";

package kratos.api;

import "google/protobuf/descriptor.proto";
import "google/api/annotations.proto";

service Metadata {
  rpc ListServices (ListServicesRequest) returns (ListServicesReply) {
    option (google.api.http) = {
      get: "/services"
    };
  }
  
  rpc GetServiceDesc (GetServiceDescRequest) returns (GetServiceDescReply) {
    option (google.api.http) = {
      get: "/services/{name}"
    };
  }
}

Best Practices

Versioning

Always version your APIs (v1, v2) to allow backward compatibility

Naming

Use clear, consistent naming: GetUser, ListUsers, CreateUser, UpdateUser, DeleteUser

RESTful URLs

Follow REST conventions: /v1/users/{id} not /v1/get_user

Error Handling

Define specific error codes for each failure case

Code Generation

After defining your APIs, generate the code:
# Generate all proto files
go generate ./...

# Or use the Makefile
make api
This generates:
  • .pb.go files (protobuf messages)
  • _http.pb.go files (HTTP bindings)
  • _grpc.pb.go files (gRPC service definitions)
  • _errors.pb.go files (error definitions)

Next Steps

Code Generation

Learn about protoc plugins and code generation

Service Implementation

Implement your service logic

Build docs developers (and LLMs) love