8000 doc/md: various improvements to gRPC tutorial by kortschak · Pull Request #2977 · ent/ent · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

doc/md: various improvements to gRPC tutorial #2977

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files. Retry
Loading
Diff view
Diff view
36 changes: 17 additions & 19 deletions doc/md/tutorial-grpc-edges.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ together with generated gRPC services.

Let's start by adding a new entity, `Category` and create edges relating our `User` type to it:

```go
```go title="ent/schema/category.go"
package schema

import (
Expand Down Expand Up @@ -47,7 +47,7 @@ func (Category) Edges( 8000 ) []ent.Edge {

Creating the inverse relation on the `User`:

```go {4-6}
```go title="ent/schema/user.go" {4-6}
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
Expand All @@ -66,17 +66,17 @@ Notice a few things:

Re-generating the project with `go generate ./...`, notice the changes to the `.proto` file:

```protobuf {1-7,18}
```protobuf title="ent/proto/entpb/entpb.proto" {1-7,18}
message Category {
int32 id = 1;
int64 id = 1;

string name = 2;

User admin = 3;
}

message User {
int32 id = 1;
int64 id = 1;

string name = 2;

Expand Down Expand Up @@ -137,7 +137,7 @@ func TestServiceWithEdges(t *testing.T) {
Name: "user",
EmailAddress: "user@service.code",
Administered: []*entpb.Category{
{Id: int32(cat.ID)},
{Id: int64(cat.ID)},
},
},
})
Expand Down Expand Up @@ -168,16 +168,14 @@ func TestServiceWithEdges(t *testing.T) {
To create the edge from the created `User` to th 8000 e existing `Category` we do not need to populate the entire `Category`
object. Instead we only populate the `Id` field. This is picked up by the generated service code:

```go {5-7}
// Create implements UserServiceServer.Create
func (svc *UserService) Create(ctx context.Context, req *CreateUserRequest) (*User, error) {
user := req.GetUser()
// truncated ...
```go title="ent/proto/entpb/entpb_user_service.go" {3-6}
func (svc *UserService) createBuilder(user *User) (*ent.UserCreate, error) {
// truncated ...
for _, item := range user.GetAdministered() {
m.AddAdministeredIDs(int(item.GetId()))
administered := int(item.GetId())
m.AddAdministeredIDs(administered)
}
res, err := m.Save(ctx)
// truncated ...
return m, nil
}
```

Expand Down Expand Up @@ -212,7 +210,7 @@ func TestGet(t *testing.T) {

// next, retrieve the user without edge information
get, err := svc.Get(ctx, &entpb.GetUserRequest{
Id: int32(user.ID),
Id: int64(user.ID),
})
if err != nil {
t.Fatal("failed retrieving the created user", err)
Expand All @@ -223,7 +221,7 @@ func TestGet(t *testing.T) {

// next, retrieve the user *WITH* edge information
get, err = svc.Get(ctx, &entpb.GetUserRequest{
Id: int32(user.ID),
Id: int64(user.ID),
View: entpb.GetUserRequest_WITH_EDGE_IDS,
})
if err != nil {
Expand All @@ -240,9 +238,9 @@ done deliberately because the amount of entities related to an entity is unbound
whether or not to return the edge information or not, the generated service adheres to [AIP-157](https://google.aip.dev/157)
(Partial Responses). In short, the `GetUserRequest` message includes an enum named `View`:

```protobuf
```protobuf title="ent/proto/entpb/entpb.proto"
message GetUserRequest {
int32 id = 1;
int64 id = 1;

View view = 2;

Expand All @@ -258,7 +256,7 @@ message GetUserRequest {

Consider the generated code for the `Get` method:

```go
```go title="ent/proto/entpb/entpb_user_service.go"
// Get implements UserServiceServer.Get
func (svc *UserService) Get(ctx context.Context, req *GetUserRequest) (*User, error) {
// .. truncated ..
Expand Down
17 changes: 9 additions & 8 deletions doc/md/tutorial-grpc-generating-a-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sidebar_label: Generating a Service
---
Generating Protobuf structs generated from our `ent.Schema` can be useful, but what we're really interested in is getting an actual server that can create, read, update, and delete entities from an actual database. To do that, we need to update just one line of code! When we annotate a schema with `entproto.Service`, we tell the `entproto` code-gen that we are interested in generating a gRPC service definition, from the `protoc-gen-entgrpc` will read our definition and generate a service implementation. Edit `ent/schema/user.go` and modify the schema's `Annotations`:

```go {4}
```go title="ent/schema/user.go" {4}
func (User) Annotations() []schema.Annotation {
return []schema.Annotation{
entproto.Message(),
Expand Down Expand Up @@ -33,7 +33,7 @@ ent/proto/entpb

First, `entproto` added a service definition to `entpb.proto`:

```protobuf
```protobuf title="ent/proto/entpb/entpb.proto"
service UserService {
rpc Create ( CreateUserRequest ) returns ( User );

Expand All @@ -51,7 +51,7 @@ service UserService {

In addition, two new files were created. The first, `entpb_grpc.pb.go`, contains the gRPC client stub and the interface definition. If you open the file, you will find in it (among many other things):

```go
```go title="ent/proto/entpb/entpb_grpc.pb.go"
// UserServiceClient is the client API for UserService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please
Expand All @@ -68,26 +68,27 @@ type UserServiceClient interface {

The second file, `entpub_user_service.go` contains a generated implementation for this interface. For example, an implementation for the `Get` method:

```go
```go title="ent/proto/entpb/entpb_user_service.go"
// Get implements UserServiceServer.Get
func (svc *UserService) Get(ctx context.Context, req *GetUserRequest) (*User, error) {
var (
err error
get *ent.User
)
id := int(req.GetId())
switch req.GetView() {
case GetUserRequest_VIEW_UNSPECIFIED, GetUserRequest_BASIC:
get, err = svc.client.User.Get(ctx, int(req.GetId()))
get, err = svc.client.User.Get(ctx, id)
case GetUserRequest_WITH_EDGE_IDS:
get, err = svc.client.User.Query().
Where(user.ID(int(req.GetId()))).
Where(user.ID(id)).
Only(ctx)
default:
return nil, status.Errorf(codes.InvalidArgument, "invalid argument: unknown view")
return nil, status.Error(codes.InvalidArgument, "invalid argument: unknown view")
}
switch {
case err == nil:
return toProtoUser(get), nil
return toProtoUser(get)
case ent.IsNotFound(err):
return nil, status.Errorf(codes.NotFound, "not found: %s", err)
default:
Expand Down
10 changes: 5 additions & 5 deletions doc/md/tutorial-grpc-generating-proto.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ As Ent and Protobuf schemas are not identical, we must supply some annotations o

The first thing we need to do is to add an `entproto.Message()` annotation. This is our opt-in to Protobuf schema generation, we don't necessarily want to generate proto messages or gRPC service definitions from *all* of our schema entities, and this annotation gives us that control. To add it, append to `ent/schema/user.go`:

```go
```go title="ent/schema/user.go"
func (User) Annotations() []schema.Annotation {
return []schema.Annotation{
entproto.Message(),
Expand All @@ -17,7 +17,7 @@ func (User) Annotations() []schema.Annotation {

Next, we need to annotate each field and assign it a field number. Recall that when [defining a protobuf message type](https://developers.google.com/protocol-buffers/docs/proto3#simple), each field must be assigned a unique number. To do that, we add an `entproto.Field` annotation on each field. Update the `Fields` in `ent/schema/user.go`:

```go
```go title="ent/schema/user.go"
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
Expand All @@ -37,7 +37,7 @@ func (User) Fields() []ent.Field {

Notice that we did not start our field numbers from 1, this is because `ent` implicitly creates the `ID` field for the entity, and that field is automatically assigned the number 1. We can now generate our protobuf message type definitions. To do that, we will add to `ent/generate.go` a `go:generate` directive that invokes the `entproto` command-line tool. It should now look like this:

```go
```go title="ent/generate.go"
package ent

//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema
Expand All @@ -61,7 +61,7 @@ ent/proto

Two files were created. Let's look at their contents:

```protobuf
```protobuf title="ent/proto/entpb/entpb.proto"
// Code generated by entproto. DO NOT EDIT.
syntax = "proto3";

Expand All @@ -80,7 +80,7 @@ message User {

Nice! A new `.proto` file containing a message type definition that maps to our `User` schema was created!

```go
```go title="ent/proto/entpb/generate.go"
package entpb
//go:generate protoc -I=.. --go_out=.. --go-grpc_out=.. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative --entgrpc_out=.. --entgrpc_opt=paths=source_relative,schema_path=../../schema entpb/entpb.proto
```
Expand Down
38 changes: 17 additions & 21 deletions doc/md/tutorial-grpc-optional-fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ primitive fields.

To support this, the Protobuf project supports some [Well-Known types](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf) called "wrapper types".
For example, the wrapper type for a `bool`, is called `google.protobuf.BoolValue` and is [defined as](https://github.com/protocolbuffers/protobuf/blob/991bcada050d7e9919503adef5b52547ec249d35/src/google/protobuf/wrappers.proto#L103-L107):
```protobuf
```protobuf title="ent/proto/entpb/entpb.proto"
// Wrapper message for `bool`.
//
// The JSON representation for `BoolValue` is JSON `true` and `false`.
Expand All @@ -22,7 +22,7 @@ When `entproto` generates a Protobuf message definition, it uses these wrapper t

Let's see this in action, modifying our ent schema to include an optional field:

```go {14-16}
```go title="ent/schema/user.go" {14-16}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
Expand All @@ -45,7 +45,7 @@ func (User) Fields() []ent.Field {

Re-running `go generate ./...`, observe that our Protobuf definition for `User` now looks like:

```protobuf {8}
```protobuf title="ent/proto/entpb/entpb.proto" {8}
message User {
int32 id = 1;

Expand All @@ -54,33 +54,29 @@ message User {
string email_address = 3;

google.protobuf.StringValue alias = 4; // <-- this is new

repeated Category administered = 5;
}
```

The generated service implementation also utilize this field. Observe in `entpb_user_service.go`:

```go {5-7}
// Create implements UserServiceServer.Create
func (svc *UserService) Create(ctx context.Context, req *CreateUserRequest) (*User, error) {
user := req.GetUser()
```go title="ent/proto/entpb/entpb_user_service.go" {3-6}
func (svc *UserService) createBuilder(user *User) (*ent.UserCreate, error) {
m := svc.client.User.Create()
if user.GetAlias() != nil {
m.SetAlias(user.GetAlias().GetValue())
userAlias := user.GetAlias().GetValue()
m.SetAlias(userAlias)
}
m.SetEmailAddress(user.GetEmailAddress())
m.SetName(user.GetName())
res, err := m.Save(ctx)

switch {
case err == nil:
return toProtoUser(res), nil
case sqlgraph.IsUniqueConstraintError(err):
return nil, status.Errorf(codes.AlreadyExists, "already exists: %s", err)
case ent.IsConstraintError(err):
return nil, status.Errorf(codes.InvalidArgument, "invalid argument: %s", err)
default:
return nil, status.Errorf(codes.Internal, "internal: %s", err)
userEmailAddress := user.GetEmailAddress()
m.SetEmailAddress(userEmailAddress)
userName := user.GetName()
m.SetName(userName)
for _, item := range user.GetAdministered() {
administered := int(item.GetId())
m.AddAdministeredIDs(administered)
}
return m, nil
}
```

Expand Down
4 changes: 2 additions & 2 deletions doc/md/tutorial-grpc-service-generation-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ To generate a service with multiple methods, bitwise OR the flags.


To see this in action, we can modify our ent schema. Let's say we wanted to prevent our gRPC client from mutating entries. We can accomplish this by modifying `ent/schema/user.go`:
```go {5}
```go title="ent/schema/user.go" {5}
func (User) Annotations() []schema.Annotation {
return []schema.Annotation{
entproto.Message(),
Expand All @@ -43,7 +43,7 @@ func (User) Annotations() []schema.Annotation {
```

Re-running `go generate ./...` will give us the following service definition in `entpb.proto`:
```protobuf
```protobuf title="ent/proto/entpb/entpb.proto"
service UserService {
rpc Create ( CreateUserRequest ) returns ( User );

Expand Down
2 changes: 1 addition & 1 deletion doc/md/tutorial-grpc-setting-up.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ go get -u entgo.io/contrib/entproto

Next, we will define the schema for the `User` entity. Open `ent/schema/user.go` and edit:

```go
```go title="ent/schema/user.go"
package schema

import (
Expand Down
0