From 9136c98aa4a75004acf85a20df274138b38d6bcd Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Wed, 13 Nov 2024 18:56:48 +0000 Subject: [PATCH 1/5] (proto) drop google.api.http annotations --- proto/ruek/api/v1/authz.proto | 24 +++---------------- proto/ruek/api/v1/entities.proto | 14 ++--------- proto/ruek/api/v1/principals.proto | 38 ++++-------------------------- proto/ruek/api/v1/relations.proto | 38 ++++-------------------------- 4 files changed, 15 insertions(+), 99 deletions(-) diff --git a/proto/ruek/api/v1/authz.proto b/proto/ruek/api/v1/authz.proto index bc84ee0..0f09717 100644 --- a/proto/ruek/api/v1/authz.proto +++ b/proto/ruek/api/v1/authz.proto @@ -3,29 +3,11 @@ syntax = "proto3"; package ruek.api.v1; import "google/protobuf/struct.proto"; -import "google/api/annotations.proto"; service Authz { - rpc Check(AuthzCheckRequest) returns (AuthzCheckResponse) { - option (google.api.http) = { - post : "/v1/authz:check" - body : "*" - }; - } - - rpc Grant(AuthzGrantRequest) returns (AuthzGrantResponse) { - option (google.api.http) = { - put : "/v1/authz:grant" - body : "*" - }; - } - - rpc Revoke(AuthzRevokeRequest) returns (AuthzRevokeResponse) { - option (google.api.http) = { - put : "/v1/authz:revoke" - body : "*" - }; - } + rpc Check(AuthzCheckRequest) returns (AuthzCheckResponse); + rpc Grant(AuthzGrantRequest) returns (AuthzGrantResponse); + rpc Revoke(AuthzRevokeRequest) returns (AuthzRevokeResponse); } message AuthzCheckRequest { diff --git a/proto/ruek/api/v1/entities.proto b/proto/ruek/api/v1/entities.proto index 6dfbf90..1ecdf8a 100644 --- a/proto/ruek/api/v1/entities.proto +++ b/proto/ruek/api/v1/entities.proto @@ -2,21 +2,11 @@ syntax = "proto3"; package ruek.api.v1; -import "google/api/annotations.proto"; import "google/protobuf/struct.proto"; service Entities { - rpc List(EntitiesListRequest) returns (EntitiesListResponse) { - option (google.api.http) = { - get : "/v1/entities" - }; - } - - rpc ListPrincipals(EntitiesListPrincipalsRequest) returns (EntitiesListPrincipalsResponse) { - option (google.api.http) = { - get : "/v1/entities:principals" - }; - } + rpc List(EntitiesListRequest) returns (EntitiesListResponse); + rpc ListPrincipals(EntitiesListPrincipalsRequest) returns (EntitiesListPrincipalsResponse); } message EntitiesEntity { diff --git a/proto/ruek/api/v1/principals.proto b/proto/ruek/api/v1/principals.proto index 449befb..8f98b2d 100644 --- a/proto/ruek/api/v1/principals.proto +++ b/proto/ruek/api/v1/principals.proto @@ -2,42 +2,14 @@ syntax = "proto3"; package ruek.api.v1; -import "google/api/annotations.proto"; import "google/protobuf/struct.proto"; service Principals { - rpc Create(PrincipalsCreateRequest) returns (Principal) { - option (google.api.http) = { - post : "/v1/principals" - body : "*" - }; - } - - rpc Delete(PrincipalsDeleteRequest) returns (PrincipalsDeleteResponse) { - option (google.api.http) = { - delete : "/v1/principals/{id}" - body : "*" - }; - } - - rpc List(PrincipalsListRequest) returns (PrincipalsListResponse) { - option (google.api.http) = { - get : "/v1/principals?segment={segment}&_limit={pagination_limit}&_start={pagination_token}" - }; - } - - rpc Retrieve(PrincipalsRetrieveRequest) returns (Principal) { - option (google.api.http) = { - get : "/v1/principals/{id}" - }; - } - - rpc Update(PrincipalsUpdateRequest) returns (Principal) { - option (google.api.http) = { - put : "/v1/principals/{id}" - body : "*" - }; - } + rpc Create(PrincipalsCreateRequest) returns (Principal); + rpc Delete(PrincipalsDeleteRequest) returns (PrincipalsDeleteResponse); + rpc List(PrincipalsListRequest) returns (PrincipalsListResponse); + rpc Retrieve(PrincipalsRetrieveRequest) returns (Principal); + rpc Update(PrincipalsUpdateRequest) returns (Principal); } message Principal { diff --git a/proto/ruek/api/v1/relations.proto b/proto/ruek/api/v1/relations.proto index 07d0760..6b9c41e 100644 --- a/proto/ruek/api/v1/relations.proto +++ b/proto/ruek/api/v1/relations.proto @@ -3,41 +3,13 @@ syntax = "proto3"; package ruek.api.v1; import "google/protobuf/struct.proto"; -import "google/api/annotations.proto"; service Relations { - rpc Check(RelationsCheckRequest) returns (RelationsCheckResponse) { - option (google.api.http) = { - post : "/v1/relations:check" - body : "*" - }; - } - - rpc Create(RelationsCreateRequest) returns (RelationsCreateResponse) { - option (google.api.http) = { - post : "/v1/relations" - body : "*" - }; - } - - rpc Delete(RelationsDeleteRequest) returns (RelationsDeleteResponse) { - option (google.api.http) = { - post : "/v1/relations:delete" - body : "*" - }; - } - - rpc ListLeft(RelationsListLeftRequest) returns (RelationsListLeftResponse) { - option (google.api.http) = { - get : "/v1/relations:left?_limit={pagination_limit}&_start={pagination_token}" - }; - } - - rpc ListRight(RelationsListRightRequest) returns (RelationsListRightResponse) { - option (google.api.http) = { - get : "/v1/relations:right?_limit={pagination_limit}&_start={pagination_token}" - }; - } + rpc Check(RelationsCheckRequest) returns (RelationsCheckResponse); + rpc Create(RelationsCreateRequest) returns (RelationsCreateResponse); + rpc Delete(RelationsDeleteRequest) returns (RelationsDeleteResponse); + rpc ListLeft(RelationsListLeftRequest) returns (RelationsListLeftResponse); + rpc ListRight(RelationsListRightRequest) returns (RelationsListRightResponse); } message Entity { From ae4da63908c7a20599683fdca657472ad95d902c Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Wed, 13 Nov 2024 19:20:23 +0000 Subject: [PATCH 2/5] (proto) copy required google.rpc types ref: https://github.com/googleapis/googleapis/tree/2d05911be5a468b556236bee537c91922f9c23a3/google/rpc --- proto/google/.clang-format | 1 + proto/google/rpc/code.proto | 186 ++++++++++++++++++++++++++++++++++ proto/google/rpc/status.proto | 49 +++++++++ 3 files changed, 236 insertions(+) create mode 100644 proto/google/.clang-format create mode 100644 proto/google/rpc/code.proto create mode 100644 proto/google/rpc/status.proto diff --git a/proto/google/.clang-format b/proto/google/.clang-format new file mode 100644 index 0000000..e384528 --- /dev/null +++ b/proto/google/.clang-format @@ -0,0 +1 @@ +DisableFormat: true diff --git a/proto/google/rpc/code.proto b/proto/google/rpc/code.proto new file mode 100644 index 0000000..ba8f2bf --- /dev/null +++ b/proto/google/rpc/code.proto @@ -0,0 +1,186 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.rpc; + +option go_package = "google.golang.org/genproto/googleapis/rpc/code;code"; +option java_multiple_files = true; +option java_outer_classname = "CodeProto"; +option java_package = "com.google.rpc"; +option objc_class_prefix = "RPC"; + +// The canonical error codes for gRPC APIs. +// +// +// Sometimes multiple error codes may apply. Services should return +// the most specific error code that applies. For example, prefer +// `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply. +// Similarly prefer `NOT_FOUND` or `ALREADY_EXISTS` over `FAILED_PRECONDITION`. +enum Code { + // Not an error; returned on success. + // + // HTTP Mapping: 200 OK + OK = 0; + + // The operation was cancelled, typically by the caller. + // + // HTTP Mapping: 499 Client Closed Request + CANCELLED = 1; + + // Unknown error. For example, this error may be returned when + // a `Status` value received from another address space belongs to + // an error space that is not known in this address space. Also + // errors raised by APIs that do not return enough error information + // may be converted to this error. + // + // HTTP Mapping: 500 Internal Server Error + UNKNOWN = 2; + + // The client specified an invalid argument. Note that this differs + // from `FAILED_PRECONDITION`. `INVALID_ARGUMENT` indicates arguments + // that are problematic regardless of the state of the system + // (e.g., a malformed file name). + // + // HTTP Mapping: 400 Bad Request + INVALID_ARGUMENT = 3; + + // The deadline expired before the operation could complete. For operations + // that change the state of the system, this error may be returned + // even if the operation has completed successfully. For example, a + // successful response from a server could have been delayed long + // enough for the deadline to expire. + // + // HTTP Mapping: 504 Gateway Timeout + DEADLINE_EXCEEDED = 4; + + // Some requested entity (e.g., file or directory) was not found. + // + // Note to server developers: if a request is denied for an entire class + // of users, such as gradual feature rollout or undocumented allowlist, + // `NOT_FOUND` may be used. If a request is denied for some users within + // a class of users, such as user-based access control, `PERMISSION_DENIED` + // must be used. + // + // HTTP Mapping: 404 Not Found + NOT_FOUND = 5; + + // The entity that a client attempted to create (e.g., file or directory) + // already exists. + // + // HTTP Mapping: 409 Conflict + ALREADY_EXISTS = 6; + + // The caller does not have permission to execute the specified + // operation. `PERMISSION_DENIED` must not be used for rejections + // caused by exhausting some resource (use `RESOURCE_EXHAUSTED` + // instead for those errors). `PERMISSION_DENIED` must not be + // used if the caller can not be identified (use `UNAUTHENTICATED` + // instead for those errors). This error code does not imply the + // request is valid or the requested entity exists or satisfies + // other pre-conditions. + // + // HTTP Mapping: 403 Forbidden + PERMISSION_DENIED = 7; + + // The request does not have valid authentication credentials for the + // operation. + // + // HTTP Mapping: 401 Unauthorized + UNAUTHENTICATED = 16; + + // Some resource has been exhausted, perhaps a per-user quota, or + // perhaps the entire file system is out of space. + // + // HTTP Mapping: 429 Too Many Requests + RESOURCE_EXHAUSTED = 8; + + // The operation was rejected because the system is not in a state + // required for the operation's execution. For example, the directory + // to be deleted is non-empty, an rmdir operation is applied to + // a non-directory, etc. + // + // Service implementors can use the following guidelines to decide + // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`: + // (a) Use `UNAVAILABLE` if the client can retry just the failing call. + // (b) Use `ABORTED` if the client should retry at a higher level. For + // example, when a client-specified test-and-set fails, indicating the + // client should restart a read-modify-write sequence. + // (c) Use `FAILED_PRECONDITION` if the client should not retry until + // the system state has been explicitly fixed. For example, if an "rmdir" + // fails because the directory is non-empty, `FAILED_PRECONDITION` + // should be returned since the client should not retry unless + // the files are deleted from the directory. + // + // HTTP Mapping: 400 Bad Request + FAILED_PRECONDITION = 9; + + // The operation was aborted, typically due to a concurrency issue such as + // a sequencer check failure or transaction abort. + // + // See the guidelines above for deciding between `FAILED_PRECONDITION`, + // `ABORTED`, and `UNAVAILABLE`. + // + // HTTP Mapping: 409 Conflict + ABORTED = 10; + + // The operation was attempted past the valid range. E.g., seeking or + // reading past end-of-file. + // + // Unlike `INVALID_ARGUMENT`, this error indicates a problem that may + // be fixed if the system state changes. For example, a 32-bit file + // system will generate `INVALID_ARGUMENT` if asked to read at an + // offset that is not in the range [0,2^32-1], but it will generate + // `OUT_OF_RANGE` if asked to read from an offset past the current + // file size. + // + // There is a fair bit of overlap between `FAILED_PRECONDITION` and + // `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific + // error) when it applies so that callers who are iterating through + // a space can easily look for an `OUT_OF_RANGE` error to detect when + // they are done. + // + // HTTP Mapping: 400 Bad Request + OUT_OF_RANGE = 11; + + // The operation is not implemented or is not supported/enabled in this + // service. + // + // HTTP Mapping: 501 Not Implemented + UNIMPLEMENTED = 12; + + // Internal errors. This means that some invariants expected by the + // underlying system have been broken. This error code is reserved + // for serious errors. + // + // HTTP Mapping: 500 Internal Server Error + INTERNAL = 13; + + // The service is currently unavailable. This is most likely a + // transient condition, which can be corrected by retrying with + // a backoff. Note that it is not always safe to retry + // non-idempotent operations. + // + // See the guidelines above for deciding between `FAILED_PRECONDITION`, + // `ABORTED`, and `UNAVAILABLE`. + // + // HTTP Mapping: 503 Service Unavailable + UNAVAILABLE = 14; + + // Unrecoverable data loss or corruption. + // + // HTTP Mapping: 500 Internal Server Error + DATA_LOSS = 15; +} diff --git a/proto/google/rpc/status.proto b/proto/google/rpc/status.proto new file mode 100644 index 0000000..90b70dd --- /dev/null +++ b/proto/google/rpc/status.proto @@ -0,0 +1,49 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.rpc; + +import "google/protobuf/any.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/rpc/status;status"; +option java_multiple_files = true; +option java_outer_classname = "StatusProto"; +option java_package = "com.google.rpc"; +option objc_class_prefix = "RPC"; + +// The `Status` type defines a logical error model that is suitable for +// different programming environments, including REST APIs and RPC APIs. It is +// used by [gRPC](https://github.com/grpc). Each `Status` message contains +// three pieces of data: error code, error message, and error details. +// +// You can find out more about this error model and how to work with it in the +// [API Design Guide](https://cloud.google.com/apis/design/errors). +message Status { + // The status code, which should be an enum value of + // [google.rpc.Code][google.rpc.Code]. + int32 code = 1; + + // A developer-facing error message, which should be in English. Any + // user-facing error message should be localized and sent in the + // [google.rpc.Status.details][google.rpc.Status.details] field, or localized + // by the client. + string message = 2; + + // A list of messages that carry the error details. There is a common set of + // message types for APIs to use. + repeated google.protobuf.Any details = 3; +} From 9f26711a6e61e5cfcd7629bb2f6f5bbd4a329e2b Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Wed, 13 Nov 2024 19:23:11 +0000 Subject: [PATCH 3/5] (cmake) drop googleapis as a dependency --- CMakeLists.txt | 1 - cmake/dependencies.cmake | 7 ----- cmake/googleapis.cmake | 56 ---------------------------------------- proto/CMakeLists.txt | 41 +++++++++++++++++++++++++++-- 4 files changed, 39 insertions(+), 66 deletions(-) delete mode 100644 cmake/googleapis.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 95ccac3..fd83aec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,6 @@ if (RUEK_ENABLE_COVERAGE) endif() include(cmake/dependencies.cmake) -include(cmake/googleapis.cmake) if (RUEK_BUILD_TESTING) enable_testing() diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 829952a..b6e357f 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -10,13 +10,6 @@ FetchContent_Declare(fmt ) FetchContent_MakeAvailable(fmt) -# googleapis -FetchContent_Declare(googleapis - URL https://github.com/googleapis/googleapis/archive/0e3b813b0d0da539eacbe86b8716feeed00943c5.tar.gz - URL_HASH SHA256=44f3b9c73a5df760c4fad3cf0c5cc54732b881f00708308f7635ff75a13dcaa5 -) -FetchContent_MakeAvailable(googleapis) - # grpcxx FetchContent_Declare(grpcxx URL https://github.com/uatuko/grpcxx/archive/refs/tags/v0.2.0.tar.gz diff --git a/cmake/googleapis.cmake b/cmake/googleapis.cmake deleted file mode 100644 index 0198e7e..0000000 --- a/cmake/googleapis.cmake +++ /dev/null @@ -1,56 +0,0 @@ -cmake_path(SET googleapis_annotations_proto ${googleapis_SOURCE_DIR}/google/api/annotations.proto) -cmake_path(SET googleapis_annotations_header ${CMAKE_CURRENT_BINARY_DIR}/google/api/annotations.pb.h) -cmake_path(SET googleapis_annotations_source ${CMAKE_CURRENT_BINARY_DIR}/google/api/annotations.pb.cc) - -cmake_path(SET googleapis_http_proto ${googleapis_SOURCE_DIR}/google/api/http.proto) -cmake_path(SET googleapis_http_header ${CMAKE_CURRENT_BINARY_DIR}/google/api/http.pb.h) -cmake_path(SET googleapis_http_source ${CMAKE_CURRENT_BINARY_DIR}/google/api/http.pb.cc) - -cmake_path(SET googleapis_rpc_code_proto ${googleapis_SOURCE_DIR}/google/rpc/code.proto) -cmake_path(SET googleapis_rpc_code_header ${CMAKE_CURRENT_BINARY_DIR}/google/rpc/code.pb.h) -cmake_path(SET googleapis_rpc_code_source ${CMAKE_CURRENT_BINARY_DIR}/google/rpc/code.pb.cc) - -cmake_path(SET googleapis_rpc_status_proto ${googleapis_SOURCE_DIR}/google/rpc/status.proto) -cmake_path(SET googleapis_rpc_status_header ${CMAKE_CURRENT_BINARY_DIR}/google/rpc/status.pb.h) -cmake_path(SET googleapis_rpc_status_source ${CMAKE_CURRENT_BINARY_DIR}/google/rpc/status.pb.cc) - -set(googleapis_protos - ${googleapis_annotations_proto} - ${googleapis_http_proto} - ${googleapis_rpc_code_proto} - ${googleapis_rpc_status_proto} -) - -set(googleapis_headers - ${googleapis_annotations_header} - ${googleapis_http_header} - ${googleapis_rpc_code_header} - ${googleapis_rpc_status_header} -) - -set(googleapis_sources - ${googleapis_annotations_source} - ${googleapis_http_source} - ${googleapis_rpc_code_source} - ${googleapis_rpc_status_source} -) - -add_custom_command( - OUTPUT ${googleapis_headers} ${googleapis_sources} - DEPENDS ${googleapis_protos} - COMMAND ${Protobuf_PROTOC_EXECUTABLE} - ARGS - --proto_path=${googleapis_SOURCE_DIR} - --proto_path=${Protobuf_INCLUDE_DIR} - --cpp_out=${CMAKE_CURRENT_BINARY_DIR} - ${googleapis_protos} -) - -add_library(googleapis - ${googleapis_sources} -) - -target_include_directories(googleapis - PUBLIC ${CMAKE_CURRENT_BINARY_DIR} - PRIVATE ${Protobuf_INCLUDE_DIR} -) diff --git a/proto/CMakeLists.txt b/proto/CMakeLists.txt index 5b3902b..9747da0 100644 --- a/proto/CMakeLists.txt +++ b/proto/CMakeLists.txt @@ -1,3 +1,4 @@ +# ruek/api/v1/**/*.proto cmake_path(SET authz_proto ${CMAKE_CURRENT_SOURCE_DIR}/ruek/api/v1/authz.proto) cmake_path(SET authz_grpcxx_header ${CMAKE_CURRENT_BINARY_DIR}/ruek/api/v1/authz.grpcxx.pb.h) cmake_path(SET authz_header ${CMAKE_CURRENT_BINARY_DIR}/ruek/api/v1/authz.pb.h) @@ -45,7 +46,6 @@ add_custom_command( COMMAND ${Protobuf_PROTOC_EXECUTABLE} ARGS --proto_path=${CMAKE_CURRENT_SOURCE_DIR} - --proto_path=${googleapis_SOURCE_DIR} --proto_path=${Protobuf_INCLUDE_DIR} --cpp_out=${CMAKE_CURRENT_BINARY_DIR} --grpcxx_out=${CMAKE_CURRENT_BINARY_DIR} @@ -54,6 +54,7 @@ add_custom_command( ) +# ruek/detail/**/*.proto cmake_path(SET detail_pagination_proto ${CMAKE_CURRENT_SOURCE_DIR}/ruek/detail/pagination.proto) cmake_path(SET detail_pagination_header ${CMAKE_CURRENT_BINARY_DIR}/ruek/detail/pagination.pb.h) cmake_path(SET detail_pagination_source ${CMAKE_CURRENT_BINARY_DIR}/ruek/detail/pagination.pb.cc) @@ -82,9 +83,46 @@ add_custom_command( ) +# google/rpc/**/*.proto +cmake_path(SET google_rpc_code_proto ${CMAKE_CURRENT_SOURCE_DIR}/google/rpc/code.proto) +cmake_path(SET google_rpc_code_header ${CMAKE_CURRENT_BINARY_DIR}/google/rpc/code.pb.h) +cmake_path(SET google_rpc_code_source ${CMAKE_CURRENT_BINARY_DIR}/google/rpc/code.pb.cc) + +cmake_path(SET google_rpc_status_proto ${CMAKE_CURRENT_SOURCE_DIR}/google/rpc/status.proto) +cmake_path(SET google_rpc_status_header ${CMAKE_CURRENT_BINARY_DIR}/google/rpc/status.pb.h) +cmake_path(SET google_rpc_status_source ${CMAKE_CURRENT_BINARY_DIR}/google/rpc/status.pb.cc) + +set(google_protos + ${google_rpc_code_proto} + ${google_rpc_status_proto} +) + +set(google_headers + ${google_rpc_code_header} + ${google_rpc_status_header} +) + +set(google_sources + ${google_rpc_code_source} + ${google_rpc_status_source} +) + +add_custom_command( + OUTPUT ${google_headers} ${google_sources} + DEPENDS ${google_protos} + COMMAND ${Protobuf_PROTOC_EXECUTABLE} + ARGS + --proto_path=${CMAKE_CURRENT_SOURCE_DIR} + --proto_path=${Protobuf_INCLUDE_DIR} + --cpp_out=${CMAKE_CURRENT_BINARY_DIR} + ${google_protos} +) + + add_library(proto ${sources} ${detail_sources} + ${google_sources} ) target_include_directories(proto @@ -92,7 +130,6 @@ target_include_directories(proto ) target_link_libraries(proto - googleapis libgrpcxx::grpcxx protobuf::libprotobuf ) From b893e20b91fbdcb630408faa268599e5450cbe23 Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Wed, 13 Nov 2024 19:24:06 +0000 Subject: [PATCH 4/5] (docs) update docs --- README.md | 1 - docs/api/v1/principals.md | 35 +++++------------------------------ docs/api/v1/relations.md | 33 +++++---------------------------- 3 files changed, 10 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index a757d2b..f9c20a4 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,6 @@ docker run --network=ruek-net --name=ruek -e PGHOST=pg -e PGUSER=ruek -e PGPASSW ## Built with * [fmt](https://github.com/fmtlib/fmt) - For string formatting. -* [googleapis](https://github.com/googleapis/googleapis) - For annotations to help with gRPC/JSON transcoding. * [googletest](https://github.com/google/googletest) - For tests. * [benchmark](https://github.com/google/benchmark) - For benchmarks. * [grpcxx](https://github.com/uatuko/grpcxx) - For the gRPC server. diff --git a/docs/api/v1/principals.md b/docs/api/v1/principals.md index 82e8636..a599a32 100644 --- a/docs/api/v1/principals.md +++ b/docs/api/v1/principals.md @@ -40,12 +40,7 @@ service Principals {} Create a new principal. ```proto -rpc Create(PrincipalsCreateRequest) returns (Principal) { - option (google.api.http) = { - post : "/v1/principals" - body : "*" - }; -} +rpc Create(PrincipalsCreateRequest) returns (Principal); ``` ### Request message @@ -61,7 +56,6 @@ rpc Create(PrincipalsCreateRequest) returns (Principal) { ``` ❯ grpcurl \ -import-path proto \ - -import-path ./.build/_deps/googleapis-src \ -proto proto/ruek/api/v1/principals.proto \ -plaintext \ localhost:8080 ruek.api.v1.Principals/Create @@ -77,12 +71,7 @@ rpc Create(PrincipalsCreateRequest) returns (Principal) { Delete an existing principal. ```proto -rpc Delete(PrincipalsDeleteRequest) returns (PrincipalsDeleteResponse) { - option (google.api.http) = { - delete : "/v1/principals/{id}" - body : "*" - }; -} +rpc Delete(PrincipalsDeleteRequest) returns (PrincipalsDeleteResponse); ``` ### Request message @@ -99,11 +88,7 @@ rpc Delete(PrincipalsDeleteRequest) returns (PrincipalsDeleteResponse) { List principals. ```proto -rpc List(PrincipalsListRequest) returns (PrincipalsListResponse) { - option (google.api.http) = { - get : "/v1/principals?segment={segment}&_limit={pagination_limit}&_start={pagination_token}" - }; -} +rpc List(PrincipalsListRequest) returns (PrincipalsListResponse); ``` ### Request message @@ -119,7 +104,6 @@ rpc List(PrincipalsListRequest) returns (PrincipalsListResponse) { ``` ❯ grpcurl \ -import-path proto \ - -import-path ./.build/_deps/googleapis-src \ -proto proto/ruek/api/v1/principals.proto \ -plaintext \ localhost:8080 ruek.api.v1.Principals/List @@ -142,11 +126,7 @@ rpc List(PrincipalsListRequest) returns (PrincipalsListResponse) { Retrieve a principal. ```proto -rpc Retrieve(PrincipalsRetrieveRequest) returns (Principal) { - option (google.api.http) = { - get : "/v1/principals/{id}" - }; -} +rpc Retrieve(PrincipalsRetrieveRequest) returns (Principal); ``` ### Request message @@ -163,12 +143,7 @@ rpc Retrieve(PrincipalsRetrieveRequest) returns (Principal) { Update a principal. ```proto - rpc Update(PrincipalsUpdateRequest) returns (Principal) { - option (google.api.http) = { - put : "/v1/principals/{id}" - body : "*" - }; - } +rpc Update(PrincipalsUpdateRequest) returns (Principal); ``` ### Request message diff --git a/docs/api/v1/relations.md b/docs/api/v1/relations.md index bc39e93..963bf79 100644 --- a/docs/api/v1/relations.md +++ b/docs/api/v1/relations.md @@ -45,12 +45,7 @@ service Relations {} Check if a relation exists. ```proto -rpc Check(RelationsCheckRequest) returns (RelationsCheckResponse) { - option (google.api.http) = { - post : "/v1/relations:check" - body : "*" - }; -} +rpc Check(RelationsCheckRequest) returns (RelationsCheckResponse); ``` ### Request message @@ -67,12 +62,7 @@ rpc Check(RelationsCheckRequest) returns (RelationsCheckResponse) { Create a new relation. ```proto -rpc Create(RelationsCreateRequest) returns (RelationsCreateResponse) { - option (google.api.http) = { - post : "/v1/relations" - body : "*" - }; -} +rpc Create(RelationsCreateRequest) returns (RelationsCreateResponse); ``` ### Request message @@ -89,12 +79,7 @@ rpc Create(RelationsCreateRequest) returns (RelationsCreateResponse) { Delete an existing relation. ```proto -rpc Delete(RelationsDeleteRequest) returns (RelationsDeleteResponse) { - option (google.api.http) = { - post : "/v1/relations:delete" - body : "*" - }; -} +rpc Delete(RelationsDeleteRequest) returns (RelationsDeleteResponse); ``` ### Request message @@ -111,11 +96,7 @@ rpc Delete(RelationsDeleteRequest) returns (RelationsDeleteResponse) { List relations to the left of a relation. ```proto -rpc ListLeft(RelationsListLeftRequest) returns (RelationsListLeftResponse) { - option (google.api.http) = { - get : "/v1/relations:left?_limit={pagination_limit}&_start={pagination_token}" - }; -} +rpc ListLeft(RelationsListLeftRequest) returns (RelationsListLeftResponse); ``` ### Request message @@ -132,11 +113,7 @@ rpc ListLeft(RelationsListLeftRequest) returns (RelationsListLeftResponse) { List relations to the right of a relation. ```proto -rpc ListRight(RelationsListRightRequest) returns (RelationsListRightResponse) { - option (google.api.http) = { - get : "/v1/relations:right?_limit={pagination_limit}&_start={pagination_token}" - }; -} +rpc ListRight(RelationsListRightRequest) returns (RelationsListRightResponse); ``` ### Request message From 29331e315896dd0778fed236c63eb309aa35d844 Mon Sep 17 00:00:00 2001 From: Uditha Atukorala Date: Wed, 13 Nov 2024 21:20:05 +0000 Subject: [PATCH 5/5] (proto) avoid sharing top-level request/response messages across rpcs --- proto/ruek/api/v1/principals.proto | 18 +++++++++++--- src/svc/principals.cpp | 35 ++++++++++++++++----------- src/svc/principals.h | 11 ++++++++- src/svc/principals_test.cpp | 39 +++++++++++++++++++----------- 4 files changed, 71 insertions(+), 32 deletions(-) diff --git a/proto/ruek/api/v1/principals.proto b/proto/ruek/api/v1/principals.proto index 8f98b2d..e7ba893 100644 --- a/proto/ruek/api/v1/principals.proto +++ b/proto/ruek/api/v1/principals.proto @@ -5,11 +5,11 @@ package ruek.api.v1; import "google/protobuf/struct.proto"; service Principals { - rpc Create(PrincipalsCreateRequest) returns (Principal); + rpc Create(PrincipalsCreateRequest) returns (PrincipalsCreateResponse); rpc Delete(PrincipalsDeleteRequest) returns (PrincipalsDeleteResponse); rpc List(PrincipalsListRequest) returns (PrincipalsListResponse); - rpc Retrieve(PrincipalsRetrieveRequest) returns (Principal); - rpc Update(PrincipalsUpdateRequest) returns (Principal); + rpc Retrieve(PrincipalsRetrieveRequest) returns (PrincipalsRetrieveResponse); + rpc Update(PrincipalsUpdateRequest) returns (PrincipalsUpdateResponse); } message Principal { @@ -26,6 +26,10 @@ message PrincipalsCreateRequest { optional string segment = 3; } +message PrincipalsCreateResponse { + Principal principal = 1; +} + message PrincipalsDeleteRequest { string id = 1; } @@ -49,9 +53,17 @@ message PrincipalsRetrieveRequest { string id = 1; } +message PrincipalsRetrieveResponse { + Principal principal = 1; +} + message PrincipalsUpdateRequest { string id = 1; optional google.protobuf.Struct attrs = 2; optional string segment = 3; } + +message PrincipalsUpdateResponse { + Principal principal = 1; +} diff --git a/src/svc/principals.cpp b/src/svc/principals.cpp index 0574985..01d0d86 100644 --- a/src/svc/principals.cpp +++ b/src/svc/principals.cpp @@ -27,7 +27,7 @@ rpcCreate::result_type Impl::call( auto p = map(ctx, req); p.store(); - return {grpcxx::status::code_t::ok, map(p)}; + return {grpcxx::status::code_t::ok, map(p)}; } template <> @@ -78,7 +78,7 @@ template <> rpcRetrieve::result_type Impl::call( grpcxx::context &ctx, const rpcRetrieve::request_type &req) { auto p = db::Principal::retrieve(ctx.meta(common::space_id_v), req.id()); - return {grpcxx::status::code_t::ok, map(p)}; + return {grpcxx::status::code_t::ok, map(p)}; } template <> @@ -87,7 +87,7 @@ rpcUpdate::result_type Impl::call( auto p = db::Principal::retrieve(ctx.meta(common::space_id_v), req.id()); if (!req.has_attrs() && !req.has_segment()) { // Nothing to update - return {grpcxx::status::code_t::ok, map(p)}; + return {grpcxx::status::code_t::ok, map(p)}; } if (req.has_attrs()) { @@ -102,7 +102,7 @@ rpcUpdate::result_type Impl::call( } p.store(); - return {grpcxx::status::code_t::ok, map(p)}; + return {grpcxx::status::code_t::ok, map(p)}; } google::rpc::Status Impl::exception() noexcept { @@ -155,8 +155,20 @@ db::Principal Impl::map( return to; } -rpcCreate::response_type Impl::map(const db::Principal &from) const noexcept { - rpcCreate::response_type to; +rpcList::response_type Impl::map(const db::Principals &from) const noexcept { + rpcList::response_type to; + + auto *arr = to.mutable_principals(); + arr->Reserve(from.size()); + for (const auto &p : from) { + arr->Add(map(p)); + } + + return to; +} + +ruek::api::v1::Principal Impl::map(const db::Principal &from) const noexcept { + ruek::api::v1::Principal to; to.set_id(from.id()); if (from.attrs()) { @@ -170,14 +182,9 @@ rpcCreate::response_type Impl::map(const db::Principal &from) const noexcept { return to; } -rpcList::response_type Impl::map(const db::Principals &from) const noexcept { - rpcList::response_type to; - - auto *arr = to.mutable_principals(); - arr->Reserve(from.size()); - for (const auto &p : from) { - arr->Add(map(p)); - } +template T Impl::map(const db::Principal &from) const noexcept { + T to; + *to.mutable_principal() = map(from); return to; } diff --git a/src/svc/principals.h b/src/svc/principals.h index 5edd5e1..9929e21 100644 --- a/src/svc/principals.h +++ b/src/svc/principals.h @@ -7,6 +7,13 @@ namespace svc { namespace principals { +namespace concepts { +template +concept has_mutable_principal = requires(T t) { + { t.mutable_principal() } -> std::same_as; +}; +} + using namespace ruek::api::v1::Principals; class Impl { @@ -24,8 +31,10 @@ class Impl { db::Principal map( const grpcxx::context &ctx, const rpcCreate::request_type &from) const noexcept; - rpcCreate::response_type map(const db::Principal &from) const noexcept; rpcList::response_type map(const db::Principals &from) const noexcept; + ruek::api::v1::Principal map(const db::Principal &from) const noexcept; + + template T map(const db::Principal &from) const noexcept; }; template <> diff --git a/src/svc/principals_test.cpp b/src/svc/principals_test.cpp index cc89e98..e9904ee 100644 --- a/src/svc/principals_test.cpp +++ b/src/svc/principals_test.cpp @@ -34,7 +34,8 @@ TEST_F(svc_PrincipalsTest, Create) { EXPECT_EQ(grpcxx::status::code_t::ok, result.status.code()); ASSERT_TRUE(result.response); - EXPECT_FALSE(result.response->id().empty()); + ASSERT_TRUE(result.response->has_principal()); + EXPECT_FALSE(result.response->principal().id().empty()); } // Success: create principal with `id` @@ -47,7 +48,8 @@ TEST_F(svc_PrincipalsTest, Create) { EXPECT_EQ(grpcxx::status::code_t::ok, result.status.code()); ASSERT_TRUE(result.response); - EXPECT_EQ(request.id(), result.response->id()); + ASSERT_TRUE(result.response->has_principal()); + EXPECT_EQ(request.id(), result.response->principal().id()); } // Success: create principal with `attrs` @@ -62,9 +64,11 @@ TEST_F(svc_PrincipalsTest, Create) { EXPECT_EQ(grpcxx::status::code_t::ok, result.status.code()); ASSERT_TRUE(result.response); + ASSERT_TRUE(result.response->has_principal()); std::string responseAttrs; - google::protobuf::util::MessageToJsonString(result.response->attrs(), &responseAttrs); + google::protobuf::util::MessageToJsonString( + result.response->principal().attrs(), &responseAttrs); EXPECT_EQ(attrs, responseAttrs); } @@ -78,7 +82,10 @@ TEST_F(svc_PrincipalsTest, Create) { EXPECT_EQ(grpcxx::status::code_t::ok, result.status.code()); ASSERT_TRUE(result.response); - EXPECT_EQ("segment:svc_PrincipalsTest.Create-with_segment", result.response->segment()); + ASSERT_TRUE(result.response->has_principal()); + EXPECT_EQ( + "segment:svc_PrincipalsTest.Create-with_segment", + result.response->principal().segment()); } // Success: create principal with space-id @@ -96,9 +103,10 @@ TEST_F(svc_PrincipalsTest, Create) { EXPECT_EQ(grpcxx::status::code_t::ok, result.status.code()); ASSERT_TRUE(result.response); + ASSERT_TRUE(result.response->has_principal()); ASSERT_NO_THROW(db::Principal::retrieve( - "space_id:svc_PrincipalsTest.Create-with_space_id", result.response->id())); + "space_id:svc_PrincipalsTest.Create-with_space_id", result.response->principal().id())); } // Error: invalid `segment` @@ -363,8 +371,9 @@ TEST_F(svc_PrincipalsTest, Retrieve) { EXPECT_NO_THROW(result = svc.call(ctx, request)); EXPECT_EQ(grpcxx::status::code_t::ok, result.status.code()); ASSERT_TRUE(result.response); + ASSERT_TRUE(result.response->has_principal()); - auto &actual = result.response.value(); + auto &actual = result.response->principal(); EXPECT_EQ(principal.id(), actual.id()); EXPECT_FALSE(actual.has_attrs()); EXPECT_FALSE(actual.has_segment()); @@ -390,8 +399,9 @@ TEST_F(svc_PrincipalsTest, Retrieve) { EXPECT_NO_THROW(result = svc.call(ctx, request)); EXPECT_EQ(grpcxx::status::code_t::ok, result.status.code()); ASSERT_TRUE(result.response); + ASSERT_TRUE(result.response->has_principal()); - auto &actual = result.response.value(); + auto &actual = result.response->principal(); EXPECT_EQ(principal.id(), actual.id()); EXPECT_FALSE(actual.has_attrs()); EXPECT_FALSE(actual.has_segment()); @@ -412,14 +422,15 @@ TEST_F(svc_PrincipalsTest, Retrieve) { EXPECT_NO_THROW(result = svc.call(ctx, request)); EXPECT_EQ(grpcxx::status::code_t::ok, result.status.code()); ASSERT_TRUE(result.response); + ASSERT_TRUE(result.response->has_principal()); - auto &actual = result.response.value(); + auto &actual = result.response->principal(); EXPECT_EQ(principal.id(), actual.id()); EXPECT_TRUE(actual.has_attrs()); EXPECT_FALSE(actual.has_segment()); std::string responseAttrs; - google::protobuf::util::MessageToJsonString(result.response->attrs(), &responseAttrs); + google::protobuf::util::MessageToJsonString(actual.attrs(), &responseAttrs); EXPECT_EQ(principal.attrs(), responseAttrs); } @@ -456,15 +467,15 @@ TEST_F(svc_PrincipalsTest, Update) { rpcUpdate::result_type result; EXPECT_NO_THROW(result = svc.call(ctx, request)); EXPECT_EQ(grpcxx::status::code_t::ok, result.status.code()); - ASSERT_TRUE(result.response); + ASSERT_TRUE(result.response->has_principal()); - auto &actual = result.response.value(); + auto &actual = result.response->principal(); EXPECT_EQ(principal.id(), actual.id()); EXPECT_EQ("segment:svc_PrincipalsTest.Update", actual.segment()); EXPECT_TRUE(actual.has_attrs()); std::string responseAttrs; - google::protobuf::util::MessageToJsonString(result.response->attrs(), &responseAttrs); + google::protobuf::util::MessageToJsonString(actual.attrs(), &responseAttrs); EXPECT_EQ(attrs, responseAttrs); } @@ -481,9 +492,9 @@ TEST_F(svc_PrincipalsTest, Update) { rpcUpdate::result_type result; EXPECT_NO_THROW(result = svc.call(ctx, request)); EXPECT_EQ(grpcxx::status::code_t::ok, result.status.code()); - ASSERT_TRUE(result.response); + ASSERT_TRUE(result.response->has_principal()); - auto &actual = result.response.value(); + auto &actual = result.response->principal(); EXPECT_EQ(principal.id(), actual.id()); EXPECT_FALSE(actual.has_segment()); EXPECT_FALSE(actual.has_attrs());