From 2457d921594418d4b15b5e4f10c64f56f9176b0e Mon Sep 17 00:00:00 2001 From: 11Dimensions <11Dimensions@users.noreply.github.com> Date: Mon, 3 Apr 2023 01:01:56 -0400 Subject: [PATCH 1/9] basic example with some very basic docs --- .gitignore | 10 ++++ README.md | 33 +++++++++++++ buf.gen.yaml | 11 +++++ buf.work.yaml | 3 ++ buf.yaml | 7 +++ build.sbt | 13 +++++ project/build.properties | 1 + project/plugins.sbt | 2 + src/main/protobuf/buf.yaml | 7 +++ src/main/protobuf/petstore/petstore.proto | 47 +++++++++++++++++++ .../petstore/impl/ZioPetstoreImpl.scala | 5 ++ 11 files changed, 139 insertions(+) create mode 100644 README.md create mode 100644 buf.gen.yaml create mode 100644 buf.work.yaml create mode 100644 buf.yaml create mode 100644 build.sbt create mode 100644 project/build.properties create mode 100644 project/plugins.sbt create mode 100644 src/main/protobuf/buf.yaml create mode 100644 src/main/protobuf/petstore/petstore.proto create mode 100644 src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala diff --git a/.gitignore b/.gitignore index 9c07d4a..19a80a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,12 @@ *.class *.log +.vscode +.metals +.history +.bloop +metals.sbt +target/ +.bsp + +#Probably not the best idea but to keep this repo clean and let people run stuff themselves +/src/main/scala/com/example/petstore/generated \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4ce7ce --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +An example. I believe these text is not correct.# Scala Pb Buf Examples. + +More documentation to come... + +## What is Buf +Great tool for protobuf dependency management - a better explanation to come + +## Prerequisites + +This guide assumes you have Scala/SBT. + +## Getting Started + +Follow the instructions of the [Buf install guide](https://buf.build/docs/installation) + +Run the following command to see your code get generated: +“` +buf generate +“` + + +## My Scala Plugin doesn't exist; what do? + +Plugins that are live: + +[Base Scala Pb Compiler](https://buf.build/community/scalapb-scala) +[ZIO GRPC](https://buf.build/community/scalapb-zio-grpc) + +The following are buf plugins that can be easily added, but require demand so the Buf team will support them. If you want to see them, PLEASE leave a thumbs up. If your company would use that plugin heavily drop a comment! +[FS2 GRPC](https://github.com/bufbuild/plugins/issues/305) +[Akka GRPC pre/post license change](https://github.com/bufbuild/plugins/issues/306) + +[Scalapb Validate](https://github.com/bufbuild/plugins/issues/304) plugin would require some help from the Buf team as their plugin test bench doesn't (at the time of writing) support chained plugins. \ No newline at end of file diff --git a/buf.gen.yaml b/buf.gen.yaml new file mode 100644 index 0000000..b1ef21d --- /dev/null +++ b/buf.gen.yaml @@ -0,0 +1,11 @@ +version: v1 +plugins: + - plugin: buf.build/community/scalapb-scala:v0.11.13 + out: src/main/scala + opt: + - flat_package + - grpc + - plugin: buf.build/community/scalapb-zio-grpc:v0.5.3 + out: src/main/scala + opt: + - flat_package diff --git a/buf.work.yaml b/buf.work.yaml new file mode 100644 index 0000000..ebb1446 --- /dev/null +++ b/buf.work.yaml @@ -0,0 +1,3 @@ +version: v1 +directories: + - src/main/protobuf \ No newline at end of file diff --git a/buf.yaml b/buf.yaml new file mode 100644 index 0000000..1a51945 --- /dev/null +++ b/buf.yaml @@ -0,0 +1,7 @@ +version: v1 +breaking: + use: + - FILE +lint: + use: + - DEFAULT diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..6129ca7 --- /dev/null +++ b/build.sbt @@ -0,0 +1,13 @@ + +scalaVersion := "2.13.8" + +name := "scalapb-buf-examples" +organization := "scalapb" +version := "1.0" + +libraryDependencies ++= + Seq( + "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion, + "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion, + "com.thesamet.scalapb.zio-grpc" %% "zio-grpc-core" % "0.5.3" + ) diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..46e43a9 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.8.2 diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..c544830 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,2 @@ +addSbtPlugin("com.thesamet" % "sbt-protoc" % "1.0.0") +libraryDependencies += "com.thesamet.scalapb" %% "compilerplugin" % "0.11.11" \ No newline at end of file diff --git a/src/main/protobuf/buf.yaml b/src/main/protobuf/buf.yaml new file mode 100644 index 0000000..1a51945 --- /dev/null +++ b/src/main/protobuf/buf.yaml @@ -0,0 +1,7 @@ +version: v1 +breaking: + use: + - FILE +lint: + use: + - DEFAULT diff --git a/src/main/protobuf/petstore/petstore.proto b/src/main/protobuf/petstore/petstore.proto new file mode 100644 index 0000000..b52ddda --- /dev/null +++ b/src/main/protobuf/petstore/petstore.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; +package petstore; + +option java_package = "com.example.petstore.generated"; + +message Pet { + int32 id = 1; + string name = 2; +} + +message User { + int32 id = 1; + string username = 2; + string email = 3; + string phone = 4; +} + +message PetByIdRequest { + int32 id = 1; +} + +message UserByNameRequest { + string username = 1; +} + +message PetResponse { + Pet pet = 1; +} + +message UserResponse { + User user = 1; +} + +message EmptyReq{ + string msg = 1; +} +message EmptyRes{ + string msg = 1; +} + +service PetStoreService { + rpc PetById (PetByIdRequest) returns (PetResponse); + rpc UserByName (UserByNameRequest) returns (UserResponse); + rpc ListUsers (EmptyReq) returns (stream User); + rpc StoreUsers (stream User)returns (EmptyRes); + rpc BulkUsers (stream User) returns (stream User); +} \ No newline at end of file diff --git a/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala b/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala new file mode 100644 index 0000000..ffa2198 --- /dev/null +++ b/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala @@ -0,0 +1,5 @@ +package com.example.petstore.impl + +class ZioPetstoreImpl { + //TODO: Draw the owl +} From ab9857d11f37bf1281c82332a4368f1bd5cd453e Mon Sep 17 00:00:00 2001 From: 11Dimensions <11Dimensions@users.noreply.github.com> Date: Mon, 3 Apr 2023 23:37:55 -0400 Subject: [PATCH 2/9] draw the owl --- .gitignore | 32 +++++++--- .scalafix.conf | 17 +++++ .scalafmt.conf | 5 ++ buf.gen.yaml | 3 - buf.yaml | 7 --- build.sbt | 8 ++- project/plugins.sbt | 2 + .../petstore/impl/PetStoreServer.scala | 20 ++++++ .../petstore/impl/ZioPetstoreImpl.scala | 62 ++++++++++++++++++- 9 files changed, 135 insertions(+), 21 deletions(-) create mode 100644 .scalafix.conf create mode 100644 .scalafmt.conf delete mode 100644 buf.yaml create mode 100644 src/main/scala/com/example/petstore/impl/PetStoreServer.scala diff --git a/.gitignore b/.gitignore index 19a80a2..26f6700 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,30 @@ +.vscode/ +.bloop/ +.metals/ +project/.bloop/ +metals.sbt + *.class *.log -.vscode -.metals -.history -.bloop -metals.sbt -target/ +*.swp + +# sbt specific .bsp +.cache/ +.history/ +.lib/ +dist/* +target/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ + +# Scala-IDE specific +.scala_dependencies +.worksheet +.idea + -#Probably not the best idea but to keep this repo clean and let people run stuff themselves +#Probably not the best idea normally but to keep this repo clean and let people run stuff themselves /src/main/scala/com/example/petstore/generated \ No newline at end of file diff --git a/.scalafix.conf b/.scalafix.conf new file mode 100644 index 0000000..06c984d --- /dev/null +++ b/.scalafix.conf @@ -0,0 +1,17 @@ +rules = [OrganizeImports] + +OrganizeImports { + groupedImports = Merge + importsOrder = SymbolsFirst + importSelectorsOrder = SymbolsFirst + groups = [ + "com.example.", + "com.", + "zio.", + "org.", + "scala.", + "java.", + "javax.", + "*" + ] +} \ No newline at end of file diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..1621400 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,5 @@ +version = "3.7.2" +rewrite.rules = [SortImports, RedundantBraces] +maxColumn = 120 +align.preset = most +runner.dialect = scala213source3 \ No newline at end of file diff --git a/buf.gen.yaml b/buf.gen.yaml index b1ef21d..562c94b 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -3,9 +3,6 @@ plugins: - plugin: buf.build/community/scalapb-scala:v0.11.13 out: src/main/scala opt: - - flat_package - grpc - plugin: buf.build/community/scalapb-zio-grpc:v0.5.3 out: src/main/scala - opt: - - flat_package diff --git a/buf.yaml b/buf.yaml deleted file mode 100644 index 1a51945..0000000 --- a/buf.yaml +++ /dev/null @@ -1,7 +0,0 @@ -version: v1 -breaking: - use: - - FILE -lint: - use: - - DEFAULT diff --git a/build.sbt b/build.sbt index 6129ca7..219a784 100644 --- a/build.sbt +++ b/build.sbt @@ -5,9 +5,13 @@ name := "scalapb-buf-examples" organization := "scalapb" version := "1.0" +ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.6.0" +scalacOptions += "-Wunused" + libraryDependencies ++= Seq( "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion, "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion, - "com.thesamet.scalapb.zio-grpc" %% "zio-grpc-core" % "0.5.3" - ) + "io.grpc" % "grpc-netty-shaded" % "1.54.0", + "com.thesamet.scalapb.zio-grpc" %% "zio-grpc-core" % "0.5.3", + ) diff --git a/project/plugins.sbt b/project/plugins.sbt index c544830..6ec49f4 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,2 +1,4 @@ addSbtPlugin("com.thesamet" % "sbt-protoc" % "1.0.0") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.0") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.10.4") libraryDependencies += "com.thesamet.scalapb" %% "compilerplugin" % "0.11.11" \ No newline at end of file diff --git a/src/main/scala/com/example/petstore/impl/PetStoreServer.scala b/src/main/scala/com/example/petstore/impl/PetStoreServer.scala new file mode 100644 index 0000000..2728560 --- /dev/null +++ b/src/main/scala/com/example/petstore/impl/PetStoreServer.scala @@ -0,0 +1,20 @@ +package com.example.petstore.impl + +import com.example.petstore.generated.petstore.User + +import zio.{RefM, ZEnv} + +import scalapb.zio_grpc.{ServerMain, ServiceList} + +object PetStoreServer extends ServerMain { + override def port: Int = 8080 + + val createPetStore = + for { + userState <- RefM.make(Map.empty[String, User]) + } yield new ZioPetstoreImpl(userState) + + override def services: ServiceList[ZEnv] = + ServiceList.addM(createPetStore) + +} diff --git a/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala b/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala index ffa2198..72b8c30 100644 --- a/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala +++ b/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala @@ -1,5 +1,63 @@ package com.example.petstore.impl -class ZioPetstoreImpl { - //TODO: Draw the owl +import com.example.petstore.generated.petstore.{EmptyReq, EmptyRes, Pet, PetByIdRequest, PetResponse, User, UserByNameRequest, UserResponse} +import com.example.petstore.generated.petstore.ZioPetstore._ + +import zio.{IO, RefM} +import zio.stream.{Stream, ZStream} + +import io.grpc.Status + +class ZioPetstoreImpl(userState: ZioPetstoreImpl.State) extends PetStoreService { + + override def petById(request: PetByIdRequest) = + request.id match { + case 0 => IO.succeed(PetResponse(Some(Pet(0, "Ralph the Dog")))) + case 1 => IO.succeed(PetResponse(Some(Pet(1, "Billy the Goat")))) + case 2 => IO.succeed(PetResponse(Some(Pet(2, "Puss in Boots")))) + case _ => IO.fail(Status.NOT_FOUND) + } + + override def userByName(request: UserByNameRequest): IO[Status, UserResponse] = + userState.get.flatMap { state => + state.get(request.username) match { + case None => IO.fail(Status.NOT_FOUND) + case user: Some[User] => IO.succeed(UserResponse(user = user)) + } + } + + override def listUsers(request: EmptyReq): Stream[Status, User] = + ZStream.fromIterableM( + userState.get.map(_.values) + ) + + override def storeUsers(request: Stream[Status, User]): IO[Status, EmptyRes] = + request + .mapM { case user => + userState.updateSome { + case state if (!state.contains(user.username) && user.username.nonEmpty) => + IO.succeed(state + ((user.username, user))) + } + } + .runDrain + .map(_ => EmptyRes.of("Finished Processing Request")) + + override def bulkUsers(request: Stream[Status, User]): Stream[Status, User] = + request.mapM { + case user if (user.username.isEmpty()) => IO.fail(Status.INVALID_ARGUMENT) + case user => + userState + .update(state => + if (state.contains(user.username)) + IO.fail(Status.ALREADY_EXISTS) + else + IO.succeed(state + ((user.username, user))) + ) + .map(_ => user) + } + +} + +object ZioPetstoreImpl { + type State = RefM[Map[String, User]] } From a7017333f063086da8ee10b5e06617a2123f1e3c Mon Sep 17 00:00:00 2001 From: 11Dimensions <11Dimensions@users.noreply.github.com> Date: Wed, 5 Apr 2023 21:56:24 -0400 Subject: [PATCH 3/9] update some of the readme --- README.md | 49 +++++++++++++++---- .../protobuf/petstore/{ => v1}/petstore.proto | 18 +++---- 2 files changed, 48 insertions(+), 19 deletions(-) rename src/main/protobuf/petstore/{ => v1}/petstore.proto (57%) diff --git a/README.md b/README.md index d4ce7ce..7fa98ad 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,51 @@ -An example. I believe these text is not correct.# Scala Pb Buf Examples. +# Scala Pb Buf Examples. -More documentation to come... +This repository contains examples of [Buf](https://buf.build/) ## What is Buf -Great tool for protobuf dependency management - a better explanation to come -## Prerequisites +Buf is a command-line interface tool that provides advanced functionality for working with Protocol Buffers, a popular binary serialization format.It offers features such as linting, compatibility checking, code generation, and dependency management, which can streamline the development workflow for Protocol Buffers-based projects. Buf configuration is defined through yaml files. -This guide assumes you have Scala/SBT. +## Prerequisites +This guide assumes that you have SBT installed ## Getting Started -Follow the instructions of the [Buf install guide](https://buf.build/docs/installation) +To install Buf, follow these steps: + +1. Download the appropriate version of Buf for your operating system from the official website (https://docs.buf.build/installation). +2. Choose your operating system +3. Follow the instructions on the website + + +## Usage + +Once Buf is installed, you can use it to validate, lint, and generate code from your Protocol Buffer files. Here are a few basic commands to get you started: + +### Lint your project +The example project does something that is suboptimal as it uses a datamodel object (`User`) as a request and response type. +Using separate request and response objects in Protocol Buffers for RPC is better as it leads to better encapsulation, and flexibility. It helps encapsulate the data being sent and received, allows for easier modifications without breaking backwards compatibility, and ensures type safety, catching errors at compile time. +Due to this running the following command will produce some errors + +``` +buf lint +``` + +which will produce the following output + +``` +src/main/protobuf/petstore/v1/petstore.proto:44:5:"petstore.v1.User" is used as the request or response type for multiple RPCs. +src/main/protobuf/petstore/v1/petstore.proto:44:54:RPC response type "User" should be named "ListUsersResponse" or "PetStoreServiceListUsersResponse". +src/main/protobuf/petstore/v1/petstore.proto:45:5:"petstore.v1.User" is used as the request or response type for multiple RPCs. +src/main/protobuf/petstore/v1/petstore.proto:45:28:RPC request type "User" should be named "StoreUsersRequest" or "PetStoreServiceStoreUsersRequest". +src/main/protobuf/petstore/v1/petstore.proto:46:5:"petstore.v1.User" is used as the request or response type for multiple RPCs. +src/main/protobuf/petstore/v1/petstore.proto:46:5:RPC "BulkUsers" has the same type "petstore.v1.User" for the request and response. +src/main/protobuf/petstore/v1/petstore.proto:46:27:RPC request type "User" should be named "BulkUsersRequest" or "PetStoreServiceBulkUsersRequest". +src/main/protobuf/petstore/v1/petstore.proto:46:49:RPC response type "User" should be named "BulkUsersResponse" or "PetStoreServiceBulkUsersResponse". +``` + +Note who Buf will suggest consistent naming, which also apply to other request response object. A win for consistency! -Run the following command to see your code get generated: -“` -buf generate -“` ## My Scala Plugin doesn't exist; what do? diff --git a/src/main/protobuf/petstore/petstore.proto b/src/main/protobuf/petstore/v1/petstore.proto similarity index 57% rename from src/main/protobuf/petstore/petstore.proto rename to src/main/protobuf/petstore/v1/petstore.proto index b52ddda..3d6094d 100644 --- a/src/main/protobuf/petstore/petstore.proto +++ b/src/main/protobuf/petstore/v1/petstore.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package petstore; +package petstore.v1; option java_package = "com.example.petstore.generated"; @@ -23,25 +23,25 @@ message UserByNameRequest { string username = 1; } -message PetResponse { +message PetByIdResponse { Pet pet = 1; } -message UserResponse { +message UserByNameResponse { User user = 1; } -message EmptyReq{ +message ListUsersRequest{ string msg = 1; } -message EmptyRes{ +message StoreUsersResponse{ string msg = 1; } service PetStoreService { - rpc PetById (PetByIdRequest) returns (PetResponse); - rpc UserByName (UserByNameRequest) returns (UserResponse); - rpc ListUsers (EmptyReq) returns (stream User); - rpc StoreUsers (stream User)returns (EmptyRes); + rpc PetById (PetByIdRequest) returns (PetByIdResponse); + rpc UserByName (UserByNameRequest) returns (UserByNameResponse); + rpc ListUsers (ListUsersRequest) returns (stream User); + rpc StoreUsers (stream User)returns (StoreUsersResponse); rpc BulkUsers (stream User) returns (stream User); } \ No newline at end of file From 0c4af6d645d74ebd50f003050a4e8bc37b7c15de Mon Sep 17 00:00:00 2001 From: 11Dimensions <11Dimensions@users.noreply.github.com> Date: Wed, 5 Apr 2023 23:59:30 -0400 Subject: [PATCH 4/9] update readme --- README.md | 107 +++++++++++++++---- src/main/protobuf/petstore/v1/petstore.proto | 40 +++---- 2 files changed, 106 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 7fa98ad..db9dab7 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,22 @@ -# Scala Pb Buf Examples. +# ScalaPb Buf Examples. -This repository contains examples of [Buf](https://buf.build/) +This repository contains examples of [Buf](https://buf.build/) and it's use with Scala. -## What is Buf +## What is Buf? -Buf is a command-line interface tool that provides advanced functionality for working with Protocol Buffers, a popular binary serialization format.It offers features such as linting, compatibility checking, code generation, and dependency management, which can streamline the development workflow for Protocol Buffers-based projects. Buf configuration is defined through yaml files. +Buf is a command-line interface tool that provides advanced functionality for working with Protocol Buffers, a popular binary serialization format. It offers features such as linting, compatibility checking, code generation, and dependency management, which can streamline the development workflow for Protocol Buffers-based projects. Buf configuration is defined through YAML files. ## Prerequisites -This guide assumes that you have SBT installed + +This guide assumes that you have SBT installed if you wan to compile and run the example code. ## Getting Started To install Buf, follow these steps: -1. Download the appropriate version of Buf for your operating system from the official website (https://docs.buf.build/installation). -2. Choose your operating system -3. Follow the instructions on the website +1. Download the appropriate version of Buf for your operating system from the [official website](https://docs.buf.build/installation). +2. Choose your operating system. +3. Follow the instructions on the website. ## Usage @@ -23,15 +24,16 @@ To install Buf, follow these steps: Once Buf is installed, you can use it to validate, lint, and generate code from your Protocol Buffer files. Here are a few basic commands to get you started: ### Lint your project -The example project does something that is suboptimal as it uses a datamodel object (`User`) as a request and response type. -Using separate request and response objects in Protocol Buffers for RPC is better as it leads to better encapsulation, and flexibility. It helps encapsulate the data being sent and received, allows for easier modifications without breaking backwards compatibility, and ensures type safety, catching errors at compile time. -Due to this running the following command will produce some errors + +The example project uses a datamodel object (`User`) as a request and response type, which is suboptimal. It is recommended to use separate request and response objects in Protocol Buffers for RPC as it leads to better encapsulation, flexibility, and type safety. This approach helps encapsulate the data being sent and received, allows for easier modifications without breaking backwards compatibility, and ensures errors are caught at compile time. + +Running the following command will produce some errors: ``` buf lint ``` -which will produce the following output +This will produce the following output: ``` src/main/protobuf/petstore/v1/petstore.proto:44:5:"petstore.v1.User" is used as the request or response type for multiple RPCs. @@ -44,19 +46,82 @@ src/main/protobuf/petstore/v1/petstore.proto:46:27:RPC request type "User" shoul src/main/protobuf/petstore/v1/petstore.proto:46:49:RPC response type "User" should be named "BulkUsersResponse" or "PetStoreServiceBulkUsersResponse". ``` -Note who Buf will suggest consistent naming, which also apply to other request response object. A win for consistency! +Note that Buf suggests consistent naming, which also applies to other request/response objects. A consistent naming scheme improves code readability and is easier to maintain. + +If you don't like the default configuration, you can alter it to suit your preferences. See the [documentation](https://buf.build/docs/breaking/usage/#key-concepts) for configuration details. + +## Format your project +No one likes messy code. That's why Buf comes with a handy feature to format your proto files and make them neat and tidy. Use the following command to format this project: + +``` +buf format -w +``` +The `-w` option will write in place. + +To see the difference in formatting run: +``` +git diff +``` + +Your peers will thank you for it! + +### Detect Breaking Changes +Let's shake things up by introducing a breaking change to our protocol buffer definition. To do this, we'll delete the id field from the User message. Once you've made the change, run the following command: +``` +buf breaking '.git#branch=master' +``` +This will check for any breaking changes in the codebase and report them. In our case, you should see an error that reads: +``` +src/main/protobuf/petstore/v1/petstore.proto:11:1:Previously present field "1" with name "id" on message "User" was deleted. +``` + +Buf provides a powerful compatibility checking tool that can also catch other types of errors such as type changes. You can configure different levels of compatibility checks depending on your needs. More information and configuration options can be found in the breaking [breaking documentation](https://buf.build/docs/breaking/overview/#key-concepts). + +It's worth noting that Buf doesn't currently check for breaking changes with extensions made by the `protoc-validate` plugin. + +### Buf Schema Registry (BSR) +Buf Schema Registry (BSR) is the place to be for storing your Protocol Buffers schemas. It provides a centralized location for managing your schema files, allowing you to easily store, share, and version them. With BSR, there's no need to copy and paste your protos or publish them as jars - everything is taken care of for you! + +With BSR, you can ensure consistency and compatibility across services, and simplify the process of integrating with external services. You can follow this [link](https://buf.build/explore) to explore protobufs published to BSR. Published modules also include viewable documentation of the types published, making it even easier to integrate. + +To publish your protos, follow the well-documented steps outlined in [Buf's documentation](https://buf.build/docs/bsr/quick-start/#step-1:-sign-up-for-a-buf-account). + +To pull a dependency, simply add it to your `buf.yaml` file. For instance, if you want to use googleapis, add the following: +``` +deps: + - buf.build/googleapis/googleapis: +``` +Here, is the version you want to use. If you don't include it, Buf will always import the latest version. Once you've added the dependency, execute the following command to begin the import process: +``` +buf mod update +``` +And that's it! Buf will resolve the types of the dependencies and understand their use in your local environment. Additionally, the protobuf types used will also be generated. And if your protobuf files aren't intended for public consumption, Buf also supports private packages. + +### Code Generation +Oh no! Looks like this project is missing all the Scala types that are needed to compile and run the server. Don't fret though, we can easily fix this. Without code generation, protobuf can be pretty useless. So let's generate the code we need by running this command: +``` +buf generate +``` + +After running this, you should see all the Scala code and be able to compile and run the server. The code generation is performed by reading the buf.gen.yaml directory and executing the remote plugins listed there. Buf supports a range of plugins, which can be found on the [plugins page](https://buf.build/plugins). + +Plugins that currently exist +- [Base ScalaPb Compiler](https://buf.build/community/scalapb-scala) +- [ZIO GRPC](https://buf.build/community/scalapb-zio-grpc) +If you need a plugin that Buf doesn't currently support, fear not! You can easily add your own. Check out the plugins page for more information. There are also several plugins that are waiting to be merged, including FS2 GRPC, Akka GRPC, and Scalapb Validate. If you're interested in any of these plugins, be sure to drop a comment or +1 in the linked issues. Bonus points if you think your organization would benefit from them! +**There are a list of plugins, however, that can be added quite easily, but due to the maintenance cost by the Buf team, they have not yet been merged. Please drop a comment or +1 in the linked issues below if you want to see them! Bonus points if you feel like your organization would make use of them.** -## My Scala Plugin doesn't exist; what do? +Two popular GRPC implementations that can be merged fairly quickly are [FS2 GRPC](https://github.com/bufbuild/plugins/issues/305) and [Akka GRPC](https://github.com/bufbuild/plugins/issues/306). [Scalapb Validate](https://github.com/bufbuild/plugins/issues/304) is also missing, but would likely require more work than the other teams as Buf's test bench for added plugins does not support chained plugins. -Plugins that are live: +Note that plugins do not take care of importing the runtime, so you will need to manually align the runtime dependency version with the plugin version you have defined. In case of the ZIO example, you can refer to the build.sbt file for the dependencies needed. For other runtimes, you will need to include equivalent dependencies. -[Base Scala Pb Compiler](https://buf.build/community/scalapb-scala) -[ZIO GRPC](https://buf.build/community/scalapb-zio-grpc) +### How to include a custom protoc plugin in Buf +When using a custom protoc plugin that is not available remotely, it is not as straightforward as adding a remote plugin. This is especially true if you want to ensure that your team's plugin version is kept in sync. Here are the general steps to follow (with full documentation and examples [here](https://buf.build/docs/generate/usage/#2.-define-a-module)): -The following are buf plugins that can be easily added, but require demand so the Buf team will support them. If you want to see them, PLEASE leave a thumbs up. If your company would use that plugin heavily drop a comment! -[FS2 GRPC](https://github.com/bufbuild/plugins/issues/305) -[Akka GRPC pre/post license change](https://github.com/bufbuild/plugins/issues/306) +1. Download your protoc plugin +2. Install the protoc plugin on your $PATH using protoc-gen- +3. In your buf.gen.yaml file, include your plugin in the list of plugins using the plugin: syntax. -[Scalapb Validate](https://github.com/bufbuild/plugins/issues/304) plugin would require some help from the Buf team as their plugin test bench doesn't (at the time of writing) support chained plugins. \ No newline at end of file +You can find more detailed instructions here. Keep in mind that this approach requires more manual setup and maintenance compared to using a remote plugin. You may wish to include the version as a suffix to the to ensure consistent behavior across computers. \ No newline at end of file diff --git a/src/main/protobuf/petstore/v1/petstore.proto b/src/main/protobuf/petstore/v1/petstore.proto index 3d6094d..8d1bb94 100644 --- a/src/main/protobuf/petstore/v1/petstore.proto +++ b/src/main/protobuf/petstore/v1/petstore.proto @@ -4,44 +4,44 @@ package petstore.v1; option java_package = "com.example.petstore.generated"; message Pet { - int32 id = 1; - string name = 2; + int32 id = 1; + string name = 2; } message User { - int32 id = 1; - string username = 2; - string email = 3; - string phone = 4; + int32 id = 1; + string username = 2; + string email = 3; + string phone = 4; } message PetByIdRequest { - int32 id = 1; + int32 id = 1; } message UserByNameRequest { - string username = 1; + string username = 1; } message PetByIdResponse { - Pet pet = 1; + Pet pet = 1; } message UserByNameResponse { - User user = 1; + User user = 1; } -message ListUsersRequest{ - string msg = 1; +message ListUsersRequest { + string msg = 1; } -message StoreUsersResponse{ - string msg = 1; +message StoreUsersResponse { + string msg = 1; } service PetStoreService { - rpc PetById (PetByIdRequest) returns (PetByIdResponse); - rpc UserByName (UserByNameRequest) returns (UserByNameResponse); - rpc ListUsers (ListUsersRequest) returns (stream User); - rpc StoreUsers (stream User)returns (StoreUsersResponse); - rpc BulkUsers (stream User) returns (stream User); -} \ No newline at end of file + rpc PetById(PetByIdRequest) returns (PetByIdResponse); + rpc UserByName(UserByNameRequest) returns (UserByNameResponse); + rpc ListUsers(ListUsersRequest) returns (stream User); + rpc StoreUsers(stream User) returns (StoreUsersResponse); + rpc BulkUsers(stream User) returns (stream User); +} From 699b324250fec727331c09ccf2bf6770ea05f695 Mon Sep 17 00:00:00 2001 From: 11Dimensions <11Dimensions@users.noreply.github.com> Date: Thu, 6 Apr 2023 00:04:37 -0400 Subject: [PATCH 5/9] add types --- .../petstore/impl/ZioPetstoreImpl.scala | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala b/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala index 72b8c30..4c6aa76 100644 --- a/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala +++ b/src/main/scala/com/example/petstore/impl/ZioPetstoreImpl.scala @@ -1,37 +1,44 @@ package com.example.petstore.impl -import com.example.petstore.generated.petstore.{EmptyReq, EmptyRes, Pet, PetByIdRequest, PetResponse, User, UserByNameRequest, UserResponse} import com.example.petstore.generated.petstore.ZioPetstore._ import zio.{IO, RefM} import zio.stream.{Stream, ZStream} import io.grpc.Status +import com.example.petstore.generated.petstore.User +import com.example.petstore.generated.petstore.PetByIdRequest +import com.example.petstore.generated.petstore.PetByIdResponse +import com.example.petstore.generated.petstore.UserByNameRequest +import com.example.petstore.generated.petstore.UserByNameResponse +import com.example.petstore.generated.petstore.Pet +import com.example.petstore.generated.petstore.ListUsersRequest +import com.example.petstore.generated.petstore.StoreUsersResponse class ZioPetstoreImpl(userState: ZioPetstoreImpl.State) extends PetStoreService { override def petById(request: PetByIdRequest) = request.id match { - case 0 => IO.succeed(PetResponse(Some(Pet(0, "Ralph the Dog")))) - case 1 => IO.succeed(PetResponse(Some(Pet(1, "Billy the Goat")))) - case 2 => IO.succeed(PetResponse(Some(Pet(2, "Puss in Boots")))) + case 0 => IO.succeed(PetByIdResponse(Some(Pet(0, "Ralph the Dog")))) + case 1 => IO.succeed(PetByIdResponse(Some(Pet(1, "Billy the Goat")))) + case 2 => IO.succeed(PetByIdResponse(Some(Pet(2, "Puss in Boots")))) case _ => IO.fail(Status.NOT_FOUND) } - override def userByName(request: UserByNameRequest): IO[Status, UserResponse] = + override def userByName(request: UserByNameRequest): IO[Status, UserByNameResponse] = userState.get.flatMap { state => state.get(request.username) match { case None => IO.fail(Status.NOT_FOUND) - case user: Some[User] => IO.succeed(UserResponse(user = user)) + case user: Some[User] => IO.succeed(UserByNameResponse(user = user)) } } - override def listUsers(request: EmptyReq): Stream[Status, User] = + override def listUsers(request: ListUsersRequest): Stream[Status, User] = ZStream.fromIterableM( userState.get.map(_.values) ) - override def storeUsers(request: Stream[Status, User]): IO[Status, EmptyRes] = + override def storeUsers(request: Stream[Status, User]): IO[Status, StoreUsersResponse] = request .mapM { case user => userState.updateSome { @@ -40,7 +47,7 @@ class ZioPetstoreImpl(userState: ZioPetstoreImpl.State) extends PetStoreService } } .runDrain - .map(_ => EmptyRes.of("Finished Processing Request")) + .map(_ => StoreUsersResponse.of("Finished Processing Request")) override def bulkUsers(request: Stream[Status, User]): Stream[Status, User] = request.mapM { From 6746c0697e9d4ac0f419ee3024d6d12525a5d048 Mon Sep 17 00:00:00 2001 From: 11Dimensions <11Dimensions@users.noreply.github.com> Date: Thu, 6 Apr 2023 00:13:49 -0400 Subject: [PATCH 6/9] cleanup readme some more, left around different drafts and added a conclusion --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index db9dab7..13a32d0 100644 --- a/README.md +++ b/README.md @@ -98,19 +98,17 @@ buf mod update And that's it! Buf will resolve the types of the dependencies and understand their use in your local environment. Additionally, the protobuf types used will also be generated. And if your protobuf files aren't intended for public consumption, Buf also supports private packages. ### Code Generation -Oh no! Looks like this project is missing all the Scala types that are needed to compile and run the server. Don't fret though, we can easily fix this. Without code generation, protobuf can be pretty useless. So let's generate the code we need by running this command: +Oh no! Looks like this project is missing all the Scala types that are needed to compile and run the server. But with Buf we can easily fix this. So let's generate the code we need by running this command: ``` buf generate ``` -After running this, you should see all the Scala code and be able to compile and run the server. The code generation is performed by reading the buf.gen.yaml directory and executing the remote plugins listed there. Buf supports a range of plugins, which can be found on the [plugins page](https://buf.build/plugins). +After running this, you should see all the Scala code and be able to compile and run the server. The code generation is performed by reading the `buf.gen.yaml` directory and executing the remote plugins listed there. Buf supports a range of plugins, which can be found on the [plugins page](https://buf.build/plugins). -Plugins that currently exist +Plugins for Scala specifically that currently exist are - [Base ScalaPb Compiler](https://buf.build/community/scalapb-scala) - [ZIO GRPC](https://buf.build/community/scalapb-zio-grpc) -If you need a plugin that Buf doesn't currently support, fear not! You can easily add your own. Check out the plugins page for more information. There are also several plugins that are waiting to be merged, including FS2 GRPC, Akka GRPC, and Scalapb Validate. If you're interested in any of these plugins, be sure to drop a comment or +1 in the linked issues. Bonus points if you think your organization would benefit from them! - **There are a list of plugins, however, that can be added quite easily, but due to the maintenance cost by the Buf team, they have not yet been merged. Please drop a comment or +1 in the linked issues below if you want to see them! Bonus points if you feel like your organization would make use of them.** Two popular GRPC implementations that can be merged fairly quickly are [FS2 GRPC](https://github.com/bufbuild/plugins/issues/305) and [Akka GRPC](https://github.com/bufbuild/plugins/issues/306). [Scalapb Validate](https://github.com/bufbuild/plugins/issues/304) is also missing, but would likely require more work than the other teams as Buf's test bench for added plugins does not support chained plugins. @@ -124,4 +122,4 @@ When using a custom protoc plugin that is not available remotely, it is not as s 2. Install the protoc plugin on your $PATH using protoc-gen- 3. In your buf.gen.yaml file, include your plugin in the list of plugins using the plugin: syntax. -You can find more detailed instructions here. Keep in mind that this approach requires more manual setup and maintenance compared to using a remote plugin. You may wish to include the version as a suffix to the to ensure consistent behavior across computers. \ No newline at end of file +Keep in mind that this approach requires more manual setup and maintenance compared to using a remote plugin. Additionally you may wish to include the version as a suffix to the to ensure consistent behavior across computers, or allow different projects to work with different versions of the same plugin. \ No newline at end of file From cbaa4efaea8f9470dbb3e6bf632abb3fa4eb4e7b Mon Sep 17 00:00:00 2001 From: 11Dimensions <11Dimensions@users.noreply.github.com> Date: Sun, 9 Apr 2023 01:17:44 -0400 Subject: [PATCH 7/9] update with local plugin example --- .gitignore | 4 ++- README.md | 32 ++++++++++++++++++-- buf.gen.yaml | 6 ++++ build.sbt | 1 + src/main/protobuf/buf.lock | 15 +++++++++ src/main/protobuf/buf.yaml | 4 +++ src/main/protobuf/petstore/v1/petstore.proto | 19 ++++++++++-- 7 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 src/main/protobuf/buf.lock diff --git a/.gitignore b/.gitignore index 26f6700..63d59df 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,6 @@ project/plugins/project/ #Probably not the best idea normally but to keep this repo clean and let people run stuff themselves -/src/main/scala/com/example/petstore/generated \ No newline at end of file +/src/main/scala/com/example/petstore/generated +/src/main/scala/io +/src/main/scala/scalapb \ No newline at end of file diff --git a/README.md b/README.md index 13a32d0..2fc6b1a 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Your peers will thank you for it! ### Detect Breaking Changes Let's shake things up by introducing a breaking change to our protocol buffer definition. To do this, we'll delete the id field from the User message. Once you've made the change, run the following command: ``` -buf breaking '.git#branch=master' +buf breaking --against '.git#branch=master' ``` This will check for any breaking changes in the codebase and report them. In our case, you should see an error that reads: ``` @@ -97,6 +97,8 @@ buf mod update ``` And that's it! Buf will resolve the types of the dependencies and understand their use in your local environment. Additionally, the protobuf types used will also be generated. And if your protobuf files aren't intended for public consumption, Buf also supports private packages. +Make note of the new example + ### Code Generation Oh no! Looks like this project is missing all the Scala types that are needed to compile and run the server. But with Buf we can easily fix this. So let's generate the code we need by running this command: ``` @@ -122,4 +124,30 @@ When using a custom protoc plugin that is not available remotely, it is not as s 2. Install the protoc plugin on your $PATH using protoc-gen- 3. In your buf.gen.yaml file, include your plugin in the list of plugins using the plugin: syntax. -Keep in mind that this approach requires more manual setup and maintenance compared to using a remote plugin. Additionally you may wish to include the version as a suffix to the to ensure consistent behavior across computers, or allow different projects to work with different versions of the same plugin. \ No newline at end of file +Keep in mind that this approach requires more manual setup and maintenance compared to using a remote plugin. Additionally you may wish to include the version as a suffix to the to ensure consistent behavior across computers, or allow different projects to work with different versions of the same plugin. + +This example repository uses the validate plugin. To be able to see it run locally + +Some commands may require sudo + +[Download scalapb-validate-0.3.4](https://repo1.maven.org/maven2/com/thesamet/scalapb/protoc-gen-scalapb-validate/0.3.4/protoc-gen-scalapb-validate-0.3.4-unix.sh) + +mv protoc-gen-scalapb-validate-0.3.4-unix.sh /usr/local/bin/protoc-gen-scalapb-validate-0.3.4 + +Really important that it starts with protoc-gen-* buf assumes the plugins are named this. + +chown +x /usr/local/bin/protoc-gen-scalapb-validate-0.3.4 + + +Now uncomment sections in petstore.proto and buf.gen.yaml + +note that need for "com.thesamet.scalapb" %% "scalapb-validate-core" % "0.3.4" + +run `buf generate --include-imports` + +Now run the server, and ask for a user with only one character + + +## Conclusion + +And thats it! This guide only gives a high level overview of what can be achieved and configured with Buf. Buf's resources and documentation are comprehensive, so please review that for more details. If there is something this guide missed, or can be made more clear, please feel free to drop a PR. \ No newline at end of file diff --git a/buf.gen.yaml b/buf.gen.yaml index 562c94b..bf1685d 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -4,5 +4,11 @@ plugins: out: src/main/scala opt: - grpc + # Uncomment this part once you have scalapb-validate installed locally + # - plugin: scalapb-validate-0.3.4 + # out: src/main/scala + # opt: + # - grpc - plugin: buf.build/community/scalapb-zio-grpc:v0.5.3 out: src/main/scala + diff --git a/build.sbt b/build.sbt index 219a784..99ca84f 100644 --- a/build.sbt +++ b/build.sbt @@ -14,4 +14,5 @@ libraryDependencies ++= "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion, "io.grpc" % "grpc-netty-shaded" % "1.54.0", "com.thesamet.scalapb.zio-grpc" %% "zio-grpc-core" % "0.5.3", + "com.thesamet.scalapb" %% "scalapb-validate-core" % "0.3.4", ) diff --git a/src/main/protobuf/buf.lock b/src/main/protobuf/buf.lock new file mode 100644 index 0000000..0233f5c --- /dev/null +++ b/src/main/protobuf/buf.lock @@ -0,0 +1,15 @@ +# Generated by buf. DO NOT EDIT. +version: v1 +deps: + - remote: buf.build + owner: envoyproxy + repository: protoc-gen-validate + commit: 45685e052c7e406b9fbd441fc7a568a5 + - remote: buf.build + owner: scalapb + repository: scalapb + commit: 4b8e0968b1ea452983e157014defba1a + - remote: buf.build + owner: scalapb + repository: scalapb-validate + commit: 0e9f937482594692842b553afa3e1b21 diff --git a/src/main/protobuf/buf.yaml b/src/main/protobuf/buf.yaml index 1a51945..8a8064e 100644 --- a/src/main/protobuf/buf.yaml +++ b/src/main/protobuf/buf.yaml @@ -1,4 +1,8 @@ version: v1 +deps: + - buf.build/scalapb/scalapb-validate:v0.3.4 + - buf.build/envoyproxy/protoc-gen-validate:728c81676f9e54d3571603b90b34c0e6419770c6 + - buf.build/scalapb/scalapb:v0.11.11 breaking: use: - FILE diff --git a/src/main/protobuf/petstore/v1/petstore.proto b/src/main/protobuf/petstore/v1/petstore.proto index 8d1bb94..7316407 100644 --- a/src/main/protobuf/petstore/v1/petstore.proto +++ b/src/main/protobuf/petstore/v1/petstore.proto @@ -3,6 +3,21 @@ package petstore.v1; option java_package = "com.example.petstore.generated"; +import "validate/validate.proto"; + +// Uncomment this block out after you have installed validate protoc plugin to do this part of the demo +// import "scalapb/scalapb.proto"; +// import "scalapb/validate/validate.proto"; //TODO: Current publish puts it in an extra dir, should be scalapb/validate.proto + +// option (scalapb.options) = { +// scope: FILE +// [scalapb.validate.file] { +// validate_at_construction: true +// insert_validator_instance: true +// skip: false +// } +// }; + message Pet { int32 id = 1; string name = 2; @@ -20,11 +35,11 @@ message PetByIdRequest { } message UserByNameRequest { - string username = 1; + string username = 1 [(validate.rules).string.min_len = 3]; } message PetByIdResponse { - Pet pet = 1; + Pet pet = 1 [(validate.rules).message.required = true]; } message UserByNameResponse { From efec2177df1240c9a05871fbe2081db4bb56119b Mon Sep 17 00:00:00 2001 From: Luka Jurukovski Date: Sun, 9 Apr 2023 23:34:02 -0400 Subject: [PATCH 8/9] update readme and ignore files --- .gitignore | 2 +- README.md | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 63d59df..35919ce 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,4 @@ project/plugins/project/ #Probably not the best idea normally but to keep this repo clean and let people run stuff themselves /src/main/scala/com/example/petstore/generated /src/main/scala/io -/src/main/scala/scalapb \ No newline at end of file +/src/main/scala/scalapb diff --git a/README.md b/README.md index 2fc6b1a..6b5a481 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,17 @@ buf mod update ``` And that's it! Buf will resolve the types of the dependencies and understand their use in your local environment. Additionally, the protobuf types used will also be generated. And if your protobuf files aren't intended for public consumption, Buf also supports private packages. -Make note of the new example +An example can be found in the `buf.yaml` file found in the petstore directory. + +In this example we are using the validate protos used by scalapb-validate: +``` +deps: + - buf.build/envoyproxy/protoc-gen-validate:728c81676f9e54d3571603b90b34c0e6419770c6 +``` +The other two dependencies are necessary for a demo of local plugins, they can be ignored for now. If you decide that a dependency is no longer needed you can remove it and run: +``` +buf mod prune +``` ### Code Generation Oh no! Looks like this project is missing all the Scala types that are needed to compile and run the server. But with Buf we can easily fix this. So let's generate the code we need by running this command: From e5ab2c102e0fe31a0d926a38aad4e519db7cdaee Mon Sep 17 00:00:00 2001 From: Luka Jurukovski Date: Sun, 9 Apr 2023 23:37:05 -0400 Subject: [PATCH 9/9] minor edits --- README.md | 30 +++++++++++++++++++++--------- build.sbt | 4 +++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6b5a481..2d1d0ef 100644 --- a/README.md +++ b/README.md @@ -105,10 +105,13 @@ deps: - buf.build/envoyproxy/protoc-gen-validate:728c81676f9e54d3571603b90b34c0e6419770c6 ``` The other two dependencies are necessary for a demo of local plugins, they can be ignored for now. If you decide that a dependency is no longer needed you can remove it and run: + ``` buf mod prune ``` +By adding this dependency we get access to `import "validate/validate.proto";` and the proto extensions available to it. However this is not limited to only extensions, this is also a great way to share common dependencies. + ### Code Generation Oh no! Looks like this project is missing all the Scala types that are needed to compile and run the server. But with Buf we can easily fix this. So let's generate the code we need by running this command: ``` @@ -136,28 +139,37 @@ When using a custom protoc plugin that is not available remotely, it is not as s Keep in mind that this approach requires more manual setup and maintenance compared to using a remote plugin. Additionally you may wish to include the version as a suffix to the to ensure consistent behavior across computers, or allow different projects to work with different versions of the same plugin. -This example repository uses the validate plugin. To be able to see it run locally -Some commands may require sudo +#### Running the Validate Plugin locally + +This example repository uses the validate plugin, and can be used for code generation. To execute the plugin locally follow these steps, note that some commands may require `sudo` or the equivalent in Windows: [Download scalapb-validate-0.3.4](https://repo1.maven.org/maven2/com/thesamet/scalapb/protoc-gen-scalapb-validate/0.3.4/protoc-gen-scalapb-validate-0.3.4-unix.sh) +Once downloaded move the file onto your path. For example: +``` mv protoc-gen-scalapb-validate-0.3.4-unix.sh /usr/local/bin/protoc-gen-scalapb-validate-0.3.4 +``` -Really important that it starts with protoc-gen-* buf assumes the plugins are named this. +**It is really important that it starts with protoc-gen-* as buf assumes the plugins are named with this prefix.** +Make sure that the script is executable +``` chown +x /usr/local/bin/protoc-gen-scalapb-validate-0.3.4 +``` +And that's it! Buf can now execute your local plugin! -Now uncomment sections in petstore.proto and buf.gen.yaml - -note that need for "com.thesamet.scalapb" %% "scalapb-validate-core" % "0.3.4" +To see this in action, uncomment out the sections as labeled in the `petstore.proto` file and the `buf.gen.yaml` file and the `build.sbt` file. -run `buf generate --include-imports` +Here is why: +* `petstore.proto` - the commented section shows how to configure some of the validation features, it also changes the code to do something meanigfully different (validate_at_construction) when you run the server +* `buf.gen.yaml` - this is the part that actually instructs buf to use the local installed plugin +* `build.sbt` - the validation plugin refers to some types that are not generated, not all plugins will need this, but like in the grpc example we need the runtime to work. -Now run the server, and ask for a user with only one character +Run `buf generate --include-imports` to generate the new code. Now, if you run the example server, you will now see that the fields marked for validation are now validated prior to the execution of the endpoint. ## Conclusion -And thats it! This guide only gives a high level overview of what can be achieved and configured with Buf. Buf's resources and documentation are comprehensive, so please review that for more details. If there is something this guide missed, or can be made more clear, please feel free to drop a PR. \ No newline at end of file +That's all to this guide however this guide only gives only a high level overview of what can be achieved and configured with Buf. Buf's resources and documentation are comprehensive, so please review that for more details. If there is something this guide missed, or can be made more clear, please feel free to drop a PR. \ No newline at end of file diff --git a/build.sbt b/build.sbt index 99ca84f..4f23ec6 100644 --- a/build.sbt +++ b/build.sbt @@ -14,5 +14,7 @@ libraryDependencies ++= "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapb.compiler.Version.scalapbVersion, "io.grpc" % "grpc-netty-shaded" % "1.54.0", "com.thesamet.scalapb.zio-grpc" %% "zio-grpc-core" % "0.5.3", - "com.thesamet.scalapb" %% "scalapb-validate-core" % "0.3.4", + // Uncomment the following line for the local valdiation plugin, this is needed + // to get some of the types that the code generator references. + // "com.thesamet.scalapb" %% "scalapb-validate-core" % "0.3.4", )