├── migrations └── .keep ├── config ├── dev │ └── config.yaml ├── stg │ └── config.yaml ├── local │ └── config.yaml ├── prod │ └── config.yaml └── config.yaml ├── scripts ├── pre-push.sh ├── pre-commit.sh ├── hooks.sh └── prepare-commit-msg.sh ├── func.make ├── .ra9 ├── README.md └── docker │ └── Dockerfile ├── pkg ├── sre │ ├── log │ │ ├── noop.go │ │ ├── params.go │ │ ├── lvl.go │ │ ├── writer.go │ │ ├── nocontext.go │ │ ├── global.go │ │ └── logger.go │ ├── id.go │ ├── env.go │ └── tracing │ │ ├── transport │ │ ├── http │ │ │ ├── router.go │ │ │ ├── params.go │ │ │ ├── opts.go │ │ │ └── handler.go │ │ └── grpc │ │ │ ├── params.go │ │ │ ├── server.go │ │ │ └── client.go │ │ ├── span.go │ │ └── provider.go └── config │ ├── multi.go │ ├── opts.go │ └── config.go ├── .dockerignore ├── delivery.make ├── Makefile ├── .gitignore ├── lint.make ├── internal ├── api │ ├── request.go │ ├── http │ │ ├── admin.go │ │ ├── doc.go │ │ ├── client.go │ │ ├── handler.go │ │ └── errors.go │ └── grpc │ │ └── example.go └── config │ └── config.go ├── pb ├── example.proto ├── example_grpc.pb.go └── example.pb.go ├── docs ├── swagger.yaml ├── swagger.json └── docs.go ├── .github └── workflows │ └── cicd.yaml ├── transport.make ├── db.make ├── docker-compose.yml ├── LICENSE ├── integrations └── proto │ └── google │ ├── api │ ├── annotations.proto │ ├── httpbody.proto │ └── http.proto │ └── protobuf │ ├── source_context.proto │ ├── empty.proto │ ├── struct.proto │ ├── wrappers.proto │ ├── duration.proto │ ├── any.proto │ ├── type.proto │ ├── timestamp.proto │ ├── api.proto │ ├── field_mask.proto │ └── descriptor.proto ├── env.make ├── README.md ├── go.mod ├── cmd ├── main.go └── api.go └── .golangci.yml /migrations/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/dev/config.yaml: -------------------------------------------------------------------------------- 1 | log_level: info 2 | -------------------------------------------------------------------------------- /config/stg/config.yaml: -------------------------------------------------------------------------------- 1 | log_level: warn 2 | -------------------------------------------------------------------------------- /config/local/config.yaml: -------------------------------------------------------------------------------- 1 | log_level: debug 2 | -------------------------------------------------------------------------------- /config/prod/config.yaml: -------------------------------------------------------------------------------- 1 | log_level: error 2 | -------------------------------------------------------------------------------- /scripts/pre-push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | go test ./... 4 | -------------------------------------------------------------------------------- /func.make: -------------------------------------------------------------------------------- 1 | describe_job = @echo "=====================\n$1...\n=====================" -------------------------------------------------------------------------------- /.ra9/README.md: -------------------------------------------------------------------------------- 1 | .ra9 2 | 3 | Directory for all infrastructure/deployments related files -------------------------------------------------------------------------------- /scripts/pre-commit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | make deps 4 | make imports 5 | make lint 6 | make swagger 7 | -------------------------------------------------------------------------------- /pkg/sre/log/noop.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import "go.uber.org/zap" 4 | 5 | func NewNoopLogger() Logger { 6 | return Logger{driver: zap.NewNop().Sugar()} 7 | } 8 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | bin/ 4 | githooks/ 5 | .ra9/ 6 | 7 | .gitignore 8 | .golangci.yml 9 | docker-compose.yml 10 | Makefile 11 | README.md -------------------------------------------------------------------------------- /delivery.make: -------------------------------------------------------------------------------- 1 | DOCKER_TAG ?= go-template 2 | docker-build: 3 | $(call describe_job,"Building docker image '$(DOCKER_TAG)'") 4 | docker build -f .ra9/Dockerfile -t $(DOCKER_TAG) . -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DIR:=$(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) 2 | LOCAL_BIN:=$(DIR)/bin 3 | 4 | export THIRD_PARTY_PROTO_PATH:=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))integrations/proto 5 | 6 | include *.make -------------------------------------------------------------------------------- /pkg/sre/id.go: -------------------------------------------------------------------------------- 1 | package sre 2 | 3 | const ( 4 | KeyRequestID Key = "request_id" 5 | KeyTraceID Key = "trace_id" 6 | KeySpanID Key = "span_id" 7 | ) 8 | 9 | type Key string 10 | 11 | func (k Key) String() string { 12 | return string(k) 13 | } 14 | -------------------------------------------------------------------------------- /config/config.yaml: -------------------------------------------------------------------------------- 1 | env: local 2 | ports: 3 | http: 80 4 | grpc: 82 5 | admin_http: 84 6 | data_store: 7 | url: postgres://postgres@localhost:5432/go-template?sslmode=disable 8 | tracing: 9 | enabled: true 10 | endpoint: "http://localhost:14268/api/traces" -------------------------------------------------------------------------------- /pkg/sre/env.go: -------------------------------------------------------------------------------- 1 | package sre 2 | 3 | const ( 4 | EnvLocal Env = "local" 5 | EnvDev Env = "dev" 6 | EnvStaging Env = "stg" 7 | EnvProduction Env = "prod" 8 | ) 9 | 10 | type Env string 11 | 12 | func (e Env) String() string { 13 | return string(e) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/sre/tracing/transport/http/router.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import chi "github.com/go-chi/chi/v5" 4 | 5 | // NewRouter constructor with middlewares for tracing 6 | func NewRouter(params Params) chi.Router { 7 | router := chi.NewRouter() 8 | 9 | return DecorateHandler(router, params) 10 | } 11 | -------------------------------------------------------------------------------- /scripts/hooks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp ./scripts/prepare-commit-msg.sh .git/hooks/prepare-commit-msg 4 | cp ./scripts/pre-commit.sh .git/hooks/pre-commit 5 | cp ./scripts/pre-push.sh .git/hooks/pre-push 6 | chmod 755 .git/hooks/prepare-commit-msg 7 | chmod 755 .git/hooks/pre-commit 8 | chmod 755 .git/hooks/pre-push -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | .idea/ 17 | bin/ -------------------------------------------------------------------------------- /lint.make: -------------------------------------------------------------------------------- 1 | imports: 2 | $(call describe_job,"Running imports") 3 | $(MAKE) imports-deps 4 | find . -name \*.go -not -path "./vendor/*" -not -path "*/pb/*" -not -path "./integrations/*" -exec $(LOCAL_BIN)/goimports-reviser -file-path {} -rm-unused -set-alias -format \; 5 | 6 | lint: 7 | $(call describe_job,"Running linter") 8 | $(MAKE) lint-deps 9 | $(LOCAL_BIN)/golangci-lint run 10 | -------------------------------------------------------------------------------- /internal/api/request.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import validation "github.com/go-ozzo/ozzo-validation/v4" 4 | 5 | type ( 6 | Sanitizer interface { 7 | Sanitize() 8 | } 9 | 10 | SafeRequest interface { 11 | Sanitizer 12 | validation.Validatable 13 | } 14 | ) 15 | 16 | // IsSafeRequest to check if your request can be processed 17 | func IsSafeRequest(req SafeRequest) error { 18 | req.Sanitize() 19 | 20 | return req.Validate() // nolint:wrapcheck 21 | } 22 | -------------------------------------------------------------------------------- /pkg/sre/tracing/transport/http/params.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | trace "github.com/riandyrn/otelchi" 5 | ) 6 | 7 | // Params covers all possible tracing options 8 | type Params struct { 9 | Name string 10 | ExtraOpts []trace.Option 11 | } 12 | 13 | // NewParams constructor with minimal required fields 14 | func NewParams(name string, extraOpts ...trace.Option) Params { 15 | return Params{ 16 | Name: name, 17 | ExtraOpts: extraOpts, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pb/example.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package example; 4 | option go_package = "github.com/ra9dev/go-template/pb/example"; 5 | 6 | // Example of proto import 7 | import "google/protobuf/empty.proto"; 8 | 9 | // The greeting service definition. 10 | service Greeter { 11 | // Sends a greeting 12 | rpc SayHello (google.protobuf.Empty) returns (HelloReply) {} 13 | } 14 | 15 | // The response message containing the greetings 16 | message HelloReply { 17 | string message = 1; 18 | } -------------------------------------------------------------------------------- /pkg/config/multi.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "fmt" 4 | 5 | func NewMerged(base Config, configsParams ...Params) (Config, error) { 6 | for _, params := range configsParams { 7 | config, err := New(params) 8 | if err != nil { 9 | return Config{}, fmt.Errorf("failed to create config: %w", err) 10 | } 11 | 12 | if err = base.MergeInConfig(config); err != nil { 13 | return Config{}, fmt.Errorf("failed to merge config: %w", err) 14 | } 15 | } 16 | 17 | return base, nil 18 | } 19 | -------------------------------------------------------------------------------- /pkg/sre/log/params.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import "github.com/ra9dev/go-template/pkg/sre" 4 | 5 | type Params struct { 6 | Env sre.Env 7 | Level Level 8 | } 9 | 10 | func NewParams(env sre.Env, lvl Level) Params { 11 | return Params{ 12 | Env: env, 13 | Level: lvl, 14 | } 15 | } 16 | 17 | func (p Params) withDefault() Params { 18 | if p.Env == "" { 19 | p.Env = sre.EnvProduction 20 | } 21 | 22 | if p.Level == "" { 23 | p.Level = DebugLevel 24 | } 25 | 26 | return p 27 | } 28 | -------------------------------------------------------------------------------- /pkg/sre/tracing/transport/http/opts.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | trace "github.com/riandyrn/otelchi" 5 | ) 6 | 7 | func buildOpts(handler Handler, params Params) []trace.Option { 8 | opts := []trace.Option{ 9 | trace.WithChiRoutes(handler), 10 | // this is not necessary for vendors that properly implemented the tracing specs (e.g Jaeger, AWS X-Ray, etc...) 11 | trace.WithRequestMethodInSpanName(false), 12 | } 13 | 14 | opts = append(opts, params.ExtraOpts...) 15 | 16 | return opts 17 | } 18 | -------------------------------------------------------------------------------- /scripts/prepare-commit-msg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # set -- $GIT_PARAMS 4 | 5 | BRANCH_NAME=$(git symbolic-ref --short HEAD) 6 | 7 | BRANCH_IN_COMMIT=0 8 | if [ -f $1 ]; then 9 | BRANCH_IN_COMMIT=$(grep -c "\[$BRANCH_NAME\]" $1) 10 | fi 11 | 12 | if [ -n "$BRANCH_NAME" ] && ! [[ $BRANCH_IN_COMMIT -ge 1 ]]; then 13 | if [ -f $1 ]; then 14 | BRANCH_NAME="${BRANCH_NAME/\//\/}" 15 | sed -i.bak -e "1s@^@[$BRANCH_NAME] @" $1 16 | else 17 | echo "[$BRANCH_NAME] " > "$1" 18 | fi 19 | fi 20 | 21 | exit 0 -------------------------------------------------------------------------------- /internal/api/http/admin.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | chi "github.com/go-chi/chi/v5" 5 | httpSwagger "github.com/swaggo/http-swagger" 6 | 7 | _ "github.com/ra9dev/go-template/docs" // swagger docs 8 | ) 9 | 10 | type AdminAPI struct{} 11 | 12 | func NewAdminAPI() AdminAPI { 13 | return AdminAPI{} 14 | } 15 | 16 | func (api AdminAPI) NewRouter() chi.Router { 17 | router := chi.NewRouter() 18 | 19 | router.Get("/swagger/*", httpSwagger.Handler(httpSwagger.URL("/v1/swagger/doc.json"))) 20 | 21 | return router 22 | } 23 | -------------------------------------------------------------------------------- /internal/api/http/doc.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | // @title go-template API 4 | // @version 1.0 5 | // @description go-template based project 6 | // @termsOfService https://github.com/ra9dev/go-template 7 | 8 | // @contact.name ra9dev 9 | // @contact.url https://ra9.dev 10 | // @contact.email ra9dev@gmail.com 11 | 12 | // @host api.go-template.com 13 | // @BasePath /v1 14 | 15 | // @accept json 16 | // @produce json 17 | 18 | // @schemes http https 19 | 20 | // @securityDefinitions.apikey jwt 21 | // @in header 22 | // @name Authorization 23 | -------------------------------------------------------------------------------- /docs/swagger.yaml: -------------------------------------------------------------------------------- 1 | basePath: /v1 2 | consumes: 3 | - application/json 4 | host: api.go-template.com 5 | info: 6 | contact: 7 | email: ra9dev@gmail.com 8 | name: ra9dev 9 | url: https://ra9.dev 10 | description: go-template based project 11 | termsOfService: https://github.com/ra9dev/go-template 12 | title: go-template API 13 | version: "1.0" 14 | paths: {} 15 | produces: 16 | - application/json 17 | schemes: 18 | - http 19 | - https 20 | securityDefinitions: 21 | jwt: 22 | in: header 23 | name: Authorization 24 | type: apiKey 25 | swagger: "2.0" 26 | -------------------------------------------------------------------------------- /pkg/sre/tracing/transport/grpc/params.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | trace "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" 5 | ) 6 | 7 | type ( 8 | // SpanTag key-value pair 9 | SpanTag struct { 10 | Key string 11 | Value any 12 | } 13 | 14 | // Params covers all possible tracing options 15 | Params struct { 16 | ExtraOpts []trace.Option 17 | } 18 | ) 19 | 20 | // NewParams constructor with minimal required fields 21 | func NewParams(extraOpts ...trace.Option) Params { 22 | return Params{ 23 | ExtraOpts: extraOpts, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pkg/config/opts.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/spf13/viper" 7 | ) 8 | 9 | type Option func(v *viper.Viper) 10 | 11 | func WithEnvPrefix(prefix string) Option { 12 | return func(v *viper.Viper) { 13 | v.SetEnvPrefix(prefix) 14 | } 15 | } 16 | 17 | func WithEnvKeyReplacer(r *strings.Replacer) Option { 18 | return func(v *viper.Viper) { 19 | v.SetEnvKeyReplacer(r) 20 | } 21 | } 22 | 23 | func WithDefault(data map[string]any) Option { 24 | return func(v *viper.Viper) { 25 | for key, val := range data { 26 | v.SetDefault(key, val) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/workflows/cicd.yaml: -------------------------------------------------------------------------------- 1 | name: ci/cd 2 | on: 3 | push: 4 | paths-ignore: 5 | - "**.md" 6 | - LICENCE 7 | branches: 8 | - main 9 | pull_request: 10 | env: 11 | DEFAULT_GO_VERSION: 1.19 12 | jobs: 13 | ci: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Install Go 17 | uses: actions/setup-go@v2.1.3 18 | with: 19 | go-version: ${{ env.DEFAULT_GO_VERSION }} 20 | - name: Checkout Repo 21 | uses: actions/checkout@v2 22 | - name: Run linter 23 | run: make lint 24 | - name: Run test 25 | run: go test ./... -------------------------------------------------------------------------------- /.ra9/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine as builder 2 | 3 | ENV CGO_ENABLED=0 4 | 5 | WORKDIR /usr/src/app 6 | 7 | # pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change 8 | COPY go.mod go.sum ./ 9 | RUN go mod download && go mod verify 10 | 11 | COPY . . 12 | RUN go build -v -o app cmd/*.go 13 | 14 | 15 | FROM alpine 16 | 17 | WORKDIR /usr/src/app 18 | 19 | COPY --from=builder /usr/src/app . 20 | COPY --from=builder /etc/ssl/certs /etc/ssl/certs 21 | COPY --from=builder /etc/passwd /etc/passwd 22 | COPY --from=builder /etc/group /etc/group 23 | 24 | ENTRYPOINT ["./app"] 25 | -------------------------------------------------------------------------------- /transport.make: -------------------------------------------------------------------------------- 1 | PROTOC := $(shell command -v protoc 2> /dev/null) 2 | PROTO_PATH ?= ./pb/*.proto 3 | grpc: 4 | ifndef PROTOC 5 | $(error "protoc is not installed. Visit https://grpc.io/docs/protoc-installation") 6 | endif 7 | $(call describe_job,"Generating grpc code") 8 | protoc \ 9 | --plugin=protoc-gen-go=$(LOCAL_BIN)/protoc-gen-go --go_out=. --go_opt=paths=source_relative --go_opt=M$(PROTO_PATH)=./pb \ 10 | --plugin=protoc-gen-go-grpc=$(LOCAL_BIN)/protoc-gen-go-grpc --go-grpc_out=. --go-grpc_opt=paths=source_relative --go-grpc_opt=M$(PROTO_PATH)=./pb \ 11 | -I /usr/local/include:$(THIRD_PARTY_PROTO_PATH):. \ 12 | $(PROTO_PATH) -------------------------------------------------------------------------------- /pkg/sre/tracing/transport/grpc/server.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | trace "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" 5 | "google.golang.org/grpc" 6 | ) 7 | 8 | // NewServer constructor with interceptors for tracing 9 | func NewServer(params Params, extraOpts ...grpc.ServerOption) *grpc.Server { 10 | si := trace.StreamServerInterceptor(params.ExtraOpts...) 11 | ui := trace.UnaryServerInterceptor(params.ExtraOpts...) 12 | 13 | // TODO put request info interceptor here as well 14 | opts := []grpc.ServerOption{grpc.StreamInterceptor(si), grpc.UnaryInterceptor(ui)} 15 | opts = append(opts, extraOpts...) 16 | 17 | return grpc.NewServer(opts...) 18 | } 19 | -------------------------------------------------------------------------------- /pkg/sre/tracing/transport/http/handler.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "net/http" 5 | 6 | chi "github.com/go-chi/chi/v5" 7 | trace "github.com/riandyrn/otelchi" 8 | ) 9 | 10 | // Handler is a type constraint for DecorateHandler 11 | type Handler interface { 12 | chi.Routes 13 | Use(middlewares ...func(http.Handler) http.Handler) 14 | } 15 | 16 | // DecorateHandler with tracing for any MiddlewareUser 17 | func DecorateHandler[HandlerType Handler](handler HandlerType, params Params) HandlerType { // nolint:ireturn 18 | opts := buildOpts(handler, params) 19 | 20 | // TODO put request info middleware here as well 21 | handler.Use(trace.Middleware(params.Name, opts...)) 22 | 23 | return handler 24 | } 25 | -------------------------------------------------------------------------------- /db.make: -------------------------------------------------------------------------------- 1 | DB_PORT ?= 5432 2 | DB_USER ?= postgres 3 | DB_NAME ?= go-template 4 | DB_DRIVER := postgres 5 | DB_URL ?= "$(DB_DRIVER)://$(DB_USER)@localhost:$(DB_PORT)/$(DB_NAME)?sslmode=disable" 6 | 7 | MIGRATION_NAME ?= migration 8 | MIGRATIONS_DIR ?= migrations 9 | MIGRATIONS_EXT ?= sql 10 | migration: 11 | $(call describe_job,"Generating migration '$(MIGRATION_NAME)'") 12 | $(MAKE) migrate-deps 13 | $(LOCAL_BIN)/migrate create -ext $(MIGRATIONS_EXT) -dir $(MIGRATIONS_DIR) -seq $(MIGRATION_NAME) 14 | 15 | MIGRATE_ARGS ?= up 16 | MIGRATE_URL ?= $(DB_URL) 17 | migrate: 18 | $(call describe_job,"Migrating $(MIGRATE_ARGS)") 19 | $(MAKE) migrate-deps 20 | $(LOCAL_BIN)/migrate -path $(MIGRATIONS_DIR) -verbose -database $(MIGRATE_URL) $(MIGRATE_ARGS) -------------------------------------------------------------------------------- /pkg/sre/log/lvl.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "go.uber.org/zap" 5 | "go.uber.org/zap/zapcore" 6 | ) 7 | 8 | const ( 9 | DebugLevel Level = "debug" 10 | InfoLevel Level = "info" 11 | WarnLevel Level = "warn" 12 | ErrorLevel Level = "error" 13 | ) 14 | 15 | type Level string 16 | 17 | func (lvl Level) ToZapAtomic() zap.AtomicLevel { 18 | switch lvl { 19 | case DebugLevel: 20 | return zap.NewAtomicLevelAt(zapcore.DebugLevel) 21 | case InfoLevel: 22 | return zap.NewAtomicLevelAt(zapcore.InfoLevel) 23 | case WarnLevel: 24 | return zap.NewAtomicLevelAt(zapcore.WarnLevel) 25 | case ErrorLevel: 26 | return zap.NewAtomicLevelAt(zapcore.ErrorLevel) 27 | default: 28 | return zap.NewAtomicLevelAt(zapcore.DebugLevel) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /pkg/sre/tracing/span.go: -------------------------------------------------------------------------------- 1 | package tracing 2 | 3 | import ( 4 | "context" 5 | 6 | "go.opentelemetry.io/otel/trace" 7 | ) 8 | 9 | // StartCustomSpan returns a span from the context. 10 | func StartCustomSpan( // nolint:ireturn 11 | ctx context.Context, 12 | kind trace.SpanKind, 13 | pkgName, methodName string, 14 | ) (context.Context, trace.Span) { 15 | tracer := Tracer(pkgName) 16 | 17 | return tracer.Start(ctx, methodName, trace.WithSpanKind(kind)) 18 | } 19 | 20 | // StartSpan returns a span from the context. 21 | func StartSpan(ctx context.Context, pkgName, methodName string) (context.Context, trace.Span) { //nolint:ireturn 22 | tracer := Tracer(pkgName) 23 | 24 | return tracer.Start(ctx, methodName, trace.WithSpanKind(trace.SpanKindInternal)) 25 | } 26 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | db: 5 | image: postgres:latest 6 | restart: always 7 | ports: 8 | - "5432:5432" 9 | environment: 10 | - POSTGRES_HOST_AUTH_METHOD=trust 11 | - POSTGRES_DB=go-template 12 | networks: ["go-template"] 13 | jaeger: 14 | restart: always 15 | image: jaegertracing/all-in-one:latest 16 | environment: 17 | - COLLECTOR_ZIPKIN_HTTP_PORT=9411 18 | ports: 19 | - "5775:5775/udp" 20 | - "6831:6831/udp" 21 | - "6832:6832/udp" 22 | - "5778:5778" 23 | - "16686:16686" 24 | - "14268:14268" 25 | - "14250:14250" 26 | - "9411:9411" 27 | networks: [ "go-template" ] 28 | 29 | networks: 30 | go-template: 31 | driver: bridge 32 | -------------------------------------------------------------------------------- /internal/api/http/client.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "net/http" 5 | 6 | chi "github.com/go-chi/chi/v5" 7 | 8 | _ "github.com/ra9dev/go-template/docs" // swagger docs 9 | ) 10 | 11 | type ClientAPI struct{} 12 | 13 | func NewClientAPI() ClientAPI { 14 | return ClientAPI{} 15 | } 16 | 17 | func (api ClientAPI) NewRouter() chi.Router { 18 | router := chi.NewRouter() 19 | 20 | router.Get("/ready", Handler(api.IsReady)) 21 | router.Get("/live", Handler(api.IsLive)) 22 | 23 | return router 24 | } 25 | 26 | func (api ClientAPI) IsReady(_ http.ResponseWriter, _ *http.Request) (struct{}, error) { 27 | return struct{}{}, nil 28 | } 29 | 30 | func (api ClientAPI) IsLive(_ http.ResponseWriter, _ *http.Request) (struct{}, error) { 31 | return struct{}{}, nil 32 | } 33 | -------------------------------------------------------------------------------- /pkg/sre/tracing/transport/grpc/client.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | "fmt" 5 | 6 | trace "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" 7 | "google.golang.org/grpc" 8 | ) 9 | 10 | // Dial to connect to grpc.Server at target address and trace client calls 11 | func Dial(target string, params Params, extraOpts ...grpc.DialOption) (*grpc.ClientConn, error) { 12 | si := trace.StreamClientInterceptor(params.ExtraOpts...) 13 | ui := trace.UnaryClientInterceptor(params.ExtraOpts...) 14 | 15 | opts := []grpc.DialOption{grpc.WithStreamInterceptor(si), grpc.WithUnaryInterceptor(ui)} 16 | opts = append(opts, extraOpts...) 17 | 18 | conn, err := grpc.Dial(target, opts...) 19 | if err != nil { 20 | return nil, fmt.Errorf("failed to grpc dial: %w", err) 21 | } 22 | 23 | return conn, nil 24 | } 25 | -------------------------------------------------------------------------------- /internal/api/http/handler.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "errors" 5 | "net/http" 6 | 7 | "github.com/go-chi/render" 8 | validation "github.com/go-ozzo/ozzo-validation/v4" 9 | ) 10 | 11 | func Handler[Response any]( 12 | handleFunc func(_ http.ResponseWriter, _ *http.Request) (Response, error), 13 | ) http.HandlerFunc { 14 | return func(w http.ResponseWriter, r *http.Request) { 15 | var ( 16 | httpErr Error 17 | validationErrs validation.Errors 18 | ) 19 | 20 | resp, err := handleFunc(w, r) 21 | 22 | switch { 23 | case err == nil: 24 | render.JSON(w, r, resp) 25 | case errors.As(err, &httpErr): 26 | Render(w, r, httpErr) 27 | case errors.As(err, &validationErrs): 28 | Render(w, r, NewValidationErrors(validationErrs)) 29 | default: 30 | Render(w, r, NewHTTPError(err, http.StatusInternalServerError)) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /docs/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "consumes": [ 3 | "application/json" 4 | ], 5 | "produces": [ 6 | "application/json" 7 | ], 8 | "schemes": [ 9 | "http", 10 | "https" 11 | ], 12 | "swagger": "2.0", 13 | "info": { 14 | "description": "go-template based project", 15 | "title": "go-template API", 16 | "termsOfService": "https://github.com/ra9dev/go-template", 17 | "contact": { 18 | "name": "ra9dev", 19 | "url": "https://ra9.dev", 20 | "email": "ra9dev@gmail.com" 21 | }, 22 | "version": "1.0" 23 | }, 24 | "host": "api.go-template.com", 25 | "basePath": "/v1", 26 | "paths": {}, 27 | "securityDefinitions": { 28 | "jwt": { 29 | "type": "apiKey", 30 | "name": "Authorization", 31 | "in": "header" 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /internal/api/grpc/example.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | "context" 5 | 6 | "go.opentelemetry.io/otel/trace" 7 | "google.golang.org/protobuf/types/known/emptypb" 8 | 9 | example "github.com/ra9dev/go-template/pb" 10 | "github.com/ra9dev/go-template/pkg/sre/tracing" 11 | ) 12 | 13 | type ExampleService struct { 14 | example.UnimplementedGreeterServer 15 | } 16 | 17 | func NewExampleService() ExampleService { 18 | return ExampleService{} 19 | } 20 | 21 | func (s ExampleService) SayHello(ctx context.Context, _ *emptypb.Empty) (*example.HelloReply, error) { 22 | ctx, span := tracing.StartSpan(ctx, "grpc", "exampleService.SayHello") 23 | defer span.End() 24 | 25 | exampleInternalBusinessLogicCall(ctx) 26 | 27 | return &example.HelloReply{Message: "Hello, world!"}, nil 28 | } 29 | 30 | // ExampleInternalBusinessLogicCall is an example of passing ctx and span to internal business logic. 31 | func exampleInternalBusinessLogicCall(ctx context.Context) { 32 | _, span := tracing.StartCustomSpan(ctx, trace.SpanKindInternal, "service", "someService.Hi") 33 | defer span.End() 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Sherkhan Kubaidullov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /integrations/proto/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /pkg/sre/log/writer.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import "context" 4 | 5 | type ( 6 | Writer[T any] interface { 7 | With(key string, value any) T 8 | Debug(args ...any) 9 | Debugf(template string, args ...any) 10 | Info(args ...any) 11 | Infof(template string, args ...any) 12 | Warn(args ...any) 13 | Warnf(template string, args ...any) 14 | Error(args ...any) 15 | Errorf(template string, args ...any) 16 | Panic(args ...any) 17 | Panicf(template string, args ...any) 18 | Fatal(args ...any) 19 | Fatalf(template string, args ...any) 20 | } 21 | 22 | ContextWriter[T any] interface { 23 | With(key string, value any) T 24 | Debug(ctx context.Context, args ...any) 25 | Debugf(ctx context.Context, template string, args ...any) 26 | Info(ctx context.Context, args ...any) 27 | Infof(ctx context.Context, template string, args ...any) 28 | Warn(ctx context.Context, args ...any) 29 | Warnf(ctx context.Context, template string, args ...any) 30 | Error(ctx context.Context, args ...any) 31 | Errorf(ctx context.Context, template string, args ...any) 32 | Panic(ctx context.Context, args ...any) 33 | Panicf(ctx context.Context, template string, args ...any) 34 | Fatal(ctx context.Context, args ...any) 35 | Fatalf(ctx context.Context, template string, args ...any) 36 | } 37 | ) 38 | -------------------------------------------------------------------------------- /docs/docs.go: -------------------------------------------------------------------------------- 1 | // Code generated by swaggo/swag. DO NOT EDIT. 2 | 3 | package docs 4 | 5 | import "github.com/swaggo/swag" 6 | 7 | const docTemplate = `{ 8 | "schemes": {{ marshal .Schemes }}, 9 | "consumes": [ 10 | "application/json" 11 | ], 12 | "produces": [ 13 | "application/json" 14 | ], 15 | "swagger": "2.0", 16 | "info": { 17 | "description": "{{escape .Description}}", 18 | "title": "{{.Title}}", 19 | "termsOfService": "https://github.com/ra9dev/go-template", 20 | "contact": { 21 | "name": "ra9dev", 22 | "url": "https://ra9.dev", 23 | "email": "ra9dev@gmail.com" 24 | }, 25 | "version": "{{.Version}}" 26 | }, 27 | "host": "{{.Host}}", 28 | "basePath": "{{.BasePath}}", 29 | "paths": {}, 30 | "securityDefinitions": { 31 | "jwt": { 32 | "type": "apiKey", 33 | "name": "Authorization", 34 | "in": "header" 35 | } 36 | } 37 | }` 38 | 39 | // SwaggerInfo holds exported Swagger Info so clients can modify it 40 | var SwaggerInfo = &swag.Spec{ 41 | Version: "1.0", 42 | Host: "api.go-template.com", 43 | BasePath: "/v1", 44 | Schemes: []string{"http", "https"}, 45 | Title: "go-template API", 46 | Description: "go-template based project", 47 | InfoInstanceName: "swagger", 48 | SwaggerTemplate: docTemplate, 49 | } 50 | 51 | func init() { 52 | swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) 53 | } 54 | -------------------------------------------------------------------------------- /internal/api/http/errors.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/go-chi/render" 7 | validation "github.com/go-ozzo/ozzo-validation/v4" 8 | 9 | "github.com/ra9dev/go-template/pkg/sre/log" 10 | ) 11 | 12 | type Error struct { 13 | err error 14 | Code int `json:"-"` 15 | Message string `json:"message"` 16 | } 17 | 18 | func (e Error) Error() string { 19 | return e.Message 20 | } 21 | 22 | func NewHTTPError(err error, code int) Error { 23 | message := err.Error() 24 | if code >= http.StatusInternalServerError { 25 | message = http.StatusText(code) 26 | } 27 | 28 | return Error{ 29 | err: err, 30 | Code: code, 31 | Message: message, 32 | } 33 | } 34 | 35 | func (e Error) Render(_ http.ResponseWriter, r *http.Request) error { 36 | render.Status(r, e.Code) 37 | 38 | if e.Code >= http.StatusInternalServerError { 39 | log.Errorf(r.Context(), "[HTTP] internal error: %v", e.err) 40 | } 41 | 42 | return nil 43 | } 44 | 45 | type ValidationErrors map[string]string 46 | 47 | func NewValidationErrors(source validation.Errors) ValidationErrors { 48 | errs := make(map[string]string, len(source)) 49 | 50 | for k, v := range source { 51 | errs[k] = v.Error() 52 | } 53 | 54 | return errs 55 | } 56 | 57 | func (e ValidationErrors) Render(_ http.ResponseWriter, r *http.Request) error { 58 | render.Status(r, http.StatusUnprocessableEntity) 59 | 60 | return nil 61 | } 62 | 63 | func Render(w http.ResponseWriter, r *http.Request, v render.Renderer) { 64 | if err := render.Render(w, r, v); err != nil { 65 | log.Errorf(r.Context(), "render error: %v", err) 66 | 67 | return 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /pkg/sre/log/nocontext.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import "context" 4 | 5 | var _ Writer[noContextLogger] = (*noContextLogger)(nil) 6 | 7 | type noContextLogger struct { 8 | logger Logger 9 | } 10 | 11 | func (n noContextLogger) With(key string, value any) noContextLogger { 12 | n.logger = n.logger.With(key, value) 13 | 14 | return n 15 | } 16 | 17 | func (n noContextLogger) Debug(args ...any) { 18 | n.logger.Debug(context.Background(), args...) 19 | } 20 | 21 | func (n noContextLogger) Debugf(template string, args ...any) { 22 | n.logger.Debugf(context.Background(), template, args...) 23 | } 24 | 25 | func (n noContextLogger) Info(args ...any) { 26 | n.logger.Info(context.Background(), args...) 27 | } 28 | 29 | func (n noContextLogger) Infof(template string, args ...any) { 30 | n.logger.Infof(context.Background(), template, args...) 31 | } 32 | 33 | func (n noContextLogger) Warn(args ...any) { 34 | n.logger.Warn(context.Background(), args...) 35 | } 36 | 37 | func (n noContextLogger) Warnf(template string, args ...any) { 38 | n.logger.Warnf(context.Background(), template, args...) 39 | } 40 | 41 | func (n noContextLogger) Error(args ...any) { 42 | n.logger.Error(context.Background(), args...) 43 | } 44 | 45 | func (n noContextLogger) Errorf(template string, args ...any) { 46 | n.logger.Errorf(context.Background(), template, args...) 47 | } 48 | 49 | func (n noContextLogger) Panic(args ...any) { 50 | n.logger.Panic(context.Background(), args...) 51 | } 52 | 53 | func (n noContextLogger) Panicf(template string, args ...any) { 54 | n.logger.Panicf(context.Background(), template, args...) 55 | } 56 | 57 | func (n noContextLogger) Fatal(args ...any) { 58 | n.logger.Fatal(context.Background(), args...) 59 | } 60 | 61 | func (n noContextLogger) Fatalf(template string, args ...any) { 62 | n.logger.Fatalf(context.Background(), template, args...) 63 | } 64 | -------------------------------------------------------------------------------- /pkg/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/viper" 7 | ) 8 | 9 | const ( 10 | DefaultName = "config" 11 | DefaultExtension = "yaml" 12 | DefaultPath = "." 13 | ) 14 | 15 | type ( 16 | Config struct { 17 | driver *viper.Viper 18 | } 19 | 20 | Params struct { 21 | Name string 22 | Extension string 23 | Paths []string 24 | Options []Option 25 | } 26 | ) 27 | 28 | func New(params Params) (Config, error) { 29 | if params.Name == "" { 30 | params.Name = DefaultName 31 | } 32 | 33 | if params.Extension == "" { 34 | params.Extension = DefaultExtension 35 | } 36 | 37 | if len(params.Paths) == 0 { 38 | params.Paths = append(params.Paths, DefaultPath) 39 | } 40 | 41 | driver := viper.New() 42 | driver.AutomaticEnv() 43 | driver.AllowEmptyEnv(true) 44 | driver.SetConfigName(params.Name) // name of config file (without extension) 45 | driver.SetConfigType(params.Extension) // REQUIRED if the config file does not have the extension in the name 46 | 47 | for _, path := range params.Paths { 48 | driver.AddConfigPath(path) 49 | } 50 | 51 | for _, opt := range params.Options { 52 | opt(driver) 53 | } 54 | 55 | if err := driver.ReadInConfig(); err != nil { 56 | return Config{}, fmt.Errorf("could not read config from file: %w", err) 57 | } 58 | 59 | return Config{driver: driver}, nil 60 | } 61 | 62 | func (c Config) Unmarshal(value any, opts ...viper.DecoderConfigOption) error { 63 | if err := c.driver.Unmarshal(value, opts...); err != nil { 64 | return fmt.Errorf("failed to unmarshal config of type %T: %w", value, err) 65 | } 66 | 67 | return nil 68 | } 69 | 70 | func (c Config) GetSettings() map[string]any { 71 | return c.driver.AllSettings() 72 | } 73 | 74 | func (c Config) MergeInConfig(other Config) error { 75 | settings := other.GetSettings() 76 | 77 | if err := c.driver.MergeConfigMap(settings); err != nil { 78 | return fmt.Errorf("failed to merge config: %w", err) 79 | } 80 | 81 | return nil 82 | } 83 | -------------------------------------------------------------------------------- /pkg/sre/log/global.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "context" 5 | "sync" 6 | 7 | "go.uber.org/zap" 8 | ) 9 | 10 | var ( 11 | loggerRegistration sync.Once 12 | logger = NewNoopLogger() 13 | ) 14 | 15 | // RegisterLogger by constructing Logger via NewLogger, global Logger is disabled by default 16 | func RegisterLogger(newLogger Logger) { 17 | loggerRegistration.Do(func() { 18 | logger = newLogger 19 | 20 | zap.ReplaceGlobals(logger.driver.Desugar()) 21 | }) 22 | } 23 | 24 | func Sync() error { 25 | return logger.Sync() 26 | } 27 | 28 | func NoContext() Writer[noContextLogger] { 29 | return logger.NoContext() 30 | } 31 | 32 | func With(key string, value any) Logger { 33 | return logger.With(key, value) 34 | } 35 | 36 | func Debug(ctx context.Context, args ...any) { 37 | logger.Debug(ctx, args...) 38 | } 39 | 40 | func Debugf(ctx context.Context, template string, args ...any) { 41 | logger.Debugf(ctx, template, args...) 42 | } 43 | 44 | func Info(ctx context.Context, args ...any) { 45 | logger.Info(ctx, args...) 46 | } 47 | 48 | func Infof(ctx context.Context, template string, args ...any) { 49 | logger.Infof(ctx, template, args...) 50 | } 51 | 52 | func Warn(ctx context.Context, args ...any) { 53 | logger.Warn(ctx, args...) 54 | } 55 | 56 | func Warnf(ctx context.Context, template string, args ...any) { 57 | logger.Warnf(ctx, template, args...) 58 | } 59 | 60 | func Error(ctx context.Context, args ...any) { 61 | logger.Error(ctx, args...) 62 | } 63 | 64 | func Errorf(ctx context.Context, template string, args ...any) { 65 | logger.Errorf(ctx, template, args...) 66 | } 67 | 68 | func Panic(ctx context.Context, args ...any) { 69 | logger.Panic(ctx, args...) 70 | } 71 | 72 | func Panicf(ctx context.Context, template string, args ...any) { 73 | logger.Panicf(ctx, template, args...) 74 | } 75 | 76 | func Fatal(ctx context.Context, args ...any) { 77 | logger.Fatal(ctx, args...) 78 | } 79 | 80 | func Fatalf(ctx context.Context, template string, args ...any) { 81 | logger.Fatalf(ctx, template, args...) 82 | } 83 | -------------------------------------------------------------------------------- /env.make: -------------------------------------------------------------------------------- 1 | GOLANG_CI_LINT_VERSION ?= latest 2 | lint-deps: 3 | ifeq ("$(wildcard $(LOCAL_BIN)/golangci-lint)","") 4 | GOBIN=$(LOCAL_BIN) go install -mod=mod github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANG_CI_LINT_VERSION) 5 | endif 6 | 7 | IMPORTS_REVISER_VERSION ?= latest 8 | imports-deps: 9 | ifeq ("$(wildcard $(LOCAL_BIN)/goimports-reviser)","") 10 | GOBIN=$(LOCAL_BIN) go install -mod=mod github.com/incu6us/goimports-reviser/v2@$(IMPORTS_REVISER_VERSION) 11 | endif 12 | 13 | MIGRATE_VERSION ?= latest 14 | migrate-deps: 15 | ifeq ("$(wildcard $(LOCAL_BIN)/migrate)","") 16 | GOBIN=$(LOCAL_BIN) go install -tags '$(DB_DRIVER)' -mod=mod github.com/golang-migrate/migrate/v4/cmd/migrate@$(MIGRATE_VERSION) 17 | endif 18 | 19 | SWAG_GO_VERSION ?= latest 20 | swagger-deps: 21 | ifeq ("$(wildcard $(LOCAL_BIN)/swag)","") 22 | GOBIN=$(LOCAL_BIN) go install -mod=mod github.com/swaggo/swag/cmd/swag@$(SWAG_GO_VERSION) 23 | endif 24 | 25 | PROTOC_GEN_GO_VERSION ?= latest 26 | PROTOC_GEN_GO_GRPC_VERSION ?= latest 27 | grpc-deps: 28 | ifeq ("$(wildcard $(LOCAL_BIN)/protoc-gen-go)","") 29 | GOBIN=$(LOCAL_BIN) go install -mod=mod google.golang.org/protobuf/cmd/protoc-gen-go@$(PROTOC_GEN_GO_VERSION) 30 | endif 31 | ifeq ("$(wildcard $(LOCAL_BIN)/protoc-gen-go-grpc)","") 32 | GOBIN=$(LOCAL_BIN) go install -mod=mod google.golang.org/grpc/cmd/protoc-gen-go-grpc@$(PROTOC_GEN_GO_GRPC_VERSION) 33 | endif 34 | 35 | deps: 36 | $(call describe_job,"Installing dependencies") 37 | $(MAKE) lint-deps 38 | $(MAKE) imports-deps 39 | $(MAKE) migrate-deps 40 | $(MAKE) swagger-deps 41 | $(MAKE) grpc-deps 42 | go mod tidy 43 | 44 | git-hooks: 45 | $(call describe_job,"Setting up git hooks") 46 | /bin/sh ./scripts/hooks.sh 47 | 48 | environment: 49 | $(call describe_job,"Local development setup") 50 | $(MAKE) git-hooks 51 | $(MAKE) deps 52 | docker-compose up --force-recreate --remove-orphans -d 53 | #sleep 5 TODO: uncomment when migrations are added 54 | #$(MAKE) migrate TODO: uncomment when migrations are added 55 | 56 | swagger: 57 | $(call describe_job,"Generating swagger docs") 58 | $(MAKE) swagger-deps 59 | $(LOCAL_BIN)/swag init -g internal/api/http/doc.go -p snakecase -o docs --parseInternal 60 | 61 | RUN_CMD ?= api 62 | run: 63 | $(call describe_job,"Running command $(RUN_CMD)") 64 | go run cmd/*.go $(RUN_CMD) 65 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/source_context.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option java_package = "com.google.protobuf"; 37 | option java_outer_classname = "SourceContextProto"; 38 | option java_multiple_files = true; 39 | option objc_class_prefix = "GPB"; 40 | option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; 41 | 42 | // `SourceContext` represents information about the source of a 43 | // protobuf element, like the file in which it is defined. 44 | message SourceContext { 45 | // The path-qualified name of the .proto file that contained the associated 46 | // protobuf element. For example: `"google/protobuf/source_context.proto"`. 47 | string file_name = 1; 48 | } 49 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/empty.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "google.golang.org/protobuf/types/known/emptypb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "EmptyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | option cc_enable_arenas = true; 42 | 43 | // A generic empty message that you can re-use to avoid defining duplicated 44 | // empty messages in your APIs. A typical example is to use it as the request 45 | // or the response type of an API method. For instance: 46 | // 47 | // service Foo { 48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); 49 | // } 50 | // 51 | // The JSON representation for `Empty` is empty JSON object `{}`. 52 | message Empty {} 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-template 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/ra9dev/go-template)](https://goreportcard.com/report/github.com/ra9dev/go-template) 4 | [![ci/cd](https://github.com/ra9dev/go-template/actions/workflows/cicd.yaml/badge.svg)](https://github.com/ra9dev/go-template/actions/workflows/cicd.yaml) 5 | [![Documentation](https://godoc.org/github.com/ra9dev/go-template?status.svg)](https://pkg.go.dev/mod/github.com/ra9dev/go-template) 6 | [![Release](https://img.shields.io/github/release/ra9dev/go-template.svg)](https://github.com/ra9dev/go-template/releases/latest) 7 | 8 | 9 | Template for productive high-tech creators 10 | 11 | ## Setup 12 | 13 | - Replace all occuriences of `go-template` to `your-service` 14 | - Run `make environment` 15 | 16 | ## Features 17 | 18 | ### Development 19 | 20 | - Shared git hooks: on [commit](./scripts/pre-commit.sh) and on [push](./scripts/pre-push.sh) 🪝 21 | - Friendly [graceful shutdown](https://github.com/ra9dev/shutdown) that can be used in any part of your code 🤳 22 | - [Smart fixer](https://github.com/incu6us/goimports-reviser) for your imports, keeping it within 3 blocks 🗄 23 | 24 | ### Delivery 25 | 26 | - [Multi-command](https://github.com/spf13/cobra) support 🤾🏼‍♀️ 🤾🏼 🤾🏼‍♂️ 27 | - Extensive multi-env [configuration](https://github.com/spf13/viper) via [config.yaml](./config/config.yaml), environment variables, flags 💽 28 | - Multi-port api server for: `http, admin_http, grpc` 🎏 29 | - Swagger spec [generation](https://github.com/swaggo/swag) (available at [Admin HTTP](./internal/api/http/admin.go)) 😎 30 | - Minimal Docker image ~ 25MB 🐳 31 | 32 | ### Database 33 | 34 | - [Database](./docker-compose.yml) for local development ([postgres](db.make) by default) 💾 35 | - [Migrations engine](https://github.com/golang-migrate/migrate) with predefined [make scripts](db.make) 🎼 36 | 37 | ### Site Reliability Engineering 38 | 39 | - [Traced logger](./pkg/sre/log) ✉️ 40 | - [Traced transport](./pkg/sre/tracing/transport) 🛞 41 | - Tracing via [Jaeger](https://www.jaegertracing.io/) and [OpenTelemetry](https://opentelemetry.io). 42 | View your traces at [Jaeger UI](http://localhost:16686/) 🔎 43 | 44 | ## To Be Done 45 | - SRE best practices support: profiling, metrics, etc. 46 | - Protocols support: 47 | - GRPC 48 | - automated proto dependencies fetch 49 | - swagger-like proto contracts availability 50 | - QUIC 51 | - multi-transport handlers 52 | - Dynamic configuration via etcd/consul/etc 53 | - CLI to create a service 54 | 55 | ## Star History 56 | 57 | [![Star History Chart](https://api.star-history.com/svg?repos=ra9dev/go-template&type=Date)](https://star-history.com/#ra9dev/go-template&Date) 58 | 59 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ra9dev/go-template 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/go-chi/chi/v5 v5.0.8 7 | github.com/go-chi/render v1.0.2 8 | github.com/go-ozzo/ozzo-validation/v4 v4.3.0 9 | github.com/ra9dev/shutdown v1.1.0 10 | github.com/riandyrn/otelchi v0.5.1 11 | github.com/spf13/cobra v1.7.0 12 | github.com/spf13/viper v1.15.0 13 | github.com/swaggo/http-swagger v1.3.4 14 | github.com/swaggo/swag v1.8.12 15 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 16 | go.opentelemetry.io/otel v1.14.0 17 | go.opentelemetry.io/otel/exporters/jaeger v1.14.0 18 | go.opentelemetry.io/otel/sdk v1.14.0 19 | go.opentelemetry.io/otel/trace v1.14.0 20 | go.uber.org/zap v1.24.0 21 | golang.org/x/sync v0.1.0 22 | google.golang.org/grpc v1.54.0 23 | google.golang.org/protobuf v1.30.0 24 | ) 25 | 26 | require ( 27 | github.com/KyleBanks/depth v1.2.1 // indirect 28 | github.com/ajg/form v1.5.1 // indirect 29 | github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect 30 | github.com/felixge/httpsnoop v1.0.3 // indirect 31 | github.com/fsnotify/fsnotify v1.6.0 // indirect 32 | github.com/go-logr/logr v1.2.4 // indirect 33 | github.com/go-logr/stdr v1.2.2 // indirect 34 | github.com/go-openapi/jsonpointer v0.19.6 // indirect 35 | github.com/go-openapi/jsonreference v0.20.2 // indirect 36 | github.com/go-openapi/spec v0.20.8 // indirect 37 | github.com/go-openapi/swag v0.22.3 // indirect 38 | github.com/golang/protobuf v1.5.3 // indirect 39 | github.com/hashicorp/hcl v1.0.0 // indirect 40 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 41 | github.com/josharian/intern v1.0.0 // indirect 42 | github.com/magiconair/properties v1.8.7 // indirect 43 | github.com/mailru/easyjson v0.7.7 // indirect 44 | github.com/mitchellh/mapstructure v1.5.0 // indirect 45 | github.com/pelletier/go-toml/v2 v2.0.7 // indirect 46 | github.com/spf13/afero v1.9.5 // indirect 47 | github.com/spf13/cast v1.5.0 // indirect 48 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 49 | github.com/spf13/pflag v1.0.5 // indirect 50 | github.com/subosito/gotenv v1.4.2 // indirect 51 | github.com/swaggo/files v1.0.1 // indirect 52 | go.opentelemetry.io/contrib v1.15.0 // indirect 53 | go.opentelemetry.io/otel/metric v0.37.0 // indirect 54 | go.uber.org/atomic v1.10.0 // indirect 55 | go.uber.org/multierr v1.11.0 // indirect 56 | golang.org/x/net v0.9.0 // indirect 57 | golang.org/x/sys v0.7.0 // indirect 58 | golang.org/x/text v0.9.0 // indirect 59 | golang.org/x/tools v0.8.0 // indirect 60 | google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd // indirect 61 | gopkg.in/ini.v1 v1.67.0 // indirect 62 | gopkg.in/yaml.v3 v3.0.1 // indirect 63 | ) 64 | -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/ra9dev/shutdown" 8 | "github.com/spf13/cobra" 9 | 10 | "github.com/ra9dev/go-template/internal/config" 11 | "github.com/ra9dev/go-template/pkg/sre/log" 12 | "github.com/ra9dev/go-template/pkg/sre/tracing" 13 | ) 14 | 15 | func main() { 16 | ctx, cancel := context.WithCancel(context.Background()) 17 | defer cancel() 18 | 19 | rootCmd := &cobra.Command{ 20 | Use: "go-template", 21 | Short: "Main entry-point command for the application", 22 | } 23 | 24 | cfg, err := config.NewConfig() 25 | if err != nil { 26 | log.Panicf(ctx, "failed to prepare config: %v", err) 27 | } 28 | 29 | if err = setupLogger(cfg); err != nil { 30 | log.Panic(ctx, err) 31 | } 32 | 33 | if err = setupTracing(cfg); err != nil { 34 | log.Panic(ctx, err) 35 | } 36 | 37 | rootCmd.AddCommand( 38 | APIServerCMD(cfg), 39 | ) 40 | 41 | done := make(chan struct{}) 42 | 43 | go func() { 44 | defer close(done) 45 | 46 | defer cancel() 47 | 48 | if shutdownErr := shutdown.Wait(); shutdownErr != nil { 49 | log.NoContext().Errorf("failed to shut down: %v", shutdownErr) 50 | 51 | return 52 | } 53 | 54 | log.NoContext().Info("Shutdown has been completed!") 55 | }() 56 | 57 | if err = rootCmd.ExecuteContext(ctx); err != nil { 58 | err = fmt.Errorf("failed to execute root cmd: %w", err) 59 | 60 | log.NoContext().Fatal(err) 61 | } 62 | 63 | <-done 64 | } 65 | 66 | func setupTracing(cfg config.Config) error { 67 | provider, err := tracing.NewProvider(tracing.Config{ 68 | ServiceName: config.ServiceName, 69 | ServiceVersion: config.ServiceVersion, 70 | Environment: cfg.Env.String(), 71 | Endpoint: cfg.Tracing.Endpoint, 72 | Enabled: cfg.Tracing.Enabled, 73 | }) 74 | if err != nil { 75 | return fmt.Errorf("failed to prepare tracing provider: %w", err) 76 | } 77 | 78 | shutdown.MustAdd("tracing", func(ctx context.Context) { 79 | log.NoContext().Info("Shutting down tracing provider") 80 | 81 | if err = provider.Shutdown(ctx); err != nil { 82 | log.NoContext().Error(err) 83 | 84 | return 85 | } 86 | 87 | log.NoContext().Info("Tracing provider shutdown succeeded!") 88 | }) 89 | 90 | return nil 91 | } 92 | 93 | func setupLogger(cfg config.Config) error { 94 | loggerParams := log.NewParams(cfg.Env, cfg.LogLevel) 95 | 96 | logger, err := log.NewLogger(loggerParams) 97 | if err != nil { 98 | return fmt.Errorf("failed to prepare logger: %w", err) 99 | } 100 | 101 | log.RegisterLogger(logger) 102 | 103 | shutdown.MustAdd("logger", func(_ context.Context) { 104 | log.NoContext().Infof("Flushing log buffer...") 105 | 106 | // ignoring err because there is no buffer for stderr 107 | _ = log.Sync() 108 | 109 | log.NoContext().Infof("Log buffer flushed!") 110 | }) 111 | 112 | return nil 113 | } 114 | -------------------------------------------------------------------------------- /pkg/sre/tracing/provider.go: -------------------------------------------------------------------------------- 1 | package tracing 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "go.opentelemetry.io/otel" 8 | "go.opentelemetry.io/otel/exporters/jaeger" 9 | "go.opentelemetry.io/otel/propagation" 10 | "go.opentelemetry.io/otel/sdk/resource" 11 | sdktrace "go.opentelemetry.io/otel/sdk/trace" 12 | semconv "go.opentelemetry.io/otel/semconv/v1.18.0" 13 | "go.opentelemetry.io/otel/trace" 14 | ) 15 | 16 | type Config struct { 17 | Endpoint string 18 | ServiceName string 19 | ServiceVersion string 20 | Environment string 21 | // Set this to `false` if you want to disable tracing completely. 22 | Enabled bool 23 | } 24 | 25 | // Provider is a wrapper around the OpenTelemetry tracer provider. 26 | type Provider struct { 27 | provider trace.TracerProvider 28 | } 29 | 30 | // NewProvider creates a new tracing provider. 31 | func NewProvider(config Config) (*Provider, error) { 32 | if !config.Enabled { 33 | return &Provider{ 34 | provider: trace.NewNoopTracerProvider(), 35 | }, nil 36 | } 37 | 38 | endpoint := jaeger.WithEndpoint(config.Endpoint) 39 | 40 | collection := jaeger.WithCollectorEndpoint( 41 | endpoint, 42 | ) 43 | 44 | exp, err := jaeger.New(collection) 45 | if err != nil { 46 | return nil, fmt.Errorf("failed to create Jaeger exporter: %w", err) 47 | } 48 | 49 | res, err := resource.Merge( 50 | resource.Default(), 51 | resource.NewWithAttributes( 52 | "", 53 | semconv.ServiceNameKey.String(config.ServiceName), 54 | semconv.ServiceVersionKey.String(config.ServiceVersion), 55 | semconv.DeploymentEnvironmentKey.String(config.Environment), 56 | ), 57 | ) 58 | if err != nil { 59 | return nil, fmt.Errorf("failed to create resource: %w", err) 60 | } 61 | 62 | provider := sdktrace.NewTracerProvider( 63 | sdktrace.WithSampler(sdktrace.AlwaysSample()), 64 | sdktrace.WithBatcher(exp), 65 | sdktrace.WithResource(res), 66 | ) 67 | 68 | otel.SetTracerProvider(provider) 69 | otel.SetTextMapPropagator( 70 | propagation.NewCompositeTextMapPropagator( 71 | propagation.TraceContext{}, 72 | propagation.Baggage{}, 73 | ), 74 | ) 75 | 76 | return &Provider{ 77 | provider: provider, 78 | }, nil 79 | } 80 | 81 | type shutdownable interface { 82 | Shutdown(ctx context.Context) error 83 | } 84 | 85 | // Shutdown shuts down the tracing provider. 86 | func (p Provider) Shutdown(ctx context.Context) error { 87 | if p.provider == nil { 88 | return nil 89 | } 90 | 91 | prv, ok := p.provider.(shutdownable) 92 | if !ok { 93 | return nil 94 | } 95 | 96 | if err := prv.Shutdown(ctx); err != nil { 97 | return fmt.Errorf("failed to shutdown tracing provider: %w", err) 98 | } 99 | 100 | return nil 101 | } 102 | 103 | // Tracer returns a tracer for the given name. 104 | func Tracer(name string) trace.Tracer { 105 | return otel.GetTracerProvider().Tracer(name) 106 | } 107 | -------------------------------------------------------------------------------- /integrations/proto/google/api/httpbody.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | 16 | syntax = "proto3"; 17 | 18 | package google.api; 19 | 20 | import "google/protobuf/any.proto"; 21 | 22 | option cc_enable_arenas = true; 23 | option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody"; 24 | option java_multiple_files = true; 25 | option java_outer_classname = "HttpBodyProto"; 26 | option java_package = "com.google.api"; 27 | option objc_class_prefix = "GAPI"; 28 | 29 | // Message that represents an arbitrary HTTP body. It should only be used for 30 | // payload formats that can't be represented as JSON, such as raw binary or 31 | // an HTML page. 32 | // 33 | // 34 | // This message can be used both in streaming and non-streaming API methods in 35 | // the request as well as the response. 36 | // 37 | // It can be used as a top-level request field, which is convenient if one 38 | // wants to extract parameters from either the URL or HTTP template into the 39 | // request fields and also want access to the raw HTTP body. 40 | // 41 | // Example: 42 | // 43 | // message GetResourceRequest { 44 | // // A unique request id. 45 | // string request_id = 1; 46 | // 47 | // // The raw HTTP body is bound to this field. 48 | // google.api.HttpBody http_body = 2; 49 | // } 50 | // 51 | // service ResourceService { 52 | // rpc GetResource(GetResourceRequest) returns (google.api.HttpBody); 53 | // rpc UpdateResource(google.api.HttpBody) returns 54 | // (google.protobuf.Empty); 55 | // } 56 | // 57 | // Example with streaming methods: 58 | // 59 | // service CaldavService { 60 | // rpc GetCalendar(stream google.api.HttpBody) 61 | // returns (stream google.api.HttpBody); 62 | // rpc UpdateCalendar(stream google.api.HttpBody) 63 | // returns (stream google.api.HttpBody); 64 | // } 65 | // 66 | // Use of this type only changes how the request and response bodies are 67 | // handled, all other features will continue to work unchanged. 68 | message HttpBody { 69 | // The HTTP Content-Type header value specifying the content type of the body. 70 | string content_type = 1; 71 | 72 | // The HTTP request/response body as raw binary. 73 | bytes data = 2; 74 | 75 | // Application specific response metadata. Must be set in the first response 76 | // for streaming APIs. 77 | repeated google.protobuf.Any extensions = 3; 78 | } 79 | -------------------------------------------------------------------------------- /pkg/sre/log/logger.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "go.opentelemetry.io/otel/trace" 8 | "go.uber.org/zap" 9 | 10 | "github.com/ra9dev/go-template/pkg/sre" 11 | ) 12 | 13 | var _ ContextWriter[Logger] = (*Logger)(nil) 14 | 15 | type Logger struct { 16 | driver *zap.SugaredLogger 17 | } 18 | 19 | func NewLogger(params Params) (Logger, error) { 20 | params = params.withDefault() 21 | 22 | var cfg zap.Config 23 | 24 | switch params.Env { 25 | case sre.EnvLocal, sre.EnvDev: 26 | cfg = zap.NewDevelopmentConfig() 27 | default: 28 | cfg = zap.NewProductionConfig() 29 | } 30 | 31 | cfg.Level = params.Level.ToZapAtomic() 32 | 33 | driver, err := cfg.Build() 34 | if err != nil { 35 | return Logger{}, fmt.Errorf("could not build logger: %w", err) 36 | } 37 | 38 | return Logger{ 39 | driver: driver.Sugar(), 40 | }, nil 41 | } 42 | 43 | func (l Logger) Sync() error { 44 | return l.driver.Sync() // nolint:wrapcheck 45 | } 46 | 47 | func (l Logger) NoContext() Writer[noContextLogger] { 48 | return noContextLogger{logger: l} 49 | } 50 | 51 | func (l Logger) With(key string, value any) Logger { 52 | l.driver = l.driver.With(key, value) 53 | 54 | return l 55 | } 56 | 57 | func (l Logger) withKeys(ctx context.Context) Logger { 58 | loggerWithKeys := l 59 | 60 | if span := trace.SpanFromContext(ctx); span.IsRecording() { 61 | loggerWithKeys = loggerWithKeys. 62 | With(sre.KeyTraceID.String(), span.SpanContext().TraceID()). 63 | With(sre.KeySpanID.String(), span.SpanContext().SpanID()) 64 | } 65 | 66 | if requestID := ctx.Value(sre.KeyRequestID); requestID != nil { 67 | loggerWithKeys = loggerWithKeys.With(sre.KeyRequestID.String(), requestID) 68 | } 69 | 70 | return loggerWithKeys 71 | } 72 | 73 | func (l Logger) Debug(ctx context.Context, args ...any) { 74 | l.withKeys(ctx).driver.Debug(args...) 75 | } 76 | 77 | func (l Logger) Debugf(ctx context.Context, template string, args ...any) { 78 | l.withKeys(ctx).driver.Debugf(template, args...) 79 | } 80 | 81 | func (l Logger) Info(ctx context.Context, args ...any) { 82 | l.withKeys(ctx).driver.Info(args...) 83 | } 84 | 85 | func (l Logger) Infof(ctx context.Context, template string, args ...any) { 86 | l.withKeys(ctx).driver.Infof(template, args...) 87 | } 88 | 89 | func (l Logger) Warn(ctx context.Context, args ...any) { 90 | l.withKeys(ctx).driver.Warn(args...) 91 | } 92 | 93 | func (l Logger) Warnf(ctx context.Context, template string, args ...any) { 94 | l.withKeys(ctx).driver.Warnf(template, args...) 95 | } 96 | 97 | func (l Logger) Error(ctx context.Context, args ...any) { 98 | l.withKeys(ctx).driver.Error(args...) 99 | } 100 | 101 | func (l Logger) Errorf(ctx context.Context, template string, args ...any) { 102 | l.withKeys(ctx).driver.Errorf(template, args...) 103 | } 104 | 105 | func (l Logger) Panic(ctx context.Context, args ...any) { 106 | l.withKeys(ctx).driver.Panic(args...) 107 | } 108 | 109 | func (l Logger) Panicf(ctx context.Context, template string, args ...any) { 110 | l.withKeys(ctx).driver.Panicf(template, args...) 111 | } 112 | 113 | func (l Logger) Fatal(ctx context.Context, args ...any) { 114 | l.withKeys(ctx).driver.Fatal(args...) 115 | } 116 | 117 | func (l Logger) Fatalf(ctx context.Context, template string, args ...any) { 118 | l.withKeys(ctx).driver.Fatalf(template, args...) 119 | } 120 | -------------------------------------------------------------------------------- /internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/ra9dev/go-template/pkg/config" 8 | "github.com/ra9dev/go-template/pkg/sre" 9 | "github.com/ra9dev/go-template/pkg/sre/log" 10 | ) 11 | 12 | const defaultConfigPath = "./config" 13 | 14 | var defaultEnvKeyReplacer = strings.NewReplacer(".", "_") 15 | 16 | const ( 17 | defaultHTTPPort = 80 18 | defaultGRPCPort = 82 19 | defaultHTTPAdminPort = 84 20 | defaultEnv = "local" 21 | ) 22 | 23 | const ( 24 | ServiceName = "go-template" 25 | ServiceVersion = "1.0.0" 26 | ) 27 | 28 | type Config struct { 29 | Env sre.Env `mapstructure:"env"` 30 | LogLevel log.Level `mapstructure:"log_level"` 31 | Ports PortsConfig `mapstructure:"ports"` 32 | DataStore DataStoreConfig `mapstructure:"data_store"` 33 | Tracing TracingConfig `mapstructure:"tracing"` 34 | } 35 | 36 | type PortsConfig struct { 37 | HTTP uint `mapstructure:"http"` 38 | GRPC uint `mapstructure:"grpc"` 39 | AdminHTTP uint `mapstructure:"admin_http"` 40 | } 41 | 42 | type DataStoreConfig struct { 43 | URL string `mapstructure:"url"` 44 | } 45 | 46 | type TracingConfig struct { 47 | Enabled bool `mapstructure:"enabled"` 48 | Endpoint string `mapstructure:"endpoint"` 49 | } 50 | 51 | func NewConfig() (Config, error) { 52 | paths := []string{defaultConfigPath} 53 | 54 | defaultConfig := map[string]any{ 55 | "env": defaultEnv, 56 | "ports.http": defaultHTTPPort, 57 | "ports.grpc": defaultGRPCPort, 58 | "ports.admin_http": defaultHTTPAdminPort, 59 | } 60 | 61 | defaultOpts := []config.Option{ 62 | config.WithEnvKeyReplacer(defaultEnvKeyReplacer), 63 | } 64 | 65 | rawCfg, err := config.New( 66 | config.Params{ 67 | Paths: paths, 68 | Options: append([]config.Option{config.WithDefault(defaultConfig)}, defaultOpts...), 69 | }, 70 | ) 71 | if err != nil { 72 | return Config{}, fmt.Errorf("could not create config: %w", err) 73 | } 74 | 75 | baseConfig := Config{} 76 | if err = rawCfg.Unmarshal(&baseConfig); err != nil { 77 | return Config{}, fmt.Errorf("could not unmarshal config: %w", err) 78 | } 79 | 80 | if additionalConfigsParams := getAdditionalConfigs(baseConfig, paths); len(additionalConfigsParams) > 0 { 81 | for i := range additionalConfigsParams { 82 | additionalConfigsParams[i].Options = append(additionalConfigsParams[i].Options, defaultOpts...) 83 | } 84 | 85 | rawCfg, err = config.NewMerged(rawCfg, additionalConfigsParams...) 86 | if err != nil { 87 | return Config{}, fmt.Errorf("could not merge configs: %w", err) 88 | } 89 | } 90 | 91 | if err = rawCfg.Unmarshal(&baseConfig); err != nil { 92 | return Config{}, fmt.Errorf("could not unmarshal config: %w", err) 93 | } 94 | 95 | return baseConfig, nil 96 | } 97 | 98 | func getAdditionalConfigs(baseConfig Config, basePaths []string) []config.Params { 99 | additionalConfigsParams := make([]config.Params, 0) 100 | 101 | if baseConfig.Env != "" { 102 | envPaths := make([]string, 0, len(basePaths)) 103 | 104 | for _, path := range basePaths { 105 | envPaths = append(envPaths, fmt.Sprintf("%s/%s", path, baseConfig.Env)) 106 | } 107 | 108 | additionalConfigsParams = append( 109 | additionalConfigsParams, 110 | config.Params{ 111 | Paths: envPaths, 112 | }, 113 | ) 114 | } 115 | 116 | return additionalConfigsParams 117 | } 118 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | skip-dirs: 3 | - vendor 4 | modules-download-mode: mod 5 | 6 | linters: 7 | disable-all: true 8 | enable: 9 | - asciicheck 10 | - bodyclose 11 | - cyclop 12 | - decorder 13 | - depguard 14 | - dogsled 15 | - dupl 16 | - durationcheck 17 | - errcheck 18 | - errchkjson 19 | - errname 20 | - errorlint 21 | - execinquery 22 | - exportloopref 23 | - forcetypeassert 24 | - gocognit 25 | - goconst 26 | - gocritic 27 | - gocyclo 28 | - gofmt 29 | - gofumpt 30 | - goheader 31 | - goimports 32 | - gomoddirectives 33 | - gomodguard 34 | - gomnd 35 | - gosec 36 | - gosimple 37 | - govet 38 | - importas 39 | - ineffassign 40 | - lll 41 | - makezero 42 | - misspell 43 | - nakedret 44 | - nestif 45 | - nilerr 46 | - nilnil 47 | - noctx 48 | - paralleltest 49 | - prealloc 50 | - predeclared 51 | - revive 52 | - rowserrcheck 53 | - sqlclosecheck 54 | - unconvert 55 | - unused 56 | - unparam 57 | - wastedassign 58 | - wrapcheck 59 | - whitespace 60 | - wsl 61 | 62 | issues: 63 | # Restricts maximum count of issues to display with the same text, and show all instead. 64 | max-same-issues: 0 65 | max-issues-per-linter: 0 66 | exclude: 67 | - Line contains TODO/BUG/FIXME 68 | 69 | linters-settings: 70 | tagliatelle: 71 | # Check the struck tag name case. 72 | case: 73 | # Use the struct field name to check the name of the struct tag. 74 | # Default: false 75 | use-field-name: true 76 | rules: 77 | json: snake 78 | varnamelen: 79 | # The longest distance, in source lines, that is being considered a "small scope". 80 | # Variables used in at most this many lines will be ignored. 81 | # Default: 5 82 | max-distance: 20 83 | # The minimum length of a variable's name that is considered "long". 84 | # Variable names that are at least this long will be ignored. 85 | # Default: 3 86 | min-name-length: 2 87 | # Check method receivers. 88 | # Default: false 89 | check-receiver: true 90 | # Check named return values. 91 | # Default: false 92 | check-return: true 93 | # Check type parameters. 94 | # Default: false 95 | check-type-param: true 96 | # Optional list of variable names that should be ignored completely. 97 | # Default: [] 98 | ignore-names: 99 | - err 100 | # Optional list of variable declarations that should be ignored completely. 101 | # Entries must be in one of the following forms (see below for examples): 102 | # - for variables, parameters, named return values, method receivers, or type parameters: 103 | # ( can also be a pointer/slice/map/chan/...) 104 | # - for constants: const 105 | # 106 | # Default: [] 107 | ignore-decls: 108 | - w http.ResponseWriter 109 | - r *http.Request 110 | wsl: 111 | # Allow multiple var/declaration statements to be cuddled. 112 | # Default: false 113 | allow-cuddle-declarations: true 114 | # Causes an error when an If statement that checks an error variable doesn't 115 | # cuddle with the assignment of that variable. 116 | # Default: false 117 | enforce-err-cuddling: true 118 | wrapcheck: 119 | ignorePackageGlobs: 120 | - google.golang.org/grpc/status 121 | -------------------------------------------------------------------------------- /pb/example_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-go-grpc v1.2.0 4 | // - protoc v3.21.5 5 | // source: pb/example.proto 6 | 7 | package example 8 | 9 | import ( 10 | context "context" 11 | grpc "google.golang.org/grpc" 12 | codes "google.golang.org/grpc/codes" 13 | status "google.golang.org/grpc/status" 14 | emptypb "google.golang.org/protobuf/types/known/emptypb" 15 | ) 16 | 17 | // This is a compile-time assertion to ensure that this generated file 18 | // is compatible with the grpc package it is being compiled against. 19 | // Requires gRPC-Go v1.32.0 or later. 20 | const _ = grpc.SupportPackageIsVersion7 21 | 22 | // GreeterClient is the client API for Greeter service. 23 | // 24 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 25 | type GreeterClient interface { 26 | // Sends a greeting 27 | SayHello(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*HelloReply, error) 28 | } 29 | 30 | type greeterClient struct { 31 | cc grpc.ClientConnInterface 32 | } 33 | 34 | func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient { 35 | return &greeterClient{cc} 36 | } 37 | 38 | func (c *greeterClient) SayHello(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*HelloReply, error) { 39 | out := new(HelloReply) 40 | err := c.cc.Invoke(ctx, "/example.Greeter/SayHello", in, out, opts...) 41 | if err != nil { 42 | return nil, err 43 | } 44 | return out, nil 45 | } 46 | 47 | // GreeterServer is the server API for Greeter service. 48 | // All implementations must embed UnimplementedGreeterServer 49 | // for forward compatibility 50 | type GreeterServer interface { 51 | // Sends a greeting 52 | SayHello(context.Context, *emptypb.Empty) (*HelloReply, error) 53 | mustEmbedUnimplementedGreeterServer() 54 | } 55 | 56 | // UnimplementedGreeterServer must be embedded to have forward compatible implementations. 57 | type UnimplementedGreeterServer struct { 58 | } 59 | 60 | func (UnimplementedGreeterServer) SayHello(context.Context, *emptypb.Empty) (*HelloReply, error) { 61 | return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") 62 | } 63 | func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {} 64 | 65 | // UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service. 66 | // Use of this interface is not recommended, as added methods to GreeterServer will 67 | // result in compilation errors. 68 | type UnsafeGreeterServer interface { 69 | mustEmbedUnimplementedGreeterServer() 70 | } 71 | 72 | func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) { 73 | s.RegisterService(&Greeter_ServiceDesc, srv) 74 | } 75 | 76 | func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 77 | in := new(emptypb.Empty) 78 | if err := dec(in); err != nil { 79 | return nil, err 80 | } 81 | if interceptor == nil { 82 | return srv.(GreeterServer).SayHello(ctx, in) 83 | } 84 | info := &grpc.UnaryServerInfo{ 85 | Server: srv, 86 | FullMethod: "/example.Greeter/SayHello", 87 | } 88 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 89 | return srv.(GreeterServer).SayHello(ctx, req.(*emptypb.Empty)) 90 | } 91 | return interceptor(ctx, in, info, handler) 92 | } 93 | 94 | // Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service. 95 | // It's only intended for direct use with grpc.RegisterService, 96 | // and not to be introspected or modified (even as a copy) 97 | var Greeter_ServiceDesc = grpc.ServiceDesc{ 98 | ServiceName: "example.Greeter", 99 | HandlerType: (*GreeterServer)(nil), 100 | Methods: []grpc.MethodDesc{ 101 | { 102 | MethodName: "SayHello", 103 | Handler: _Greeter_SayHello_Handler, 104 | }, 105 | }, 106 | Streams: []grpc.StreamDesc{}, 107 | Metadata: "pb/example.proto", 108 | } 109 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/struct.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "google.golang.org/protobuf/types/known/structpb"; 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "StructProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // `Struct` represents a structured data value, consisting of fields 44 | // which map to dynamically typed values. In some languages, `Struct` 45 | // might be supported by a native representation. For example, in 46 | // scripting languages like JS a struct is represented as an 47 | // object. The details of that representation are described together 48 | // with the proto support for the language. 49 | // 50 | // The JSON representation for `Struct` is JSON object. 51 | message Struct { 52 | // Unordered map of dynamically typed values. 53 | map fields = 1; 54 | } 55 | 56 | // `Value` represents a dynamically typed value which can be either 57 | // null, a number, a string, a boolean, a recursive struct value, or a 58 | // list of values. A producer of value is expected to set one of that 59 | // variants, absence of any variant indicates an error. 60 | // 61 | // The JSON representation for `Value` is JSON value. 62 | message Value { 63 | // The kind of value. 64 | oneof kind { 65 | // Represents a null value. 66 | NullValue null_value = 1; 67 | // Represents a double value. 68 | double number_value = 2; 69 | // Represents a string value. 70 | string string_value = 3; 71 | // Represents a boolean value. 72 | bool bool_value = 4; 73 | // Represents a structured value. 74 | Struct struct_value = 5; 75 | // Represents a repeated `Value`. 76 | ListValue list_value = 6; 77 | } 78 | } 79 | 80 | // `NullValue` is a singleton enumeration to represent the null value for the 81 | // `Value` type union. 82 | // 83 | // The JSON representation for `NullValue` is JSON `null`. 84 | enum NullValue { 85 | // Null value. 86 | NULL_VALUE = 0; 87 | } 88 | 89 | // `ListValue` is a wrapper around a repeated field of values. 90 | // 91 | // The JSON representation for `ListValue` is JSON array. 92 | message ListValue { 93 | // Repeated field of dynamically typed values. 94 | repeated Value values = 1; 95 | } 96 | -------------------------------------------------------------------------------- /cmd/api.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net" 8 | "net/http" 9 | "time" 10 | 11 | chi "github.com/go-chi/chi/v5" 12 | "github.com/ra9dev/shutdown" 13 | "github.com/spf13/cobra" 14 | "golang.org/x/sync/errgroup" 15 | "google.golang.org/grpc" 16 | 17 | grpcAPI "github.com/ra9dev/go-template/internal/api/grpc" 18 | httpAPI "github.com/ra9dev/go-template/internal/api/http" 19 | "github.com/ra9dev/go-template/internal/config" 20 | example "github.com/ra9dev/go-template/pb" 21 | "github.com/ra9dev/go-template/pkg/sre/log" 22 | tracedGRPC "github.com/ra9dev/go-template/pkg/sre/tracing/transport/grpc" 23 | tracedHTTP "github.com/ra9dev/go-template/pkg/sre/tracing/transport/http" 24 | ) 25 | 26 | const ( 27 | readTimeout = 5 * time.Second 28 | writeTimeout = 30 * time.Second 29 | ) 30 | 31 | func APIServerCMD(cfg config.Config) *cobra.Command { 32 | cmd := &cobra.Command{ 33 | Use: "api", 34 | Short: "api server of project", 35 | } 36 | 37 | cmd.RunE = func(cmd *cobra.Command, args []string) error { 38 | ctx := cmd.Context() 39 | group, groupCTX := errgroup.WithContext(ctx) 40 | 41 | group.Go(func() error { 42 | clientHTTPHandler := newHTTPClientHandler() 43 | clientHTTP := newHTTPServer(cfg.Ports.HTTP)(clientHTTPHandler) 44 | 45 | return httpSrvRun(groupCTX, clientHTTP) 46 | }) 47 | 48 | group.Go(func() error { 49 | adminHTTPHandler := newHTTPAdminHandler() 50 | adminHTTP := newHTTPServer(cfg.Ports.AdminHTTP)(adminHTTPHandler) 51 | 52 | return httpSrvRun(groupCTX, adminHTTP) 53 | }) 54 | 55 | group.Go(func() error { 56 | return grpcSrvRun(groupCTX, cfg.Ports.GRPC) 57 | }) 58 | 59 | if err := group.Wait(); err != nil { 60 | return fmt.Errorf("api group failed: %w", err) 61 | } 62 | 63 | return nil 64 | } 65 | 66 | return cmd 67 | } 68 | 69 | func httpSrvRun(ctx context.Context, srv *http.Server) error { 70 | log.Infof(ctx, "Listening HTTP on %s...", srv.Addr) 71 | 72 | if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { 73 | return fmt.Errorf("HTTP server failed to serve: %w", err) 74 | } 75 | 76 | return nil 77 | } 78 | 79 | func newHTTPClientHandler() chi.Router { 80 | tracedRouter := tracedHTTP.NewRouter(tracedHTTP.NewParams("client_api")) 81 | api := httpAPI.NewClientAPI() 82 | 83 | tracedRouter.Mount("/v1", api.NewRouter()) 84 | 85 | return tracedRouter 86 | } 87 | 88 | func newHTTPAdminHandler() chi.Router { 89 | tracedRouter := tracedHTTP.NewRouter(tracedHTTP.NewParams("admin_api")) 90 | api := httpAPI.NewAdminAPI() 91 | 92 | tracedRouter.Mount("/v1", api.NewRouter()) 93 | 94 | return tracedRouter 95 | } 96 | 97 | func newHTTPServer(port uint) func(handler http.Handler) *http.Server { 98 | return func(handler http.Handler) *http.Server { 99 | addr := fmt.Sprintf(":%d", port) 100 | 101 | srv := http.Server{ 102 | Addr: addr, 103 | Handler: handler, 104 | ReadTimeout: readTimeout, 105 | WriteTimeout: writeTimeout, 106 | } 107 | 108 | shutdownKey := fmt.Sprintf("http:%d", port) 109 | 110 | shutdown.MustAdd(shutdownKey, func(ctx context.Context) { 111 | log.NoContext().Infof("Shutting down HTTP%s...", addr) 112 | 113 | if err := srv.Shutdown(ctx); err != nil { 114 | log.NoContext().Errorf("HTTP shutdown failed: %v", err) 115 | 116 | return 117 | } 118 | 119 | log.NoContext().Infof("HTTP%s shutdown succeeded!", addr) 120 | }) 121 | 122 | return &srv 123 | } 124 | } 125 | 126 | func grpcSrvRun(ctx context.Context, port uint) error { 127 | grpcListener, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 128 | if err != nil { 129 | return fmt.Errorf("failed to listen port %d for grpc: %w", port, err) 130 | } 131 | 132 | log.Infof(ctx, "Listening GRPC on :%d...", port) 133 | 134 | grpcServer := newGRPCServer(port) 135 | 136 | if err := grpcServer.Serve(grpcListener); err != nil { 137 | return fmt.Errorf("GRPC server failed to serve: %w", err) 138 | } 139 | 140 | return nil 141 | } 142 | 143 | func newGRPCServer(port uint) *grpc.Server { 144 | srv := tracedGRPC.NewServer(tracedGRPC.NewParams()) 145 | exampleService := grpcAPI.NewExampleService() 146 | 147 | example.RegisterGreeterServer(srv, exampleService) 148 | 149 | shutdownKey := fmt.Sprintf("grpc:%d", port) 150 | 151 | shutdown.MustAdd(shutdownKey, func(ctx context.Context) { 152 | log.NoContext().Infof("Shutting down GRPC:%d...", port) 153 | 154 | srv.GracefulStop() 155 | 156 | log.NoContext().Infof("GRPC:%d shutdown succeeded!", port) 157 | }) 158 | 159 | return srv 160 | } 161 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/wrappers.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Wrappers for primitive (non-message) types. These types are useful 32 | // for embedding primitives in the `google.protobuf.Any` type and for places 33 | // where we need to distinguish between the absence of a primitive 34 | // typed field and its default value. 35 | // 36 | // These wrappers have no meaningful use within repeated fields as they lack 37 | // the ability to detect presence on individual elements. 38 | // These wrappers have no meaningful use within a map or a oneof since 39 | // individual entries of a map or fields of a oneof can already detect presence. 40 | 41 | syntax = "proto3"; 42 | 43 | package google.protobuf; 44 | 45 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 46 | option cc_enable_arenas = true; 47 | option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; 48 | option java_package = "com.google.protobuf"; 49 | option java_outer_classname = "WrappersProto"; 50 | option java_multiple_files = true; 51 | option objc_class_prefix = "GPB"; 52 | 53 | // Wrapper message for `double`. 54 | // 55 | // The JSON representation for `DoubleValue` is JSON number. 56 | message DoubleValue { 57 | // The double value. 58 | double value = 1; 59 | } 60 | 61 | // Wrapper message for `float`. 62 | // 63 | // The JSON representation for `FloatValue` is JSON number. 64 | message FloatValue { 65 | // The float value. 66 | float value = 1; 67 | } 68 | 69 | // Wrapper message for `int64`. 70 | // 71 | // The JSON representation for `Int64Value` is JSON string. 72 | message Int64Value { 73 | // The int64 value. 74 | int64 value = 1; 75 | } 76 | 77 | // Wrapper message for `uint64`. 78 | // 79 | // The JSON representation for `UInt64Value` is JSON string. 80 | message UInt64Value { 81 | // The uint64 value. 82 | uint64 value = 1; 83 | } 84 | 85 | // Wrapper message for `int32`. 86 | // 87 | // The JSON representation for `Int32Value` is JSON number. 88 | message Int32Value { 89 | // The int32 value. 90 | int32 value = 1; 91 | } 92 | 93 | // Wrapper message for `uint32`. 94 | // 95 | // The JSON representation for `UInt32Value` is JSON number. 96 | message UInt32Value { 97 | // The uint32 value. 98 | uint32 value = 1; 99 | } 100 | 101 | // Wrapper message for `bool`. 102 | // 103 | // The JSON representation for `BoolValue` is JSON `true` and `false`. 104 | message BoolValue { 105 | // The bool value. 106 | bool value = 1; 107 | } 108 | 109 | // Wrapper message for `string`. 110 | // 111 | // The JSON representation for `StringValue` is JSON string. 112 | message StringValue { 113 | // The string value. 114 | string value = 1; 115 | } 116 | 117 | // Wrapper message for `bytes`. 118 | // 119 | // The JSON representation for `BytesValue` is JSON string. 120 | message BytesValue { 121 | // The bytes value. 122 | bytes value = 1; 123 | } 124 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/duration.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "google.golang.org/protobuf/types/known/durationpb"; 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "DurationProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // A Duration represents a signed, fixed-length span of time represented 44 | // as a count of seconds and fractions of seconds at nanosecond 45 | // resolution. It is independent of any calendar and concepts like "day" 46 | // or "month". It is related to Timestamp in that the difference between 47 | // two Timestamp values is a Duration and it can be added or subtracted 48 | // from a Timestamp. Range is approximately +-10,000 years. 49 | // 50 | // # Examples 51 | // 52 | // Example 1: Compute Duration from two Timestamps in pseudo code. 53 | // 54 | // Timestamp start = ...; 55 | // Timestamp end = ...; 56 | // Duration duration = ...; 57 | // 58 | // duration.seconds = end.seconds - start.seconds; 59 | // duration.nanos = end.nanos - start.nanos; 60 | // 61 | // if (duration.seconds < 0 && duration.nanos > 0) { 62 | // duration.seconds += 1; 63 | // duration.nanos -= 1000000000; 64 | // } else if (duration.seconds > 0 && duration.nanos < 0) { 65 | // duration.seconds -= 1; 66 | // duration.nanos += 1000000000; 67 | // } 68 | // 69 | // Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. 70 | // 71 | // Timestamp start = ...; 72 | // Duration duration = ...; 73 | // Timestamp end = ...; 74 | // 75 | // end.seconds = start.seconds + duration.seconds; 76 | // end.nanos = start.nanos + duration.nanos; 77 | // 78 | // if (end.nanos < 0) { 79 | // end.seconds -= 1; 80 | // end.nanos += 1000000000; 81 | // } else if (end.nanos >= 1000000000) { 82 | // end.seconds += 1; 83 | // end.nanos -= 1000000000; 84 | // } 85 | // 86 | // Example 3: Compute Duration from datetime.timedelta in Python. 87 | // 88 | // td = datetime.timedelta(days=3, minutes=10) 89 | // duration = Duration() 90 | // duration.FromTimedelta(td) 91 | // 92 | // # JSON Mapping 93 | // 94 | // In JSON format, the Duration type is encoded as a string rather than an 95 | // object, where the string ends in the suffix "s" (indicating seconds) and 96 | // is preceded by the number of seconds, with nanoseconds expressed as 97 | // fractional seconds. For example, 3 seconds with 0 nanoseconds should be 98 | // encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should 99 | // be expressed in JSON format as "3.000000001s", and 3 seconds and 1 100 | // microsecond should be expressed in JSON format as "3.000001s". 101 | // 102 | // 103 | message Duration { 104 | // Signed seconds of the span of time. Must be from -315,576,000,000 105 | // to +315,576,000,000 inclusive. Note: these bounds are computed from: 106 | // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years 107 | int64 seconds = 1; 108 | 109 | // Signed fractions of a second at nanosecond resolution of the span 110 | // of time. Durations less than one second are represented with a 0 111 | // `seconds` field and a positive or negative `nanos` field. For durations 112 | // of one second or more, a non-zero value for the `nanos` field must be 113 | // of the same sign as the `seconds` field. Must be from -999,999,999 114 | // to +999,999,999 inclusive. 115 | int32 nanos = 2; 116 | } 117 | -------------------------------------------------------------------------------- /pb/example.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.1 4 | // protoc v3.21.5 5 | // source: pb/example.proto 6 | 7 | package example 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | emptypb "google.golang.org/protobuf/types/known/emptypb" 13 | reflect "reflect" 14 | sync "sync" 15 | ) 16 | 17 | const ( 18 | // Verify that this generated code is sufficiently up-to-date. 19 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 20 | // Verify that runtime/protoimpl is sufficiently up-to-date. 21 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 22 | ) 23 | 24 | // The response message containing the greetings 25 | type HelloReply struct { 26 | state protoimpl.MessageState 27 | sizeCache protoimpl.SizeCache 28 | unknownFields protoimpl.UnknownFields 29 | 30 | Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` 31 | } 32 | 33 | func (x *HelloReply) Reset() { 34 | *x = HelloReply{} 35 | if protoimpl.UnsafeEnabled { 36 | mi := &file_pb_example_proto_msgTypes[0] 37 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 38 | ms.StoreMessageInfo(mi) 39 | } 40 | } 41 | 42 | func (x *HelloReply) String() string { 43 | return protoimpl.X.MessageStringOf(x) 44 | } 45 | 46 | func (*HelloReply) ProtoMessage() {} 47 | 48 | func (x *HelloReply) ProtoReflect() protoreflect.Message { 49 | mi := &file_pb_example_proto_msgTypes[0] 50 | if protoimpl.UnsafeEnabled && x != nil { 51 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 52 | if ms.LoadMessageInfo() == nil { 53 | ms.StoreMessageInfo(mi) 54 | } 55 | return ms 56 | } 57 | return mi.MessageOf(x) 58 | } 59 | 60 | // Deprecated: Use HelloReply.ProtoReflect.Descriptor instead. 61 | func (*HelloReply) Descriptor() ([]byte, []int) { 62 | return file_pb_example_proto_rawDescGZIP(), []int{0} 63 | } 64 | 65 | func (x *HelloReply) GetMessage() string { 66 | if x != nil { 67 | return x.Message 68 | } 69 | return "" 70 | } 71 | 72 | var File_pb_example_proto protoreflect.FileDescriptor 73 | 74 | var file_pb_example_proto_rawDesc = []byte{ 75 | 0x0a, 0x10, 0x70, 0x62, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 76 | 0x74, 0x6f, 0x12, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 77 | 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 78 | 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x26, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 79 | 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 80 | 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 81 | 0x32, 0x44, 0x0a, 0x07, 0x47, 0x72, 0x65, 0x65, 0x74, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x08, 0x53, 82 | 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 83 | 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 84 | 0x13, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 85 | 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 86 | 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x61, 0x39, 0x64, 0x65, 0x76, 0x2f, 0x67, 0x6f, 0x2d, 0x74, 87 | 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2f, 0x70, 0x62, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 88 | 0x6c, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 89 | } 90 | 91 | var ( 92 | file_pb_example_proto_rawDescOnce sync.Once 93 | file_pb_example_proto_rawDescData = file_pb_example_proto_rawDesc 94 | ) 95 | 96 | func file_pb_example_proto_rawDescGZIP() []byte { 97 | file_pb_example_proto_rawDescOnce.Do(func() { 98 | file_pb_example_proto_rawDescData = protoimpl.X.CompressGZIP(file_pb_example_proto_rawDescData) 99 | }) 100 | return file_pb_example_proto_rawDescData 101 | } 102 | 103 | var file_pb_example_proto_msgTypes = make([]protoimpl.MessageInfo, 1) 104 | var file_pb_example_proto_goTypes = []interface{}{ 105 | (*HelloReply)(nil), // 0: example.HelloReply 106 | (*emptypb.Empty)(nil), // 1: google.protobuf.Empty 107 | } 108 | var file_pb_example_proto_depIdxs = []int32{ 109 | 1, // 0: example.Greeter.SayHello:input_type -> google.protobuf.Empty 110 | 0, // 1: example.Greeter.SayHello:output_type -> example.HelloReply 111 | 1, // [1:2] is the sub-list for method output_type 112 | 0, // [0:1] is the sub-list for method input_type 113 | 0, // [0:0] is the sub-list for extension type_name 114 | 0, // [0:0] is the sub-list for extension extendee 115 | 0, // [0:0] is the sub-list for field type_name 116 | } 117 | 118 | func init() { file_pb_example_proto_init() } 119 | func file_pb_example_proto_init() { 120 | if File_pb_example_proto != nil { 121 | return 122 | } 123 | if !protoimpl.UnsafeEnabled { 124 | file_pb_example_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 125 | switch v := v.(*HelloReply); i { 126 | case 0: 127 | return &v.state 128 | case 1: 129 | return &v.sizeCache 130 | case 2: 131 | return &v.unknownFields 132 | default: 133 | return nil 134 | } 135 | } 136 | } 137 | type x struct{} 138 | out := protoimpl.TypeBuilder{ 139 | File: protoimpl.DescBuilder{ 140 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 141 | RawDescriptor: file_pb_example_proto_rawDesc, 142 | NumEnums: 0, 143 | NumMessages: 1, 144 | NumExtensions: 0, 145 | NumServices: 1, 146 | }, 147 | GoTypes: file_pb_example_proto_goTypes, 148 | DependencyIndexes: file_pb_example_proto_depIdxs, 149 | MessageInfos: file_pb_example_proto_msgTypes, 150 | }.Build() 151 | File_pb_example_proto = out.File 152 | file_pb_example_proto_rawDesc = nil 153 | file_pb_example_proto_goTypes = nil 154 | file_pb_example_proto_depIdxs = nil 155 | } 156 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/any.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "google.golang.org/protobuf/types/known/anypb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "AnyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | 42 | // `Any` contains an arbitrary serialized protocol buffer message along with a 43 | // URL that describes the type of the serialized message. 44 | // 45 | // Protobuf library provides support to pack/unpack Any values in the form 46 | // of utility functions or additional generated methods of the Any type. 47 | // 48 | // Example 1: Pack and unpack a message in C++. 49 | // 50 | // Foo foo = ...; 51 | // Any any; 52 | // any.PackFrom(foo); 53 | // ... 54 | // if (any.UnpackTo(&foo)) { 55 | // ... 56 | // } 57 | // 58 | // Example 2: Pack and unpack a message in Java. 59 | // 60 | // Foo foo = ...; 61 | // Any any = Any.pack(foo); 62 | // ... 63 | // if (any.is(Foo.class)) { 64 | // foo = any.unpack(Foo.class); 65 | // } 66 | // 67 | // Example 3: Pack and unpack a message in Python. 68 | // 69 | // foo = Foo(...) 70 | // any = Any() 71 | // any.Pack(foo) 72 | // ... 73 | // if any.Is(Foo.DESCRIPTOR): 74 | // any.Unpack(foo) 75 | // ... 76 | // 77 | // Example 4: Pack and unpack a message in Go 78 | // 79 | // foo := &pb.Foo{...} 80 | // any, err := anypb.New(foo) 81 | // if err != nil { 82 | // ... 83 | // } 84 | // ... 85 | // foo := &pb.Foo{} 86 | // if err := any.UnmarshalTo(foo); err != nil { 87 | // ... 88 | // } 89 | // 90 | // The pack methods provided by protobuf library will by default use 91 | // 'type.googleapis.com/full.type.name' as the type URL and the unpack 92 | // methods only use the fully qualified type name after the last '/' 93 | // in the type URL, for example "foo.bar.com/x/y.z" will yield type 94 | // name "y.z". 95 | // 96 | // 97 | // JSON 98 | // ==== 99 | // The JSON representation of an `Any` value uses the regular 100 | // representation of the deserialized, embedded message, with an 101 | // additional field `@type` which contains the type URL. Example: 102 | // 103 | // package google.profile; 104 | // message Person { 105 | // string first_name = 1; 106 | // string last_name = 2; 107 | // } 108 | // 109 | // { 110 | // "@type": "type.googleapis.com/google.profile.Person", 111 | // "firstName": , 112 | // "lastName": 113 | // } 114 | // 115 | // If the embedded message type is well-known and has a custom JSON 116 | // representation, that representation will be embedded adding a field 117 | // `value` which holds the custom JSON in addition to the `@type` 118 | // field. Example (for message [google.protobuf.Duration][]): 119 | // 120 | // { 121 | // "@type": "type.googleapis.com/google.protobuf.Duration", 122 | // "value": "1.212s" 123 | // } 124 | // 125 | message Any { 126 | // A URL/resource name that uniquely identifies the type of the serialized 127 | // protocol buffer message. This string must contain at least 128 | // one "/" character. The last segment of the URL's path must represent 129 | // the fully qualified name of the type (as in 130 | // `path/google.protobuf.Duration`). The name should be in a canonical form 131 | // (e.g., leading "." is not accepted). 132 | // 133 | // In practice, teams usually precompile into the binary all types that they 134 | // expect it to use in the context of Any. However, for URLs which use the 135 | // scheme `http`, `https`, or no scheme, one can optionally set up a type 136 | // server that maps type URLs to message definitions as follows: 137 | // 138 | // * If no scheme is provided, `https` is assumed. 139 | // * An HTTP GET on the URL must yield a [google.protobuf.Type][] 140 | // value in binary format, or produce an error. 141 | // * Applications are allowed to cache lookup results based on the 142 | // URL, or have them precompiled into a binary to avoid any 143 | // lookup. Therefore, binary compatibility needs to be preserved 144 | // on changes to types. (Use versioned type names to manage 145 | // breaking changes.) 146 | // 147 | // Note: this functionality is not currently available in the official 148 | // protobuf release, and it is not used for type URLs beginning with 149 | // type.googleapis.com. 150 | // 151 | // Schemes other than `http`, `https` (or the empty scheme) might be 152 | // used with implementation specific semantics. 153 | // 154 | string type_url = 1; 155 | 156 | // Must be a valid serialized protocol buffer of the above specified type. 157 | bytes value = 2; 158 | } 159 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/type.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | import "google/protobuf/any.proto"; 36 | import "google/protobuf/source_context.proto"; 37 | 38 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 39 | option cc_enable_arenas = true; 40 | option java_package = "com.google.protobuf"; 41 | option java_outer_classname = "TypeProto"; 42 | option java_multiple_files = true; 43 | option objc_class_prefix = "GPB"; 44 | option go_package = "google.golang.org/protobuf/types/known/typepb"; 45 | 46 | // A protocol buffer message type. 47 | message Type { 48 | // The fully qualified message name. 49 | string name = 1; 50 | // The list of fields. 51 | repeated Field fields = 2; 52 | // The list of types appearing in `oneof` definitions in this type. 53 | repeated string oneofs = 3; 54 | // The protocol buffer options. 55 | repeated Option options = 4; 56 | // The source context. 57 | SourceContext source_context = 5; 58 | // The source syntax. 59 | Syntax syntax = 6; 60 | } 61 | 62 | // A single field of a message type. 63 | message Field { 64 | // Basic field types. 65 | enum Kind { 66 | // Field type unknown. 67 | TYPE_UNKNOWN = 0; 68 | // Field type double. 69 | TYPE_DOUBLE = 1; 70 | // Field type float. 71 | TYPE_FLOAT = 2; 72 | // Field type int64. 73 | TYPE_INT64 = 3; 74 | // Field type uint64. 75 | TYPE_UINT64 = 4; 76 | // Field type int32. 77 | TYPE_INT32 = 5; 78 | // Field type fixed64. 79 | TYPE_FIXED64 = 6; 80 | // Field type fixed32. 81 | TYPE_FIXED32 = 7; 82 | // Field type bool. 83 | TYPE_BOOL = 8; 84 | // Field type string. 85 | TYPE_STRING = 9; 86 | // Field type group. Proto2 syntax only, and deprecated. 87 | TYPE_GROUP = 10; 88 | // Field type message. 89 | TYPE_MESSAGE = 11; 90 | // Field type bytes. 91 | TYPE_BYTES = 12; 92 | // Field type uint32. 93 | TYPE_UINT32 = 13; 94 | // Field type enum. 95 | TYPE_ENUM = 14; 96 | // Field type sfixed32. 97 | TYPE_SFIXED32 = 15; 98 | // Field type sfixed64. 99 | TYPE_SFIXED64 = 16; 100 | // Field type sint32. 101 | TYPE_SINT32 = 17; 102 | // Field type sint64. 103 | TYPE_SINT64 = 18; 104 | } 105 | 106 | // Whether a field is optional, required, or repeated. 107 | enum Cardinality { 108 | // For fields with unknown cardinality. 109 | CARDINALITY_UNKNOWN = 0; 110 | // For optional fields. 111 | CARDINALITY_OPTIONAL = 1; 112 | // For required fields. Proto2 syntax only. 113 | CARDINALITY_REQUIRED = 2; 114 | // For repeated fields. 115 | CARDINALITY_REPEATED = 3; 116 | } 117 | 118 | // The field type. 119 | Kind kind = 1; 120 | // The field cardinality. 121 | Cardinality cardinality = 2; 122 | // The field number. 123 | int32 number = 3; 124 | // The field name. 125 | string name = 4; 126 | // The field type URL, without the scheme, for message or enumeration 127 | // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. 128 | string type_url = 6; 129 | // The index of the field type in `Type.oneofs`, for message or enumeration 130 | // types. The first type has index 1; zero means the type is not in the list. 131 | int32 oneof_index = 7; 132 | // Whether to use alternative packed wire representation. 133 | bool packed = 8; 134 | // The protocol buffer options. 135 | repeated Option options = 9; 136 | // The field JSON name. 137 | string json_name = 10; 138 | // The string value of the default value of this field. Proto2 syntax only. 139 | string default_value = 11; 140 | } 141 | 142 | // Enum type definition. 143 | message Enum { 144 | // Enum type name. 145 | string name = 1; 146 | // Enum value definitions. 147 | repeated EnumValue enumvalue = 2; 148 | // Protocol buffer options. 149 | repeated Option options = 3; 150 | // The source context. 151 | SourceContext source_context = 4; 152 | // The source syntax. 153 | Syntax syntax = 5; 154 | } 155 | 156 | // Enum value definition. 157 | message EnumValue { 158 | // Enum value name. 159 | string name = 1; 160 | // Enum value number. 161 | int32 number = 2; 162 | // Protocol buffer options. 163 | repeated Option options = 3; 164 | } 165 | 166 | // A protocol buffer option, which can be attached to a message, field, 167 | // enumeration, etc. 168 | message Option { 169 | // The option's name. For protobuf built-in options (options defined in 170 | // descriptor.proto), this is the short name. For example, `"map_entry"`. 171 | // For custom options, it should be the fully-qualified name. For example, 172 | // `"google.api.http"`. 173 | string name = 1; 174 | // The option's value packed in an Any message. If the value is a primitive, 175 | // the corresponding wrapper type defined in google/protobuf/wrappers.proto 176 | // should be used. If the value is an enum, it should be stored as an int32 177 | // value using the google.protobuf.Int32Value type. 178 | Any value = 2; 179 | } 180 | 181 | // The syntax in which a protocol buffer element is defined. 182 | enum Syntax { 183 | // Syntax `proto2`. 184 | SYNTAX_PROTO2 = 0; 185 | // Syntax `proto3`. 186 | SYNTAX_PROTO3 = 1; 187 | } 188 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/timestamp.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "google.golang.org/protobuf/types/known/timestamppb"; 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "TimestampProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // A Timestamp represents a point in time independent of any time zone or local 44 | // calendar, encoded as a count of seconds and fractions of seconds at 45 | // nanosecond resolution. The count is relative to an epoch at UTC midnight on 46 | // January 1, 1970, in the proleptic Gregorian calendar which extends the 47 | // Gregorian calendar backwards to year one. 48 | // 49 | // All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap 50 | // second table is needed for interpretation, using a [24-hour linear 51 | // smear](https://developers.google.com/time/smear). 52 | // 53 | // The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By 54 | // restricting to that range, we ensure that we can convert to and from [RFC 55 | // 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. 56 | // 57 | // # Examples 58 | // 59 | // Example 1: Compute Timestamp from POSIX `time()`. 60 | // 61 | // Timestamp timestamp; 62 | // timestamp.set_seconds(time(NULL)); 63 | // timestamp.set_nanos(0); 64 | // 65 | // Example 2: Compute Timestamp from POSIX `gettimeofday()`. 66 | // 67 | // struct timeval tv; 68 | // gettimeofday(&tv, NULL); 69 | // 70 | // Timestamp timestamp; 71 | // timestamp.set_seconds(tv.tv_sec); 72 | // timestamp.set_nanos(tv.tv_usec * 1000); 73 | // 74 | // Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. 75 | // 76 | // FILETIME ft; 77 | // GetSystemTimeAsFileTime(&ft); 78 | // UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; 79 | // 80 | // // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z 81 | // // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. 82 | // Timestamp timestamp; 83 | // timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); 84 | // timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); 85 | // 86 | // Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. 87 | // 88 | // long millis = System.currentTimeMillis(); 89 | // 90 | // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) 91 | // .setNanos((int) ((millis % 1000) * 1000000)).build(); 92 | // 93 | // 94 | // Example 5: Compute Timestamp from Java `Instant.now()`. 95 | // 96 | // Instant now = Instant.now(); 97 | // 98 | // Timestamp timestamp = 99 | // Timestamp.newBuilder().setSeconds(now.getEpochSecond()) 100 | // .setNanos(now.getNano()).build(); 101 | // 102 | // 103 | // Example 6: Compute Timestamp from current time in Python. 104 | // 105 | // timestamp = Timestamp() 106 | // timestamp.GetCurrentTime() 107 | // 108 | // # JSON Mapping 109 | // 110 | // In JSON format, the Timestamp type is encoded as a string in the 111 | // [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the 112 | // format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" 113 | // where {year} is always expressed using four digits while {month}, {day}, 114 | // {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional 115 | // seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), 116 | // are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone 117 | // is required. A proto3 JSON serializer should always use UTC (as indicated by 118 | // "Z") when printing the Timestamp type and a proto3 JSON parser should be 119 | // able to accept both UTC and other timezones (as indicated by an offset). 120 | // 121 | // For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 122 | // 01:30 UTC on January 15, 2017. 123 | // 124 | // In JavaScript, one can convert a Date object to this format using the 125 | // standard 126 | // [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) 127 | // method. In Python, a standard `datetime.datetime` object can be converted 128 | // to this format using 129 | // [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with 130 | // the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use 131 | // the Joda Time's [`ISODateTimeFormat.dateTime()`]( 132 | // http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D 133 | // ) to obtain a formatter capable of generating timestamps in this format. 134 | // 135 | // 136 | message Timestamp { 137 | // Represents seconds of UTC time since Unix epoch 138 | // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 139 | // 9999-12-31T23:59:59Z inclusive. 140 | int64 seconds = 1; 141 | 142 | // Non-negative fractions of a second at nanosecond resolution. Negative 143 | // second values with fractions must still have non-negative nanos values 144 | // that count forward in time. Must be from 0 to 999,999,999 145 | // inclusive. 146 | int32 nanos = 2; 147 | } 148 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/api.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | import "google/protobuf/source_context.proto"; 36 | import "google/protobuf/type.proto"; 37 | 38 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 39 | option java_package = "com.google.protobuf"; 40 | option java_outer_classname = "ApiProto"; 41 | option java_multiple_files = true; 42 | option objc_class_prefix = "GPB"; 43 | option go_package = "google.golang.org/protobuf/types/known/apipb"; 44 | 45 | // Api is a light-weight descriptor for an API Interface. 46 | // 47 | // Interfaces are also described as "protocol buffer services" in some contexts, 48 | // such as by the "service" keyword in a .proto file, but they are different 49 | // from API Services, which represent a concrete implementation of an interface 50 | // as opposed to simply a description of methods and bindings. They are also 51 | // sometimes simply referred to as "APIs" in other contexts, such as the name of 52 | // this message itself. See https://cloud.google.com/apis/design/glossary for 53 | // detailed terminology. 54 | message Api { 55 | // The fully qualified name of this interface, including package name 56 | // followed by the interface's simple name. 57 | string name = 1; 58 | 59 | // The methods of this interface, in unspecified order. 60 | repeated Method methods = 2; 61 | 62 | // Any metadata attached to the interface. 63 | repeated Option options = 3; 64 | 65 | // A version string for this interface. If specified, must have the form 66 | // `major-version.minor-version`, as in `1.10`. If the minor version is 67 | // omitted, it defaults to zero. If the entire version field is empty, the 68 | // major version is derived from the package name, as outlined below. If the 69 | // field is not empty, the version in the package name will be verified to be 70 | // consistent with what is provided here. 71 | // 72 | // The versioning schema uses [semantic 73 | // versioning](http://semver.org) where the major version number 74 | // indicates a breaking change and the minor version an additive, 75 | // non-breaking change. Both version numbers are signals to users 76 | // what to expect from different versions, and should be carefully 77 | // chosen based on the product plan. 78 | // 79 | // The major version is also reflected in the package name of the 80 | // interface, which must end in `v`, as in 81 | // `google.feature.v1`. For major versions 0 and 1, the suffix can 82 | // be omitted. Zero major versions must only be used for 83 | // experimental, non-GA interfaces. 84 | // 85 | // 86 | string version = 4; 87 | 88 | // Source context for the protocol buffer service represented by this 89 | // message. 90 | SourceContext source_context = 5; 91 | 92 | // Included interfaces. See [Mixin][]. 93 | repeated Mixin mixins = 6; 94 | 95 | // The source syntax of the service. 96 | Syntax syntax = 7; 97 | } 98 | 99 | // Method represents a method of an API interface. 100 | message Method { 101 | // The simple name of this method. 102 | string name = 1; 103 | 104 | // A URL of the input message type. 105 | string request_type_url = 2; 106 | 107 | // If true, the request is streamed. 108 | bool request_streaming = 3; 109 | 110 | // The URL of the output message type. 111 | string response_type_url = 4; 112 | 113 | // If true, the response is streamed. 114 | bool response_streaming = 5; 115 | 116 | // Any metadata attached to the method. 117 | repeated Option options = 6; 118 | 119 | // The source syntax of this method. 120 | Syntax syntax = 7; 121 | } 122 | 123 | // Declares an API Interface to be included in this interface. The including 124 | // interface must redeclare all the methods from the included interface, but 125 | // documentation and options are inherited as follows: 126 | // 127 | // - If after comment and whitespace stripping, the documentation 128 | // string of the redeclared method is empty, it will be inherited 129 | // from the original method. 130 | // 131 | // - Each annotation belonging to the service config (http, 132 | // visibility) which is not set in the redeclared method will be 133 | // inherited. 134 | // 135 | // - If an http annotation is inherited, the path pattern will be 136 | // modified as follows. Any version prefix will be replaced by the 137 | // version of the including interface plus the [root][] path if 138 | // specified. 139 | // 140 | // Example of a simple mixin: 141 | // 142 | // package google.acl.v1; 143 | // service AccessControl { 144 | // // Get the underlying ACL object. 145 | // rpc GetAcl(GetAclRequest) returns (Acl) { 146 | // option (google.api.http).get = "/v1/{resource=**}:getAcl"; 147 | // } 148 | // } 149 | // 150 | // package google.storage.v2; 151 | // service Storage { 152 | // rpc GetAcl(GetAclRequest) returns (Acl); 153 | // 154 | // // Get a data record. 155 | // rpc GetData(GetDataRequest) returns (Data) { 156 | // option (google.api.http).get = "/v2/{resource=**}"; 157 | // } 158 | // } 159 | // 160 | // Example of a mixin configuration: 161 | // 162 | // apis: 163 | // - name: google.storage.v2.Storage 164 | // mixins: 165 | // - name: google.acl.v1.AccessControl 166 | // 167 | // The mixin construct implies that all methods in `AccessControl` are 168 | // also declared with same name and request/response types in 169 | // `Storage`. A documentation generator or annotation processor will 170 | // see the effective `Storage.GetAcl` method after inheriting 171 | // documentation and annotations as follows: 172 | // 173 | // service Storage { 174 | // // Get the underlying ACL object. 175 | // rpc GetAcl(GetAclRequest) returns (Acl) { 176 | // option (google.api.http).get = "/v2/{resource=**}:getAcl"; 177 | // } 178 | // ... 179 | // } 180 | // 181 | // Note how the version in the path pattern changed from `v1` to `v2`. 182 | // 183 | // If the `root` field in the mixin is specified, it should be a 184 | // relative path under which inherited HTTP paths are placed. Example: 185 | // 186 | // apis: 187 | // - name: google.storage.v2.Storage 188 | // mixins: 189 | // - name: google.acl.v1.AccessControl 190 | // root: acls 191 | // 192 | // This implies the following inherited HTTP annotation: 193 | // 194 | // service Storage { 195 | // // Get the underlying ACL object. 196 | // rpc GetAcl(GetAclRequest) returns (Acl) { 197 | // option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; 198 | // } 199 | // ... 200 | // } 201 | message Mixin { 202 | // The fully qualified name of the interface which is included. 203 | string name = 1; 204 | 205 | // If non-empty specifies a path under which inherited HTTP paths 206 | // are rooted. 207 | string root = 2; 208 | } 209 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/field_mask.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option java_package = "com.google.protobuf"; 37 | option java_outer_classname = "FieldMaskProto"; 38 | option java_multiple_files = true; 39 | option objc_class_prefix = "GPB"; 40 | option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; 41 | option cc_enable_arenas = true; 42 | 43 | // `FieldMask` represents a set of symbolic field paths, for example: 44 | // 45 | // paths: "f.a" 46 | // paths: "f.b.d" 47 | // 48 | // Here `f` represents a field in some root message, `a` and `b` 49 | // fields in the message found in `f`, and `d` a field found in the 50 | // message in `f.b`. 51 | // 52 | // Field masks are used to specify a subset of fields that should be 53 | // returned by a get operation or modified by an update operation. 54 | // Field masks also have a custom JSON encoding (see below). 55 | // 56 | // # Field Masks in Projections 57 | // 58 | // When used in the context of a projection, a response message or 59 | // sub-message is filtered by the API to only contain those fields as 60 | // specified in the mask. For example, if the mask in the previous 61 | // example is applied to a response message as follows: 62 | // 63 | // f { 64 | // a : 22 65 | // b { 66 | // d : 1 67 | // x : 2 68 | // } 69 | // y : 13 70 | // } 71 | // z: 8 72 | // 73 | // The result will not contain specific values for fields x,y and z 74 | // (their value will be set to the default, and omitted in proto text 75 | // output): 76 | // 77 | // 78 | // f { 79 | // a : 22 80 | // b { 81 | // d : 1 82 | // } 83 | // } 84 | // 85 | // A repeated field is not allowed except at the last position of a 86 | // paths string. 87 | // 88 | // If a FieldMask object is not present in a get operation, the 89 | // operation applies to all fields (as if a FieldMask of all fields 90 | // had been specified). 91 | // 92 | // Note that a field mask does not necessarily apply to the 93 | // top-level response message. In case of a REST get operation, the 94 | // field mask applies directly to the response, but in case of a REST 95 | // list operation, the mask instead applies to each individual message 96 | // in the returned resource list. In case of a REST custom method, 97 | // other definitions may be used. Where the mask applies will be 98 | // clearly documented together with its declaration in the API. In 99 | // any case, the effect on the returned resource/resources is required 100 | // behavior for APIs. 101 | // 102 | // # Field Masks in Update Operations 103 | // 104 | // A field mask in update operations specifies which fields of the 105 | // targeted resource are going to be updated. The API is required 106 | // to only change the values of the fields as specified in the mask 107 | // and leave the others untouched. If a resource is passed in to 108 | // describe the updated values, the API ignores the values of all 109 | // fields not covered by the mask. 110 | // 111 | // If a repeated field is specified for an update operation, new values will 112 | // be appended to the existing repeated field in the target resource. Note that 113 | // a repeated field is only allowed in the last position of a `paths` string. 114 | // 115 | // If a sub-message is specified in the last position of the field mask for an 116 | // update operation, then new value will be merged into the existing sub-message 117 | // in the target resource. 118 | // 119 | // For example, given the target message: 120 | // 121 | // f { 122 | // b { 123 | // d: 1 124 | // x: 2 125 | // } 126 | // c: [1] 127 | // } 128 | // 129 | // And an update message: 130 | // 131 | // f { 132 | // b { 133 | // d: 10 134 | // } 135 | // c: [2] 136 | // } 137 | // 138 | // then if the field mask is: 139 | // 140 | // paths: ["f.b", "f.c"] 141 | // 142 | // then the result will be: 143 | // 144 | // f { 145 | // b { 146 | // d: 10 147 | // x: 2 148 | // } 149 | // c: [1, 2] 150 | // } 151 | // 152 | // An implementation may provide options to override this default behavior for 153 | // repeated and message fields. 154 | // 155 | // In order to reset a field's value to the default, the field must 156 | // be in the mask and set to the default value in the provided resource. 157 | // Hence, in order to reset all fields of a resource, provide a default 158 | // instance of the resource and set all fields in the mask, or do 159 | // not provide a mask as described below. 160 | // 161 | // If a field mask is not present on update, the operation applies to 162 | // all fields (as if a field mask of all fields has been specified). 163 | // Note that in the presence of schema evolution, this may mean that 164 | // fields the client does not know and has therefore not filled into 165 | // the request will be reset to their default. If this is unwanted 166 | // behavior, a specific service may require a client to always specify 167 | // a field mask, producing an error if not. 168 | // 169 | // As with get operations, the location of the resource which 170 | // describes the updated values in the request message depends on the 171 | // operation kind. In any case, the effect of the field mask is 172 | // required to be honored by the API. 173 | // 174 | // ## Considerations for HTTP REST 175 | // 176 | // The HTTP kind of an update operation which uses a field mask must 177 | // be set to PATCH instead of PUT in order to satisfy HTTP semantics 178 | // (PUT must only be used for full updates). 179 | // 180 | // # JSON Encoding of Field Masks 181 | // 182 | // In JSON, a field mask is encoded as a single string where paths are 183 | // separated by a comma. Fields name in each path are converted 184 | // to/from lower-camel naming conventions. 185 | // 186 | // As an example, consider the following message declarations: 187 | // 188 | // message Profile { 189 | // User user = 1; 190 | // Photo photo = 2; 191 | // } 192 | // message User { 193 | // string display_name = 1; 194 | // string address = 2; 195 | // } 196 | // 197 | // In proto a field mask for `Profile` may look as such: 198 | // 199 | // mask { 200 | // paths: "user.display_name" 201 | // paths: "photo" 202 | // } 203 | // 204 | // In JSON, the same mask is represented as below: 205 | // 206 | // { 207 | // mask: "user.displayName,photo" 208 | // } 209 | // 210 | // # Field Masks and Oneof Fields 211 | // 212 | // Field masks treat fields in oneofs just as regular fields. Consider the 213 | // following message: 214 | // 215 | // message SampleMessage { 216 | // oneof test_oneof { 217 | // string name = 4; 218 | // SubMessage sub_message = 9; 219 | // } 220 | // } 221 | // 222 | // The field mask can be: 223 | // 224 | // mask { 225 | // paths: "name" 226 | // } 227 | // 228 | // Or: 229 | // 230 | // mask { 231 | // paths: "sub_message" 232 | // } 233 | // 234 | // Note that oneof type names ("test_oneof" in this case) cannot be used in 235 | // paths. 236 | // 237 | // ## Field Mask Verification 238 | // 239 | // The implementation of any API method which has a FieldMask type field in the 240 | // request should verify the included field paths, and return an 241 | // `INVALID_ARGUMENT` error if any path is unmappable. 242 | message FieldMask { 243 | // The set of field mask paths. 244 | repeated string paths = 1; 245 | } 246 | -------------------------------------------------------------------------------- /integrations/proto/google/api/http.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | option cc_enable_arenas = true; 20 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 21 | option java_multiple_files = true; 22 | option java_outer_classname = "HttpProto"; 23 | option java_package = "com.google.api"; 24 | option objc_class_prefix = "GAPI"; 25 | 26 | 27 | // Defines the HTTP configuration for an API service. It contains a list of 28 | // [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method 29 | // to one or more HTTP REST API methods. 30 | message Http { 31 | // A list of HTTP configuration rules that apply to individual API methods. 32 | // 33 | // **NOTE:** All service configuration rules follow "last one wins" order. 34 | repeated HttpRule rules = 1; 35 | 36 | // When set to true, URL path parmeters will be fully URI-decoded except in 37 | // cases of single segment matches in reserved expansion, where "%2F" will be 38 | // left encoded. 39 | // 40 | // The default behavior is to not decode RFC 6570 reserved characters in multi 41 | // segment matches. 42 | bool fully_decode_reserved_expansion = 2; 43 | } 44 | 45 | // `HttpRule` defines the mapping of an RPC method to one or more HTTP 46 | // REST API methods. The mapping specifies how different portions of the RPC 47 | // request message are mapped to URL path, URL query parameters, and 48 | // HTTP request body. The mapping is typically specified as an 49 | // `google.api.http` annotation on the RPC method, 50 | // see "google/api/annotations.proto" for details. 51 | // 52 | // The mapping consists of a field specifying the path template and 53 | // method kind. The path template can refer to fields in the request 54 | // message, as in the example below which describes a REST GET 55 | // operation on a resource collection of messages: 56 | // 57 | // 58 | // service Messaging { 59 | // rpc GetMessage(GetMessageRequest) returns (Message) { 60 | // option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}"; 61 | // } 62 | // } 63 | // message GetMessageRequest { 64 | // message SubMessage { 65 | // string subfield = 1; 66 | // } 67 | // string message_id = 1; // mapped to the URL 68 | // SubMessage sub = 2; // `sub.subfield` is url-mapped 69 | // } 70 | // message Message { 71 | // string text = 1; // content of the resource 72 | // } 73 | // 74 | // The same http annotation can alternatively be expressed inside the 75 | // `GRPC API Configuration` YAML file. 76 | // 77 | // http: 78 | // rules: 79 | // - selector: .Messaging.GetMessage 80 | // get: /v1/messages/{message_id}/{sub.subfield} 81 | // 82 | // This definition enables an automatic, bidrectional mapping of HTTP 83 | // JSON to RPC. Example: 84 | // 85 | // HTTP | RPC 86 | // -----|----- 87 | // `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))` 88 | // 89 | // In general, not only fields but also field paths can be referenced 90 | // from a path pattern. Fields mapped to the path pattern cannot be 91 | // repeated and must have a primitive (non-message) type. 92 | // 93 | // Any fields in the request message which are not bound by the path 94 | // pattern automatically become (optional) HTTP query 95 | // parameters. Assume the following definition of the request message: 96 | // 97 | // 98 | // service Messaging { 99 | // rpc GetMessage(GetMessageRequest) returns (Message) { 100 | // option (google.api.http).get = "/v1/messages/{message_id}"; 101 | // } 102 | // } 103 | // message GetMessageRequest { 104 | // message SubMessage { 105 | // string subfield = 1; 106 | // } 107 | // string message_id = 1; // mapped to the URL 108 | // int64 revision = 2; // becomes a parameter 109 | // SubMessage sub = 3; // `sub.subfield` becomes a parameter 110 | // } 111 | // 112 | // 113 | // This enables a HTTP JSON to RPC mapping as below: 114 | // 115 | // HTTP | RPC 116 | // -----|----- 117 | // `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))` 118 | // 119 | // Note that fields which are mapped to HTTP parameters must have a 120 | // primitive type or a repeated primitive type. Message types are not 121 | // allowed. In the case of a repeated type, the parameter can be 122 | // repeated in the URL, as in `...?param=A¶m=B`. 123 | // 124 | // For HTTP method kinds which allow a request body, the `body` field 125 | // specifies the mapping. Consider a REST update method on the 126 | // message resource collection: 127 | // 128 | // 129 | // service Messaging { 130 | // rpc UpdateMessage(UpdateMessageRequest) returns (Message) { 131 | // option (google.api.http) = { 132 | // put: "/v1/messages/{message_id}" 133 | // body: "message" 134 | // }; 135 | // } 136 | // } 137 | // message UpdateMessageRequest { 138 | // string message_id = 1; // mapped to the URL 139 | // Message message = 2; // mapped to the body 140 | // } 141 | // 142 | // 143 | // The following HTTP JSON to RPC mapping is enabled, where the 144 | // representation of the JSON in the request body is determined by 145 | // protos JSON encoding: 146 | // 147 | // HTTP | RPC 148 | // -----|----- 149 | // `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })` 150 | // 151 | // The special name `*` can be used in the body mapping to define that 152 | // every field not bound by the path template should be mapped to the 153 | // request body. This enables the following alternative definition of 154 | // the update method: 155 | // 156 | // service Messaging { 157 | // rpc UpdateMessage(Message) returns (Message) { 158 | // option (google.api.http) = { 159 | // put: "/v1/messages/{message_id}" 160 | // body: "*" 161 | // }; 162 | // } 163 | // } 164 | // message Message { 165 | // string message_id = 1; 166 | // string text = 2; 167 | // } 168 | // 169 | // 170 | // The following HTTP JSON to RPC mapping is enabled: 171 | // 172 | // HTTP | RPC 173 | // -----|----- 174 | // `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")` 175 | // 176 | // Note that when using `*` in the body mapping, it is not possible to 177 | // have HTTP parameters, as all fields not bound by the path end in 178 | // the body. This makes this option more rarely used in practice of 179 | // defining REST APIs. The common usage of `*` is in custom methods 180 | // which don't use the URL at all for transferring data. 181 | // 182 | // It is possible to define multiple HTTP methods for one RPC by using 183 | // the `additional_bindings` option. Example: 184 | // 185 | // service Messaging { 186 | // rpc GetMessage(GetMessageRequest) returns (Message) { 187 | // option (google.api.http) = { 188 | // get: "/v1/messages/{message_id}" 189 | // additional_bindings { 190 | // get: "/v1/users/{user_id}/messages/{message_id}" 191 | // } 192 | // }; 193 | // } 194 | // } 195 | // message GetMessageRequest { 196 | // string message_id = 1; 197 | // string user_id = 2; 198 | // } 199 | // 200 | // 201 | // This enables the following two alternative HTTP JSON to RPC 202 | // mappings: 203 | // 204 | // HTTP | RPC 205 | // -----|----- 206 | // `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` 207 | // `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")` 208 | // 209 | // # Rules for HTTP mapping 210 | // 211 | // The rules for mapping HTTP path, query parameters, and body fields 212 | // to the request message are as follows: 213 | // 214 | // 1. The `body` field specifies either `*` or a field path, or is 215 | // omitted. If omitted, it indicates there is no HTTP request body. 216 | // 2. Leaf fields (recursive expansion of nested messages in the 217 | // request) can be classified into three types: 218 | // (a) Matched in the URL template. 219 | // (b) Covered by body (if body is `*`, everything except (a) fields; 220 | // else everything under the body field) 221 | // (c) All other fields. 222 | // 3. URL query parameters found in the HTTP request are mapped to (c) fields. 223 | // 4. Any body sent with an HTTP request can contain only (b) fields. 224 | // 225 | // The syntax of the path template is as follows: 226 | // 227 | // Template = "/" Segments [ Verb ] ; 228 | // Segments = Segment { "/" Segment } ; 229 | // Segment = "*" | "**" | LITERAL | Variable ; 230 | // Variable = "{" FieldPath [ "=" Segments ] "}" ; 231 | // FieldPath = IDENT { "." IDENT } ; 232 | // Verb = ":" LITERAL ; 233 | // 234 | // The syntax `*` matches a single path segment. The syntax `**` matches zero 235 | // or more path segments, which must be the last part of the path except the 236 | // `Verb`. The syntax `LITERAL` matches literal text in the path. 237 | // 238 | // The syntax `Variable` matches part of the URL path as specified by its 239 | // template. A variable template must not contain other variables. If a variable 240 | // matches a single path segment, its template may be omitted, e.g. `{var}` 241 | // is equivalent to `{var=*}`. 242 | // 243 | // If a variable contains exactly one path segment, such as `"{var}"` or 244 | // `"{var=*}"`, when such a variable is expanded into a URL path, all characters 245 | // except `[-_.~0-9a-zA-Z]` are percent-encoded. Such variables show up in the 246 | // Discovery Document as `{var}`. 247 | // 248 | // If a variable contains one or more path segments, such as `"{var=foo/*}"` 249 | // or `"{var=**}"`, when such a variable is expanded into a URL path, all 250 | // characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. Such variables 251 | // show up in the Discovery Document as `{+var}`. 252 | // 253 | // NOTE: While the single segment variable matches the semantics of 254 | // [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 255 | // Simple String Expansion, the multi segment variable **does not** match 256 | // RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion 257 | // does not expand special characters like `?` and `#`, which would lead 258 | // to invalid URLs. 259 | // 260 | // NOTE: the field paths in variables and in the `body` must not refer to 261 | // repeated fields or map fields. 262 | message HttpRule { 263 | // Selects methods to which this rule applies. 264 | // 265 | // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. 266 | string selector = 1; 267 | 268 | // Determines the URL pattern is matched by this rules. This pattern can be 269 | // used with any of the {get|put|post|delete|patch} methods. A custom method 270 | // can be defined using the 'custom' field. 271 | oneof pattern { 272 | // Used for listing and getting information about resources. 273 | string get = 2; 274 | 275 | // Used for updating a resource. 276 | string put = 3; 277 | 278 | // Used for creating a resource. 279 | string post = 4; 280 | 281 | // Used for deleting a resource. 282 | string delete = 5; 283 | 284 | // Used for updating a resource. 285 | string patch = 6; 286 | 287 | // The custom pattern is used for specifying an HTTP method that is not 288 | // included in the `pattern` field, such as HEAD, or "*" to leave the 289 | // HTTP method unspecified for this rule. The wild-card rule is useful 290 | // for services that provide content to Web (HTML) clients. 291 | CustomHttpPattern custom = 8; 292 | } 293 | 294 | // The name of the request field whose value is mapped to the HTTP body, or 295 | // `*` for mapping all fields not captured by the path pattern to the HTTP 296 | // body. NOTE: the referred field must not be a repeated field and must be 297 | // present at the top-level of request message type. 298 | string body = 7; 299 | 300 | // Optional. The name of the response field whose value is mapped to the HTTP 301 | // body of response. Other response fields are ignored. When 302 | // not set, the response message will be used as HTTP body of response. 303 | string response_body = 12; 304 | 305 | // Additional HTTP bindings for the selector. Nested bindings must 306 | // not contain an `additional_bindings` field themselves (that is, 307 | // the nesting may only be one level deep). 308 | repeated HttpRule additional_bindings = 11; 309 | } 310 | 311 | // A custom pattern is used for defining custom HTTP verb. 312 | message CustomHttpPattern { 313 | // The name of this custom HTTP verb. 314 | string kind = 1; 315 | 316 | // The path matched by this custom verb. 317 | string path = 2; 318 | } 319 | -------------------------------------------------------------------------------- /integrations/proto/google/protobuf/descriptor.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | // Author: kenton@google.com (Kenton Varda) 32 | // Based on original Protocol Buffers design by 33 | // Sanjay Ghemawat, Jeff Dean, and others. 34 | // 35 | // The messages in this file describe the definitions found in .proto files. 36 | // A valid .proto file can be translated directly to a FileDescriptorProto 37 | // without any other information (e.g. without reading its imports). 38 | 39 | 40 | syntax = "proto2"; 41 | 42 | package google.protobuf; 43 | 44 | option go_package = "google.golang.org/protobuf/types/descriptorpb"; 45 | option java_package = "com.google.protobuf"; 46 | option java_outer_classname = "DescriptorProtos"; 47 | option csharp_namespace = "Google.Protobuf.Reflection"; 48 | option objc_class_prefix = "GPB"; 49 | option cc_enable_arenas = true; 50 | 51 | // descriptor.proto must be optimized for speed because reflection-based 52 | // algorithms don't work during bootstrapping. 53 | option optimize_for = SPEED; 54 | 55 | // The protocol compiler can output a FileDescriptorSet containing the .proto 56 | // files it parses. 57 | message FileDescriptorSet { 58 | repeated FileDescriptorProto file = 1; 59 | } 60 | 61 | // Describes a complete .proto file. 62 | message FileDescriptorProto { 63 | optional string name = 1; // file name, relative to root of source tree 64 | optional string package = 2; // e.g. "foo", "foo.bar", etc. 65 | 66 | // Names of files imported by this file. 67 | repeated string dependency = 3; 68 | // Indexes of the public imported files in the dependency list above. 69 | repeated int32 public_dependency = 10; 70 | // Indexes of the weak imported files in the dependency list. 71 | // For Google-internal migration only. Do not use. 72 | repeated int32 weak_dependency = 11; 73 | 74 | // All top-level definitions in this file. 75 | repeated DescriptorProto message_type = 4; 76 | repeated EnumDescriptorProto enum_type = 5; 77 | repeated ServiceDescriptorProto service = 6; 78 | repeated FieldDescriptorProto extension = 7; 79 | 80 | optional FileOptions options = 8; 81 | 82 | // This field contains optional information about the original source code. 83 | // You may safely remove this entire field without harming runtime 84 | // functionality of the descriptors -- the information is needed only by 85 | // development tools. 86 | optional SourceCodeInfo source_code_info = 9; 87 | 88 | // The syntax of the proto file. 89 | // The supported values are "proto2" and "proto3". 90 | optional string syntax = 12; 91 | } 92 | 93 | // Describes a message type. 94 | message DescriptorProto { 95 | optional string name = 1; 96 | 97 | repeated FieldDescriptorProto field = 2; 98 | repeated FieldDescriptorProto extension = 6; 99 | 100 | repeated DescriptorProto nested_type = 3; 101 | repeated EnumDescriptorProto enum_type = 4; 102 | 103 | message ExtensionRange { 104 | optional int32 start = 1; // Inclusive. 105 | optional int32 end = 2; // Exclusive. 106 | 107 | optional ExtensionRangeOptions options = 3; 108 | } 109 | repeated ExtensionRange extension_range = 5; 110 | 111 | repeated OneofDescriptorProto oneof_decl = 8; 112 | 113 | optional MessageOptions options = 7; 114 | 115 | // Range of reserved tag numbers. Reserved tag numbers may not be used by 116 | // fields or extension ranges in the same message. Reserved ranges may 117 | // not overlap. 118 | message ReservedRange { 119 | optional int32 start = 1; // Inclusive. 120 | optional int32 end = 2; // Exclusive. 121 | } 122 | repeated ReservedRange reserved_range = 9; 123 | // Reserved field names, which may not be used by fields in the same message. 124 | // A given name may only be reserved once. 125 | repeated string reserved_name = 10; 126 | } 127 | 128 | message ExtensionRangeOptions { 129 | // The parser stores options it doesn't recognize here. See above. 130 | repeated UninterpretedOption uninterpreted_option = 999; 131 | 132 | 133 | // Clients can define custom options in extensions of this message. See above. 134 | extensions 1000 to max; 135 | } 136 | 137 | // Describes a field within a message. 138 | message FieldDescriptorProto { 139 | enum Type { 140 | // 0 is reserved for errors. 141 | // Order is weird for historical reasons. 142 | TYPE_DOUBLE = 1; 143 | TYPE_FLOAT = 2; 144 | // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if 145 | // negative values are likely. 146 | TYPE_INT64 = 3; 147 | TYPE_UINT64 = 4; 148 | // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if 149 | // negative values are likely. 150 | TYPE_INT32 = 5; 151 | TYPE_FIXED64 = 6; 152 | TYPE_FIXED32 = 7; 153 | TYPE_BOOL = 8; 154 | TYPE_STRING = 9; 155 | // Tag-delimited aggregate. 156 | // Group type is deprecated and not supported in proto3. However, Proto3 157 | // implementations should still be able to parse the group wire format and 158 | // treat group fields as unknown fields. 159 | TYPE_GROUP = 10; 160 | TYPE_MESSAGE = 11; // Length-delimited aggregate. 161 | 162 | // New in version 2. 163 | TYPE_BYTES = 12; 164 | TYPE_UINT32 = 13; 165 | TYPE_ENUM = 14; 166 | TYPE_SFIXED32 = 15; 167 | TYPE_SFIXED64 = 16; 168 | TYPE_SINT32 = 17; // Uses ZigZag encoding. 169 | TYPE_SINT64 = 18; // Uses ZigZag encoding. 170 | } 171 | 172 | enum Label { 173 | // 0 is reserved for errors 174 | LABEL_OPTIONAL = 1; 175 | LABEL_REQUIRED = 2; 176 | LABEL_REPEATED = 3; 177 | } 178 | 179 | optional string name = 1; 180 | optional int32 number = 3; 181 | optional Label label = 4; 182 | 183 | // If type_name is set, this need not be set. If both this and type_name 184 | // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. 185 | optional Type type = 5; 186 | 187 | // For message and enum types, this is the name of the type. If the name 188 | // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping 189 | // rules are used to find the type (i.e. first the nested types within this 190 | // message are searched, then within the parent, on up to the root 191 | // namespace). 192 | optional string type_name = 6; 193 | 194 | // For extensions, this is the name of the type being extended. It is 195 | // resolved in the same manner as type_name. 196 | optional string extendee = 2; 197 | 198 | // For numeric types, contains the original text representation of the value. 199 | // For booleans, "true" or "false". 200 | // For strings, contains the default text contents (not escaped in any way). 201 | // For bytes, contains the C escaped value. All bytes >= 128 are escaped. 202 | // TODO(kenton): Base-64 encode? 203 | optional string default_value = 7; 204 | 205 | // If set, gives the index of a oneof in the containing type's oneof_decl 206 | // list. This field is a member of that oneof. 207 | optional int32 oneof_index = 9; 208 | 209 | // JSON name of this field. The value is set by protocol compiler. If the 210 | // user has set a "json_name" option on this field, that option's value 211 | // will be used. Otherwise, it's deduced from the field's name by converting 212 | // it to camelCase. 213 | optional string json_name = 10; 214 | 215 | optional FieldOptions options = 8; 216 | 217 | // If true, this is a proto3 "optional". When a proto3 field is optional, it 218 | // tracks presence regardless of field type. 219 | // 220 | // When proto3_optional is true, this field must be belong to a oneof to 221 | // signal to old proto3 clients that presence is tracked for this field. This 222 | // oneof is known as a "synthetic" oneof, and this field must be its sole 223 | // member (each proto3 optional field gets its own synthetic oneof). Synthetic 224 | // oneofs exist in the descriptor only, and do not generate any API. Synthetic 225 | // oneofs must be ordered after all "real" oneofs. 226 | // 227 | // For message fields, proto3_optional doesn't create any semantic change, 228 | // since non-repeated message fields always track presence. However it still 229 | // indicates the semantic detail of whether the user wrote "optional" or not. 230 | // This can be useful for round-tripping the .proto file. For consistency we 231 | // give message fields a synthetic oneof also, even though it is not required 232 | // to track presence. This is especially important because the parser can't 233 | // tell if a field is a message or an enum, so it must always create a 234 | // synthetic oneof. 235 | // 236 | // Proto2 optional fields do not set this flag, because they already indicate 237 | // optional with `LABEL_OPTIONAL`. 238 | optional bool proto3_optional = 17; 239 | } 240 | 241 | // Describes a oneof. 242 | message OneofDescriptorProto { 243 | optional string name = 1; 244 | optional OneofOptions options = 2; 245 | } 246 | 247 | // Describes an enum type. 248 | message EnumDescriptorProto { 249 | optional string name = 1; 250 | 251 | repeated EnumValueDescriptorProto value = 2; 252 | 253 | optional EnumOptions options = 3; 254 | 255 | // Range of reserved numeric values. Reserved values may not be used by 256 | // entries in the same enum. Reserved ranges may not overlap. 257 | // 258 | // Note that this is distinct from DescriptorProto.ReservedRange in that it 259 | // is inclusive such that it can appropriately represent the entire int32 260 | // domain. 261 | message EnumReservedRange { 262 | optional int32 start = 1; // Inclusive. 263 | optional int32 end = 2; // Inclusive. 264 | } 265 | 266 | // Range of reserved numeric values. Reserved numeric values may not be used 267 | // by enum values in the same enum declaration. Reserved ranges may not 268 | // overlap. 269 | repeated EnumReservedRange reserved_range = 4; 270 | 271 | // Reserved enum value names, which may not be reused. A given name may only 272 | // be reserved once. 273 | repeated string reserved_name = 5; 274 | } 275 | 276 | // Describes a value within an enum. 277 | message EnumValueDescriptorProto { 278 | optional string name = 1; 279 | optional int32 number = 2; 280 | 281 | optional EnumValueOptions options = 3; 282 | } 283 | 284 | // Describes a service. 285 | message ServiceDescriptorProto { 286 | optional string name = 1; 287 | repeated MethodDescriptorProto method = 2; 288 | 289 | optional ServiceOptions options = 3; 290 | } 291 | 292 | // Describes a method of a service. 293 | message MethodDescriptorProto { 294 | optional string name = 1; 295 | 296 | // Input and output type names. These are resolved in the same way as 297 | // FieldDescriptorProto.type_name, but must refer to a message type. 298 | optional string input_type = 2; 299 | optional string output_type = 3; 300 | 301 | optional MethodOptions options = 4; 302 | 303 | // Identifies if client streams multiple client messages 304 | optional bool client_streaming = 5 [default = false]; 305 | // Identifies if server streams multiple server messages 306 | optional bool server_streaming = 6 [default = false]; 307 | } 308 | 309 | 310 | // =================================================================== 311 | // Options 312 | 313 | // Each of the definitions above may have "options" attached. These are 314 | // just annotations which may cause code to be generated slightly differently 315 | // or may contain hints for code that manipulates protocol messages. 316 | // 317 | // Clients may define custom options as extensions of the *Options messages. 318 | // These extensions may not yet be known at parsing time, so the parser cannot 319 | // store the values in them. Instead it stores them in a field in the *Options 320 | // message called uninterpreted_option. This field must have the same name 321 | // across all *Options messages. We then use this field to populate the 322 | // extensions when we build a descriptor, at which point all protos have been 323 | // parsed and so all extensions are known. 324 | // 325 | // Extension numbers for custom options may be chosen as follows: 326 | // * For options which will only be used within a single application or 327 | // organization, or for experimental options, use field numbers 50000 328 | // through 99999. It is up to you to ensure that you do not use the 329 | // same number for multiple options. 330 | // * For options which will be published and used publicly by multiple 331 | // independent entities, e-mail protobuf-global-extension-registry@google.com 332 | // to reserve extension numbers. Simply provide your project name (e.g. 333 | // Objective-C plugin) and your project website (if available) -- there's no 334 | // need to explain how you intend to use them. Usually you only need one 335 | // extension number. You can declare multiple options with only one extension 336 | // number by putting them in a sub-message. See the Custom Options section of 337 | // the docs for examples: 338 | // https://developers.google.com/protocol-buffers/docs/proto#options 339 | // If this turns out to be popular, a web service will be set up 340 | // to automatically assign option numbers. 341 | 342 | message FileOptions { 343 | 344 | // Sets the Java package where classes generated from this .proto will be 345 | // placed. By default, the proto package is used, but this is often 346 | // inappropriate because proto packages do not normally start with backwards 347 | // domain names. 348 | optional string java_package = 1; 349 | 350 | 351 | // Controls the name of the wrapper Java class generated for the .proto file. 352 | // That class will always contain the .proto file's getDescriptor() method as 353 | // well as any top-level extensions defined in the .proto file. 354 | // If java_multiple_files is disabled, then all the other classes from the 355 | // .proto file will be nested inside the single wrapper outer class. 356 | optional string java_outer_classname = 8; 357 | 358 | // If enabled, then the Java code generator will generate a separate .java 359 | // file for each top-level message, enum, and service defined in the .proto 360 | // file. Thus, these types will *not* be nested inside the wrapper class 361 | // named by java_outer_classname. However, the wrapper class will still be 362 | // generated to contain the file's getDescriptor() method as well as any 363 | // top-level extensions defined in the file. 364 | optional bool java_multiple_files = 10 [default = false]; 365 | 366 | // This option does nothing. 367 | optional bool java_generate_equals_and_hash = 20 [deprecated=true]; 368 | 369 | // If set true, then the Java2 code generator will generate code that 370 | // throws an exception whenever an attempt is made to assign a non-UTF-8 371 | // byte sequence to a string field. 372 | // Message reflection will do the same. 373 | // However, an extension field still accepts non-UTF-8 byte sequences. 374 | // This option has no effect on when used with the lite runtime. 375 | optional bool java_string_check_utf8 = 27 [default = false]; 376 | 377 | 378 | // Generated classes can be optimized for speed or code size. 379 | enum OptimizeMode { 380 | SPEED = 1; // Generate complete code for parsing, serialization, 381 | // etc. 382 | CODE_SIZE = 2; // Use ReflectionOps to implement these methods. 383 | LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. 384 | } 385 | optional OptimizeMode optimize_for = 9 [default = SPEED]; 386 | 387 | // Sets the Go package where structs generated from this .proto will be 388 | // placed. If omitted, the Go package will be derived from the following: 389 | // - The basename of the package import path, if provided. 390 | // - Otherwise, the package statement in the .proto file, if present. 391 | // - Otherwise, the basename of the .proto file, without extension. 392 | optional string go_package = 11; 393 | 394 | 395 | 396 | 397 | // Should generic services be generated in each language? "Generic" services 398 | // are not specific to any particular RPC system. They are generated by the 399 | // main code generators in each language (without additional plugins). 400 | // Generic services were the only kind of service generation supported by 401 | // early versions of google.protobuf. 402 | // 403 | // Generic services are now considered deprecated in favor of using plugins 404 | // that generate code specific to your particular RPC system. Therefore, 405 | // these default to false. Old code which depends on generic services should 406 | // explicitly set them to true. 407 | optional bool cc_generic_services = 16 [default = false]; 408 | optional bool java_generic_services = 17 [default = false]; 409 | optional bool py_generic_services = 18 [default = false]; 410 | optional bool php_generic_services = 42 [default = false]; 411 | 412 | // Is this file deprecated? 413 | // Depending on the target platform, this can emit Deprecated annotations 414 | // for everything in the file, or it will be completely ignored; in the very 415 | // least, this is a formalization for deprecating files. 416 | optional bool deprecated = 23 [default = false]; 417 | 418 | // Enables the use of arenas for the proto messages in this file. This applies 419 | // only to generated classes for C++. 420 | optional bool cc_enable_arenas = 31 [default = true]; 421 | 422 | 423 | // Sets the objective c class prefix which is prepended to all objective c 424 | // generated classes from this .proto. There is no default. 425 | optional string objc_class_prefix = 36; 426 | 427 | // Namespace for generated classes; defaults to the package. 428 | optional string csharp_namespace = 37; 429 | 430 | // By default Swift generators will take the proto package and CamelCase it 431 | // replacing '.' with underscore and use that to prefix the types/symbols 432 | // defined. When this options is provided, they will use this value instead 433 | // to prefix the types/symbols defined. 434 | optional string swift_prefix = 39; 435 | 436 | // Sets the php class prefix which is prepended to all php generated classes 437 | // from this .proto. Default is empty. 438 | optional string php_class_prefix = 40; 439 | 440 | // Use this option to change the namespace of php generated classes. Default 441 | // is empty. When this option is empty, the package name will be used for 442 | // determining the namespace. 443 | optional string php_namespace = 41; 444 | 445 | // Use this option to change the namespace of php generated metadata classes. 446 | // Default is empty. When this option is empty, the proto file name will be 447 | // used for determining the namespace. 448 | optional string php_metadata_namespace = 44; 449 | 450 | // Use this option to change the package of ruby generated classes. Default 451 | // is empty. When this option is not set, the package name will be used for 452 | // determining the ruby package. 453 | optional string ruby_package = 45; 454 | 455 | 456 | // The parser stores options it doesn't recognize here. 457 | // See the documentation for the "Options" section above. 458 | repeated UninterpretedOption uninterpreted_option = 999; 459 | 460 | // Clients can define custom options in extensions of this message. 461 | // See the documentation for the "Options" section above. 462 | extensions 1000 to max; 463 | 464 | reserved 38; 465 | } 466 | 467 | message MessageOptions { 468 | // Set true to use the old proto1 MessageSet wire format for extensions. 469 | // This is provided for backwards-compatibility with the MessageSet wire 470 | // format. You should not use this for any other reason: It's less 471 | // efficient, has fewer features, and is more complicated. 472 | // 473 | // The message must be defined exactly as follows: 474 | // message Foo { 475 | // option message_set_wire_format = true; 476 | // extensions 4 to max; 477 | // } 478 | // Note that the message cannot have any defined fields; MessageSets only 479 | // have extensions. 480 | // 481 | // All extensions of your type must be singular messages; e.g. they cannot 482 | // be int32s, enums, or repeated messages. 483 | // 484 | // Because this is an option, the above two restrictions are not enforced by 485 | // the protocol compiler. 486 | optional bool message_set_wire_format = 1 [default = false]; 487 | 488 | // Disables the generation of the standard "descriptor()" accessor, which can 489 | // conflict with a field of the same name. This is meant to make migration 490 | // from proto1 easier; new code should avoid fields named "descriptor". 491 | optional bool no_standard_descriptor_accessor = 2 [default = false]; 492 | 493 | // Is this message deprecated? 494 | // Depending on the target platform, this can emit Deprecated annotations 495 | // for the message, or it will be completely ignored; in the very least, 496 | // this is a formalization for deprecating messages. 497 | optional bool deprecated = 3 [default = false]; 498 | 499 | reserved 4, 5, 6; 500 | 501 | // Whether the message is an automatically generated map entry type for the 502 | // maps field. 503 | // 504 | // For maps fields: 505 | // map map_field = 1; 506 | // The parsed descriptor looks like: 507 | // message MapFieldEntry { 508 | // option map_entry = true; 509 | // optional KeyType key = 1; 510 | // optional ValueType value = 2; 511 | // } 512 | // repeated MapFieldEntry map_field = 1; 513 | // 514 | // Implementations may choose not to generate the map_entry=true message, but 515 | // use a native map in the target language to hold the keys and values. 516 | // The reflection APIs in such implementations still need to work as 517 | // if the field is a repeated message field. 518 | // 519 | // NOTE: Do not set the option in .proto files. Always use the maps syntax 520 | // instead. The option should only be implicitly set by the proto compiler 521 | // parser. 522 | optional bool map_entry = 7; 523 | 524 | reserved 8; // javalite_serializable 525 | reserved 9; // javanano_as_lite 526 | 527 | 528 | // The parser stores options it doesn't recognize here. See above. 529 | repeated UninterpretedOption uninterpreted_option = 999; 530 | 531 | // Clients can define custom options in extensions of this message. See above. 532 | extensions 1000 to max; 533 | } 534 | 535 | message FieldOptions { 536 | // The ctype option instructs the C++ code generator to use a different 537 | // representation of the field than it normally would. See the specific 538 | // options below. This option is not yet implemented in the open source 539 | // release -- sorry, we'll try to include it in a future version! 540 | optional CType ctype = 1 [default = STRING]; 541 | enum CType { 542 | // Default mode. 543 | STRING = 0; 544 | 545 | CORD = 1; 546 | 547 | STRING_PIECE = 2; 548 | } 549 | // The packed option can be enabled for repeated primitive fields to enable 550 | // a more efficient representation on the wire. Rather than repeatedly 551 | // writing the tag and type for each element, the entire array is encoded as 552 | // a single length-delimited blob. In proto3, only explicit setting it to 553 | // false will avoid using packed encoding. 554 | optional bool packed = 2; 555 | 556 | // The jstype option determines the JavaScript type used for values of the 557 | // field. The option is permitted only for 64 bit integral and fixed types 558 | // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING 559 | // is represented as JavaScript string, which avoids loss of precision that 560 | // can happen when a large value is converted to a floating point JavaScript. 561 | // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to 562 | // use the JavaScript "number" type. The behavior of the default option 563 | // JS_NORMAL is implementation dependent. 564 | // 565 | // This option is an enum to permit additional types to be added, e.g. 566 | // goog.math.Integer. 567 | optional JSType jstype = 6 [default = JS_NORMAL]; 568 | enum JSType { 569 | // Use the default type. 570 | JS_NORMAL = 0; 571 | 572 | // Use JavaScript strings. 573 | JS_STRING = 1; 574 | 575 | // Use JavaScript numbers. 576 | JS_NUMBER = 2; 577 | } 578 | 579 | // Should this field be parsed lazily? Lazy applies only to message-type 580 | // fields. It means that when the outer message is initially parsed, the 581 | // inner message's contents will not be parsed but instead stored in encoded 582 | // form. The inner message will actually be parsed when it is first accessed. 583 | // 584 | // This is only a hint. Implementations are free to choose whether to use 585 | // eager or lazy parsing regardless of the value of this option. However, 586 | // setting this option true suggests that the protocol author believes that 587 | // using lazy parsing on this field is worth the additional bookkeeping 588 | // overhead typically needed to implement it. 589 | // 590 | // This option does not affect the public interface of any generated code; 591 | // all method signatures remain the same. Furthermore, thread-safety of the 592 | // interface is not affected by this option; const methods remain safe to 593 | // call from multiple threads concurrently, while non-const methods continue 594 | // to require exclusive access. 595 | // 596 | // 597 | // Note that implementations may choose not to check required fields within 598 | // a lazy sub-message. That is, calling IsInitialized() on the outer message 599 | // may return true even if the inner message has missing required fields. 600 | // This is necessary because otherwise the inner message would have to be 601 | // parsed in order to perform the check, defeating the purpose of lazy 602 | // parsing. An implementation which chooses not to check required fields 603 | // must be consistent about it. That is, for any particular sub-message, the 604 | // implementation must either *always* check its required fields, or *never* 605 | // check its required fields, regardless of whether or not the message has 606 | // been parsed. 607 | optional bool lazy = 5 [default = false]; 608 | 609 | // Is this field deprecated? 610 | // Depending on the target platform, this can emit Deprecated annotations 611 | // for accessors, or it will be completely ignored; in the very least, this 612 | // is a formalization for deprecating fields. 613 | optional bool deprecated = 3 [default = false]; 614 | 615 | // For Google-internal migration only. Do not use. 616 | optional bool weak = 10 [default = false]; 617 | 618 | 619 | // The parser stores options it doesn't recognize here. See above. 620 | repeated UninterpretedOption uninterpreted_option = 999; 621 | 622 | // Clients can define custom options in extensions of this message. See above. 623 | extensions 1000 to max; 624 | 625 | reserved 4; // removed jtype 626 | } 627 | 628 | message OneofOptions { 629 | // The parser stores options it doesn't recognize here. See above. 630 | repeated UninterpretedOption uninterpreted_option = 999; 631 | 632 | // Clients can define custom options in extensions of this message. See above. 633 | extensions 1000 to max; 634 | } 635 | 636 | message EnumOptions { 637 | 638 | // Set this option to true to allow mapping different tag names to the same 639 | // value. 640 | optional bool allow_alias = 2; 641 | 642 | // Is this enum deprecated? 643 | // Depending on the target platform, this can emit Deprecated annotations 644 | // for the enum, or it will be completely ignored; in the very least, this 645 | // is a formalization for deprecating enums. 646 | optional bool deprecated = 3 [default = false]; 647 | 648 | reserved 5; // javanano_as_lite 649 | 650 | // The parser stores options it doesn't recognize here. See above. 651 | repeated UninterpretedOption uninterpreted_option = 999; 652 | 653 | // Clients can define custom options in extensions of this message. See above. 654 | extensions 1000 to max; 655 | } 656 | 657 | message EnumValueOptions { 658 | // Is this enum value deprecated? 659 | // Depending on the target platform, this can emit Deprecated annotations 660 | // for the enum value, or it will be completely ignored; in the very least, 661 | // this is a formalization for deprecating enum values. 662 | optional bool deprecated = 1 [default = false]; 663 | 664 | // The parser stores options it doesn't recognize here. See above. 665 | repeated UninterpretedOption uninterpreted_option = 999; 666 | 667 | // Clients can define custom options in extensions of this message. See above. 668 | extensions 1000 to max; 669 | } 670 | 671 | message ServiceOptions { 672 | 673 | // Note: Field numbers 1 through 32 are reserved for Google's internal RPC 674 | // framework. We apologize for hoarding these numbers to ourselves, but 675 | // we were already using them long before we decided to release Protocol 676 | // Buffers. 677 | 678 | // Is this service deprecated? 679 | // Depending on the target platform, this can emit Deprecated annotations 680 | // for the service, or it will be completely ignored; in the very least, 681 | // this is a formalization for deprecating services. 682 | optional bool deprecated = 33 [default = false]; 683 | 684 | // The parser stores options it doesn't recognize here. See above. 685 | repeated UninterpretedOption uninterpreted_option = 999; 686 | 687 | // Clients can define custom options in extensions of this message. See above. 688 | extensions 1000 to max; 689 | } 690 | 691 | message MethodOptions { 692 | 693 | // Note: Field numbers 1 through 32 are reserved for Google's internal RPC 694 | // framework. We apologize for hoarding these numbers to ourselves, but 695 | // we were already using them long before we decided to release Protocol 696 | // Buffers. 697 | 698 | // Is this method deprecated? 699 | // Depending on the target platform, this can emit Deprecated annotations 700 | // for the method, or it will be completely ignored; in the very least, 701 | // this is a formalization for deprecating methods. 702 | optional bool deprecated = 33 [default = false]; 703 | 704 | // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, 705 | // or neither? HTTP based RPC implementation may choose GET verb for safe 706 | // methods, and PUT verb for idempotent methods instead of the default POST. 707 | enum IdempotencyLevel { 708 | IDEMPOTENCY_UNKNOWN = 0; 709 | NO_SIDE_EFFECTS = 1; // implies idempotent 710 | IDEMPOTENT = 2; // idempotent, but may have side effects 711 | } 712 | optional IdempotencyLevel idempotency_level = 34 713 | [default = IDEMPOTENCY_UNKNOWN]; 714 | 715 | // The parser stores options it doesn't recognize here. See above. 716 | repeated UninterpretedOption uninterpreted_option = 999; 717 | 718 | // Clients can define custom options in extensions of this message. See above. 719 | extensions 1000 to max; 720 | } 721 | 722 | 723 | // A message representing a option the parser does not recognize. This only 724 | // appears in options protos created by the compiler::Parser class. 725 | // DescriptorPool resolves these when building Descriptor objects. Therefore, 726 | // options protos in descriptor objects (e.g. returned by Descriptor::options(), 727 | // or produced by Descriptor::CopyTo()) will never have UninterpretedOptions 728 | // in them. 729 | message UninterpretedOption { 730 | // The name of the uninterpreted option. Each string represents a segment in 731 | // a dot-separated name. is_extension is true iff a segment represents an 732 | // extension (denoted with parentheses in options specs in .proto files). 733 | // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents 734 | // "foo.(bar.baz).qux". 735 | message NamePart { 736 | required string name_part = 1; 737 | required bool is_extension = 2; 738 | } 739 | repeated NamePart name = 2; 740 | 741 | // The value of the uninterpreted option, in whatever type the tokenizer 742 | // identified it as during parsing. Exactly one of these should be set. 743 | optional string identifier_value = 3; 744 | optional uint64 positive_int_value = 4; 745 | optional int64 negative_int_value = 5; 746 | optional double double_value = 6; 747 | optional bytes string_value = 7; 748 | optional string aggregate_value = 8; 749 | } 750 | 751 | // =================================================================== 752 | // Optional source code info 753 | 754 | // Encapsulates information about the original source file from which a 755 | // FileDescriptorProto was generated. 756 | message SourceCodeInfo { 757 | // A Location identifies a piece of source code in a .proto file which 758 | // corresponds to a particular definition. This information is intended 759 | // to be useful to IDEs, code indexers, documentation generators, and similar 760 | // tools. 761 | // 762 | // For example, say we have a file like: 763 | // message Foo { 764 | // optional string foo = 1; 765 | // } 766 | // Let's look at just the field definition: 767 | // optional string foo = 1; 768 | // ^ ^^ ^^ ^ ^^^ 769 | // a bc de f ghi 770 | // We have the following locations: 771 | // span path represents 772 | // [a,i) [ 4, 0, 2, 0 ] The whole field definition. 773 | // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). 774 | // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). 775 | // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). 776 | // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). 777 | // 778 | // Notes: 779 | // - A location may refer to a repeated field itself (i.e. not to any 780 | // particular index within it). This is used whenever a set of elements are 781 | // logically enclosed in a single code segment. For example, an entire 782 | // extend block (possibly containing multiple extension definitions) will 783 | // have an outer location whose path refers to the "extensions" repeated 784 | // field without an index. 785 | // - Multiple locations may have the same path. This happens when a single 786 | // logical declaration is spread out across multiple places. The most 787 | // obvious example is the "extend" block again -- there may be multiple 788 | // extend blocks in the same scope, each of which will have the same path. 789 | // - A location's span is not always a subset of its parent's span. For 790 | // example, the "extendee" of an extension declaration appears at the 791 | // beginning of the "extend" block and is shared by all extensions within 792 | // the block. 793 | // - Just because a location's span is a subset of some other location's span 794 | // does not mean that it is a descendant. For example, a "group" defines 795 | // both a type and a field in a single declaration. Thus, the locations 796 | // corresponding to the type and field and their components will overlap. 797 | // - Code which tries to interpret locations should probably be designed to 798 | // ignore those that it doesn't understand, as more types of locations could 799 | // be recorded in the future. 800 | repeated Location location = 1; 801 | message Location { 802 | // Identifies which part of the FileDescriptorProto was defined at this 803 | // location. 804 | // 805 | // Each element is a field number or an index. They form a path from 806 | // the root FileDescriptorProto to the place where the definition. For 807 | // example, this path: 808 | // [ 4, 3, 2, 7, 1 ] 809 | // refers to: 810 | // file.message_type(3) // 4, 3 811 | // .field(7) // 2, 7 812 | // .name() // 1 813 | // This is because FileDescriptorProto.message_type has field number 4: 814 | // repeated DescriptorProto message_type = 4; 815 | // and DescriptorProto.field has field number 2: 816 | // repeated FieldDescriptorProto field = 2; 817 | // and FieldDescriptorProto.name has field number 1: 818 | // optional string name = 1; 819 | // 820 | // Thus, the above path gives the location of a field name. If we removed 821 | // the last element: 822 | // [ 4, 3, 2, 7 ] 823 | // this path refers to the whole field declaration (from the beginning 824 | // of the label to the terminating semicolon). 825 | repeated int32 path = 1 [packed = true]; 826 | 827 | // Always has exactly three or four elements: start line, start column, 828 | // end line (optional, otherwise assumed same as start line), end column. 829 | // These are packed into a single field for efficiency. Note that line 830 | // and column numbers are zero-based -- typically you will want to add 831 | // 1 to each before displaying to a user. 832 | repeated int32 span = 2 [packed = true]; 833 | 834 | // If this SourceCodeInfo represents a complete declaration, these are any 835 | // comments appearing before and after the declaration which appear to be 836 | // attached to the declaration. 837 | // 838 | // A series of line comments appearing on consecutive lines, with no other 839 | // tokens appearing on those lines, will be treated as a single comment. 840 | // 841 | // leading_detached_comments will keep paragraphs of comments that appear 842 | // before (but not connected to) the current element. Each paragraph, 843 | // separated by empty lines, will be one comment element in the repeated 844 | // field. 845 | // 846 | // Only the comment content is provided; comment markers (e.g. //) are 847 | // stripped out. For block comments, leading whitespace and an asterisk 848 | // will be stripped from the beginning of each line other than the first. 849 | // Newlines are included in the output. 850 | // 851 | // Examples: 852 | // 853 | // optional int32 foo = 1; // Comment attached to foo. 854 | // // Comment attached to bar. 855 | // optional int32 bar = 2; 856 | // 857 | // optional string baz = 3; 858 | // // Comment attached to baz. 859 | // // Another line attached to baz. 860 | // 861 | // // Comment attached to qux. 862 | // // 863 | // // Another line attached to qux. 864 | // optional double qux = 4; 865 | // 866 | // // Detached comment for corge. This is not leading or trailing comments 867 | // // to qux or corge because there are blank lines separating it from 868 | // // both. 869 | // 870 | // // Detached comment for corge paragraph 2. 871 | // 872 | // optional string corge = 5; 873 | // /* Block comment attached 874 | // * to corge. Leading asterisks 875 | // * will be removed. */ 876 | // /* Block comment attached to 877 | // * grault. */ 878 | // optional int32 grault = 6; 879 | // 880 | // // ignored detached comments. 881 | optional string leading_comments = 3; 882 | optional string trailing_comments = 4; 883 | repeated string leading_detached_comments = 6; 884 | } 885 | } 886 | 887 | // Describes the relationship between generated code and its original source 888 | // file. A GeneratedCodeInfo message is associated with only one generated 889 | // source file, but may contain references to different source .proto files. 890 | message GeneratedCodeInfo { 891 | // An Annotation connects some span of text in generated code to an element 892 | // of its generating .proto file. 893 | repeated Annotation annotation = 1; 894 | message Annotation { 895 | // Identifies the element in the original source .proto file. This field 896 | // is formatted the same as SourceCodeInfo.Location.path. 897 | repeated int32 path = 1 [packed = true]; 898 | 899 | // Identifies the filesystem path to the original source .proto. 900 | optional string source_file = 2; 901 | 902 | // Identifies the starting offset in bytes in the generated code 903 | // that relates to the identified object. 904 | optional int32 begin = 3; 905 | 906 | // Identifies the ending offset in bytes in the generated code that 907 | // relates to the identified offset. The end offset should be one past 908 | // the last relevant byte (so the length of the text = end - begin). 909 | optional int32 end = 4; 910 | } 911 | } 912 | --------------------------------------------------------------------------------