Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
1759f91cd1 | |||
b9d6dea90b | |||
db062baab2 |
80
.air.toml
Normal file
80
.air.toml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# .air.toml
|
||||||
|
#
|
||||||
|
# A configuration file for the 'air' live-reloading tool.
|
||||||
|
# This configuration is tailored for a Go project that needs to be run with specific command-line flags
|
||||||
|
# and requires graceful handling of system signals like SIGINT and SIGTERM.
|
||||||
|
#
|
||||||
|
# To use:
|
||||||
|
# 1. Install air: `go install github.com/cosmtrek/air@latest`
|
||||||
|
# 2. Place this file, renamed to `.air.toml`, in the root of your project.
|
||||||
|
# 3. Run `air` from your terminal in the project root.
|
||||||
|
|
||||||
|
# The root directory of your project to watch for changes.
|
||||||
|
# '.' indicates the current directory where air is run.
|
||||||
|
root = "."
|
||||||
|
|
||||||
|
# A temporary directory for air to store its build artifacts.
|
||||||
|
# You should add this directory to your .gitignore file.
|
||||||
|
tmp_dir = "tmp"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
# Step 1: Build the Go binary and place it in the tmp directory.
|
||||||
|
# Step 2: Copy the configuration file into the tmp directory as well.
|
||||||
|
# This ensures all runtime assets are in one place.
|
||||||
|
cmd = "go build -o ./tmp/main . && cp config.yaml ./tmp/"
|
||||||
|
|
||||||
|
# The 'full_bin' command gives us complete control over how the app is run.
|
||||||
|
# We first change the directory to 'tmp' so that the application's working
|
||||||
|
# directory is where the binary and its config file are located.
|
||||||
|
# Then, we execute the binary, pointing it to the config file in the same directory.
|
||||||
|
full_bin = "cd ./tmp && ./main -config config.yaml"
|
||||||
|
|
||||||
|
# A list of directories to watch for file changes.
|
||||||
|
# Air will recursively watch these directories.
|
||||||
|
include_dir = ["."]
|
||||||
|
|
||||||
|
# A list of file extensions to watch.
|
||||||
|
# Air will restart when any of these files change.
|
||||||
|
include_ext = ["go", "toml", "yaml", "yml"]
|
||||||
|
|
||||||
|
# A list of directories to ignore.
|
||||||
|
# It's good practice to ignore temporary directories, vendor folders, and git history.
|
||||||
|
exclude_dir = ["tmp", "vendor", ".git"]
|
||||||
|
|
||||||
|
# A list of specific files to ignore.
|
||||||
|
exclude_file = []
|
||||||
|
|
||||||
|
# A list of regular expressions to exclude files or directories.
|
||||||
|
exclude_regex = ["_test.go"]
|
||||||
|
|
||||||
|
# A list of files or directories to watch that are not in the 'include_dir'.
|
||||||
|
# Useful for watching template files if they are outside your main source directories.
|
||||||
|
include_file = []
|
||||||
|
|
||||||
|
# This setting is crucial for graceful shutdowns.
|
||||||
|
# It stops the running process on a file change before building and restarting.
|
||||||
|
# This ensures that your application's shutdown logic is triggered.
|
||||||
|
stop_on_error = true
|
||||||
|
|
||||||
|
# Send SIGINT (Ctrl+C) to the running process before killing it.
|
||||||
|
# This is essential for allowing your application to handle the signal and shut down gracefully.
|
||||||
|
send_interrupt = true
|
||||||
|
|
||||||
|
# The delay in milliseconds to wait for the process to shut down gracefully after sending SIGINT.
|
||||||
|
# If your app needs more time for cleanup, you can increase this value.
|
||||||
|
kill_delay = 500 # ms
|
||||||
|
|
||||||
|
[log]
|
||||||
|
# Show timestamps in the log output.
|
||||||
|
time = true
|
||||||
|
|
||||||
|
[color]
|
||||||
|
# Customize colors for different parts of the air output.
|
||||||
|
main = "magenta"
|
||||||
|
watcher = "cyan"
|
||||||
|
build = "yellow"
|
||||||
|
runner = "green"
|
||||||
|
|
||||||
|
[misc]
|
||||||
|
# Delete the temporary binary file on exit.
|
||||||
|
clean_on_exit = true
|
@ -10,6 +10,7 @@ Check out the [go-app framework](https://gitea.libretechconsulting.com/rmcguire/
|
|||||||
|
|
||||||
- **📈 OpenTelemetry (OTEL) Metrics & Traces** – Comprehensive observability with built-in support for metrics and traces.
|
- **📈 OpenTelemetry (OTEL) Metrics & Traces** – Comprehensive observability with built-in support for metrics and traces.
|
||||||
- 📝 Logging with Zerolog – High-performance structured logging with zerolog for ultra-fast, leveled logging.
|
- 📝 Logging with Zerolog – High-performance structured logging with zerolog for ultra-fast, leveled logging.
|
||||||
|
- 💻 Local dev with air pre-configured (just run `air`)
|
||||||
- **💬 GRPC + GRPC-Gateway** – Supports RESTful JSON APIs alongside gRPC with auto-generated Swagger (OpenAPI2) specs.
|
- **💬 GRPC + GRPC-Gateway** – Supports RESTful JSON APIs alongside gRPC with auto-generated Swagger (OpenAPI2) specs.
|
||||||
- 🌐 HTTP and GRPC Middleware – Flexible middleware support for HTTP and GRPC to enhance request handling, authentication, and observability.
|
- 🌐 HTTP and GRPC Middleware – Flexible middleware support for HTTP and GRPC to enhance request handling, authentication, and observability.
|
||||||
- **📦 Multi-Arch Builds** – Robust Makefile that supports building for multiple architectures (amd64, arm64, etc.).
|
- **📦 Multi-Arch Builds** – Robust Makefile that supports building for multiple architectures (amd64, arm64, etc.).
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
package demo
|
package demo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
_ "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
|
||||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
@ -143,15 +144,15 @@ var File_demo_app_v1alpha1_app_proto protoreflect.FileDescriptor
|
|||||||
|
|
||||||
const file_demo_app_v1alpha1_app_proto_rawDesc = "" +
|
const file_demo_app_v1alpha1_app_proto_rawDesc = "" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"\x1bdemo/app/v1alpha1/app.proto\x12\x11demo.app.v1alpha1\x1a\x1cgoogle/api/annotations.proto\x1a\x1fgoogle/protobuf/timestamp.proto\">\n" +
|
"\x1bdemo/app/v1alpha1/app.proto\x12\x11demo.app.v1alpha1\x1a\x1bbuf/validate/validate.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"G\n" +
|
||||||
"\x0eGetDemoRequest\x12\x1f\n" +
|
"\x0eGetDemoRequest\x12(\n" +
|
||||||
"\blanguage\x18\x01 \x01(\tH\x00R\blanguage\x88\x01\x01B\v\n" +
|
"\blanguage\x18\x01 \x01(\tB\a\xbaH\x04r\x02\x10\x02H\x00R\blanguage\x88\x01\x01B\v\n" +
|
||||||
"\t_language\"\x93\x01\n" +
|
"\t_language\"\x9c\x01\n" +
|
||||||
"\x0fGetDemoResponse\x128\n" +
|
"\x0fGetDemoResponse\x128\n" +
|
||||||
"\ttimestamp\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12\x12\n" +
|
"\ttimestamp\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12\x12\n" +
|
||||||
"\x04fact\x18\x02 \x01(\tR\x04fact\x12\x16\n" +
|
"\x04fact\x18\x02 \x01(\tR\x04fact\x12\x16\n" +
|
||||||
"\x06source\x18\x03 \x01(\tR\x06source\x12\x1a\n" +
|
"\x06source\x18\x03 \x01(\tR\x06source\x12#\n" +
|
||||||
"\blanguage\x18\x04 \x01(\tR\blanguage2z\n" +
|
"\blanguage\x18\x04 \x01(\tB\a\xbaH\x04r\x02\x10\x02R\blanguage2z\n" +
|
||||||
"\x0eDemoAppService\x12h\n" +
|
"\x0eDemoAppService\x12h\n" +
|
||||||
"\aGetDemo\x12!.demo.app.v1alpha1.GetDemoRequest\x1a\".demo.app.v1alpha1.GetDemoResponse\"\x16\x82\xd3\xe4\x93\x02\x10\x12\x0e/v1alpha1/demoB\xd5\x01\n" +
|
"\aGetDemo\x12!.demo.app.v1alpha1.GetDemoRequest\x1a\".demo.app.v1alpha1.GetDemoResponse\"\x16\x82\xd3\xe4\x93\x02\x10\x12\x0e/v1alpha1/demoB\xd5\x01\n" +
|
||||||
"\x15com.demo.app.v1alpha1B\bAppProtoP\x01ZLgitea.libretechconsulting.com/rmcguire/go-server-with-otel/api/v1alpha1/demo\xa2\x02\x03DAX\xaa\x02\x11Demo.App.V1alpha1\xca\x02\x11Demo\\App\\V1alpha1\xe2\x02\x1dDemo\\App\\V1alpha1\\GPBMetadata\xea\x02\x13Demo::App::V1alpha1b\x06proto3"
|
"\x15com.demo.app.v1alpha1B\bAppProtoP\x01ZLgitea.libretechconsulting.com/rmcguire/go-server-with-otel/api/v1alpha1/demo\xa2\x02\x03DAX\xaa\x02\x11Demo.App.V1alpha1\xca\x02\x11Demo\\App\\V1alpha1\xe2\x02\x1dDemo\\App\\V1alpha1\\GPBMetadata\xea\x02\x13Demo::App::V1alpha1b\x06proto3"
|
||||||
|
@ -1,275 +0,0 @@
|
|||||||
// Code generated by protoc-gen-validate. DO NOT EDIT.
|
|
||||||
// source: demo/app/v1alpha1/app.proto
|
|
||||||
|
|
||||||
package demo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/mail"
|
|
||||||
"net/url"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"google.golang.org/protobuf/types/known/anypb"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ensure the imports are used
|
|
||||||
var (
|
|
||||||
_ = bytes.MinRead
|
|
||||||
_ = errors.New("")
|
|
||||||
_ = fmt.Print
|
|
||||||
_ = utf8.UTFMax
|
|
||||||
_ = (*regexp.Regexp)(nil)
|
|
||||||
_ = (*strings.Reader)(nil)
|
|
||||||
_ = net.IPv4len
|
|
||||||
_ = time.Duration(0)
|
|
||||||
_ = (*url.URL)(nil)
|
|
||||||
_ = (*mail.Address)(nil)
|
|
||||||
_ = anypb.Any{}
|
|
||||||
_ = sort.Sort
|
|
||||||
)
|
|
||||||
|
|
||||||
// Validate checks the field values on GetDemoRequest with the rules defined in
|
|
||||||
// the proto definition for this message. If any rules are violated, the first
|
|
||||||
// error encountered is returned, or nil if there are no violations.
|
|
||||||
func (m *GetDemoRequest) Validate() error {
|
|
||||||
return m.validate(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateAll checks the field values on GetDemoRequest with the rules defined
|
|
||||||
// in the proto definition for this message. If any rules are violated, the
|
|
||||||
// result is a list of violation errors wrapped in GetDemoRequestMultiError,
|
|
||||||
// or nil if none found.
|
|
||||||
func (m *GetDemoRequest) ValidateAll() error {
|
|
||||||
return m.validate(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *GetDemoRequest) validate(all bool) error {
|
|
||||||
if m == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var errors []error
|
|
||||||
|
|
||||||
if m.Language != nil {
|
|
||||||
// no validation rules for Language
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errors) > 0 {
|
|
||||||
return GetDemoRequestMultiError(errors)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDemoRequestMultiError is an error wrapping multiple validation errors
|
|
||||||
// returned by GetDemoRequest.ValidateAll() if the designated constraints
|
|
||||||
// aren't met.
|
|
||||||
type GetDemoRequestMultiError []error
|
|
||||||
|
|
||||||
// Error returns a concatenation of all the error messages it wraps.
|
|
||||||
func (m GetDemoRequestMultiError) Error() string {
|
|
||||||
msgs := make([]string, 0, len(m))
|
|
||||||
for _, err := range m {
|
|
||||||
msgs = append(msgs, err.Error())
|
|
||||||
}
|
|
||||||
return strings.Join(msgs, "; ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllErrors returns a list of validation violation errors.
|
|
||||||
func (m GetDemoRequestMultiError) AllErrors() []error { return m }
|
|
||||||
|
|
||||||
// GetDemoRequestValidationError is the validation error returned by
|
|
||||||
// GetDemoRequest.Validate if the designated constraints aren't met.
|
|
||||||
type GetDemoRequestValidationError struct {
|
|
||||||
field string
|
|
||||||
reason string
|
|
||||||
cause error
|
|
||||||
key bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Field function returns field value.
|
|
||||||
func (e GetDemoRequestValidationError) Field() string { return e.field }
|
|
||||||
|
|
||||||
// Reason function returns reason value.
|
|
||||||
func (e GetDemoRequestValidationError) Reason() string { return e.reason }
|
|
||||||
|
|
||||||
// Cause function returns cause value.
|
|
||||||
func (e GetDemoRequestValidationError) Cause() error { return e.cause }
|
|
||||||
|
|
||||||
// Key function returns key value.
|
|
||||||
func (e GetDemoRequestValidationError) Key() bool { return e.key }
|
|
||||||
|
|
||||||
// ErrorName returns error name.
|
|
||||||
func (e GetDemoRequestValidationError) ErrorName() string { return "GetDemoRequestValidationError" }
|
|
||||||
|
|
||||||
// Error satisfies the builtin error interface
|
|
||||||
func (e GetDemoRequestValidationError) Error() string {
|
|
||||||
cause := ""
|
|
||||||
if e.cause != nil {
|
|
||||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
|
||||||
}
|
|
||||||
|
|
||||||
key := ""
|
|
||||||
if e.key {
|
|
||||||
key = "key for "
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"invalid %sGetDemoRequest.%s: %s%s",
|
|
||||||
key,
|
|
||||||
e.field,
|
|
||||||
e.reason,
|
|
||||||
cause)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ error = GetDemoRequestValidationError{}
|
|
||||||
|
|
||||||
var _ interface {
|
|
||||||
Field() string
|
|
||||||
Reason() string
|
|
||||||
Key() bool
|
|
||||||
Cause() error
|
|
||||||
ErrorName() string
|
|
||||||
} = GetDemoRequestValidationError{}
|
|
||||||
|
|
||||||
// Validate checks the field values on GetDemoResponse with the rules defined
|
|
||||||
// in the proto definition for this message. If any rules are violated, the
|
|
||||||
// first error encountered is returned, or nil if there are no violations.
|
|
||||||
func (m *GetDemoResponse) Validate() error {
|
|
||||||
return m.validate(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateAll checks the field values on GetDemoResponse with the rules
|
|
||||||
// defined in the proto definition for this message. If any rules are
|
|
||||||
// violated, the result is a list of violation errors wrapped in
|
|
||||||
// GetDemoResponseMultiError, or nil if none found.
|
|
||||||
func (m *GetDemoResponse) ValidateAll() error {
|
|
||||||
return m.validate(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *GetDemoResponse) validate(all bool) error {
|
|
||||||
if m == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var errors []error
|
|
||||||
|
|
||||||
if all {
|
|
||||||
switch v := interface{}(m.GetTimestamp()).(type) {
|
|
||||||
case interface{ ValidateAll() error }:
|
|
||||||
if err := v.ValidateAll(); err != nil {
|
|
||||||
errors = append(errors, GetDemoResponseValidationError{
|
|
||||||
field: "Timestamp",
|
|
||||||
reason: "embedded message failed validation",
|
|
||||||
cause: err,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
case interface{ Validate() error }:
|
|
||||||
if err := v.Validate(); err != nil {
|
|
||||||
errors = append(errors, GetDemoResponseValidationError{
|
|
||||||
field: "Timestamp",
|
|
||||||
reason: "embedded message failed validation",
|
|
||||||
cause: err,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if v, ok := interface{}(m.GetTimestamp()).(interface{ Validate() error }); ok {
|
|
||||||
if err := v.Validate(); err != nil {
|
|
||||||
return GetDemoResponseValidationError{
|
|
||||||
field: "Timestamp",
|
|
||||||
reason: "embedded message failed validation",
|
|
||||||
cause: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no validation rules for Fact
|
|
||||||
|
|
||||||
// no validation rules for Source
|
|
||||||
|
|
||||||
// no validation rules for Language
|
|
||||||
|
|
||||||
if len(errors) > 0 {
|
|
||||||
return GetDemoResponseMultiError(errors)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDemoResponseMultiError is an error wrapping multiple validation errors
|
|
||||||
// returned by GetDemoResponse.ValidateAll() if the designated constraints
|
|
||||||
// aren't met.
|
|
||||||
type GetDemoResponseMultiError []error
|
|
||||||
|
|
||||||
// Error returns a concatenation of all the error messages it wraps.
|
|
||||||
func (m GetDemoResponseMultiError) Error() string {
|
|
||||||
msgs := make([]string, 0, len(m))
|
|
||||||
for _, err := range m {
|
|
||||||
msgs = append(msgs, err.Error())
|
|
||||||
}
|
|
||||||
return strings.Join(msgs, "; ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllErrors returns a list of validation violation errors.
|
|
||||||
func (m GetDemoResponseMultiError) AllErrors() []error { return m }
|
|
||||||
|
|
||||||
// GetDemoResponseValidationError is the validation error returned by
|
|
||||||
// GetDemoResponse.Validate if the designated constraints aren't met.
|
|
||||||
type GetDemoResponseValidationError struct {
|
|
||||||
field string
|
|
||||||
reason string
|
|
||||||
cause error
|
|
||||||
key bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Field function returns field value.
|
|
||||||
func (e GetDemoResponseValidationError) Field() string { return e.field }
|
|
||||||
|
|
||||||
// Reason function returns reason value.
|
|
||||||
func (e GetDemoResponseValidationError) Reason() string { return e.reason }
|
|
||||||
|
|
||||||
// Cause function returns cause value.
|
|
||||||
func (e GetDemoResponseValidationError) Cause() error { return e.cause }
|
|
||||||
|
|
||||||
// Key function returns key value.
|
|
||||||
func (e GetDemoResponseValidationError) Key() bool { return e.key }
|
|
||||||
|
|
||||||
// ErrorName returns error name.
|
|
||||||
func (e GetDemoResponseValidationError) ErrorName() string { return "GetDemoResponseValidationError" }
|
|
||||||
|
|
||||||
// Error satisfies the builtin error interface
|
|
||||||
func (e GetDemoResponseValidationError) Error() string {
|
|
||||||
cause := ""
|
|
||||||
if e.cause != nil {
|
|
||||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
|
||||||
}
|
|
||||||
|
|
||||||
key := ""
|
|
||||||
if e.key {
|
|
||||||
key = "key for "
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"invalid %sGetDemoResponse.%s: %s%s",
|
|
||||||
key,
|
|
||||||
e.field,
|
|
||||||
e.reason,
|
|
||||||
cause)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ error = GetDemoResponseValidationError{}
|
|
||||||
|
|
||||||
var _ interface {
|
|
||||||
Field() string
|
|
||||||
Reason() string
|
|
||||||
Key() bool
|
|
||||||
Cause() error
|
|
||||||
ErrorName() string
|
|
||||||
} = GetDemoResponseValidationError{}
|
|
@ -14,10 +14,6 @@ plugins:
|
|||||||
opt:
|
opt:
|
||||||
- paths=source_relative
|
- paths=source_relative
|
||||||
- require_unimplemented_servers=false
|
- require_unimplemented_servers=false
|
||||||
- remote: buf.build/bufbuild/validate-go
|
|
||||||
out: api
|
|
||||||
opt:
|
|
||||||
- paths=source_relative
|
|
||||||
- remote: buf.build/grpc-ecosystem/gateway
|
- remote: buf.build/grpc-ecosystem/gateway
|
||||||
out: api
|
out: api
|
||||||
opt:
|
opt:
|
||||||
|
7
main.go
7
main.go
@ -31,12 +31,15 @@ import (
|
|||||||
const terminationGracePeriod = 30 * time.Second
|
const terminationGracePeriod = 30 * time.Second
|
||||||
|
|
||||||
var (
|
var (
|
||||||
flagSchema bool
|
|
||||||
|
|
||||||
// TODO: Register your service.AppService implementers here
|
// TODO: Register your service.AppService implementers here
|
||||||
|
// This should be the only change necessary here
|
||||||
|
// NOTE: At least one service needs to add a dial option
|
||||||
|
// for transport credentials, otherwise you will have to do it here
|
||||||
appServices = []service.AppService{
|
appServices = []service.AppService{
|
||||||
&demo.DemoService{},
|
&demo.DemoService{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flagSchema bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
package demo.app.v1alpha1;
|
package demo.app.v1alpha1;
|
||||||
|
|
||||||
|
import "buf/validate/validate.proto";
|
||||||
import "google/api/annotations.proto";
|
import "google/api/annotations.proto";
|
||||||
import "google/protobuf/timestamp.proto";
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ option go_package = "gitea.libretechconsulting.com/rmcguire/go-server-with-otel/
|
|||||||
// Options for random fact, in this case
|
// Options for random fact, in this case
|
||||||
// just a language
|
// just a language
|
||||||
message GetDemoRequest {
|
message GetDemoRequest {
|
||||||
optional string language = 1;
|
optional string language = 1 [(buf.validate.field).string.min_len = 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a randome fact, because this is a demo app
|
// Returns a randome fact, because this is a demo app
|
||||||
@ -18,7 +19,7 @@ message GetDemoResponse {
|
|||||||
google.protobuf.Timestamp timestamp = 1;
|
google.protobuf.Timestamp timestamp = 1;
|
||||||
string fact = 2;
|
string fact = 2;
|
||||||
string source = 3;
|
string source = 3;
|
||||||
string language = 4;
|
string language = 4 [(buf.validate.field).string.min_len = 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
service DemoAppService {
|
service DemoAppService {
|
||||||
|
Reference in New Issue
Block a user