Null SupportΒΆ

In proto3, all fields are never null. However, we can use Oneof to define a nullable type, for example:

syntax = "proto3";

package snippets;

import "google/protobuf/struct.proto";

service SnippetController {
    rpc Update(Snippet) returns (Snippet) {}
}

message NullableString {
    oneof kind {
        string value = 1;
        google.protobuf.NullValue null = 2;
    }
}

message Snippet {
    int32 id = 1;
    string title = 2;
    NullableString language = 3;
}

The client example:

import grpc
import snippets_pb2
import snippets_pb2_grpc
from google.protobuf.struct_pb2 import NullValue


with grpc.insecure_channel('localhost:50051') as channel:
    stub = snippets_pb2_grpc.SnippetControllerStub(channel)
    request = snippets_pb2.Snippet(id=1, title='snippet title')
    # send non-null value
    # request.language.value = "python"
    # send null value
    request.language.null = NullValue.NULL_VALUE
    response = stub.Update(request)
    print(response, end='')

The service implementation:

from django_grpc_framework import generics, mixins
from django_grpc_framework import proto_serializers
from snippets.models import Snippet
import snippets_pb2
from google.protobuf.struct_pb2 import NullValue


class SnippetProtoSerializer(proto_serializers.ModelProtoSerializer):
    class Meta:
        model = Snippet
        fields = '__all__'

    def message_to_data(self, message):
        data = {
            'title': message.title,
        }
        if message.language.HasField('value'):
            data['language'] = message.language.value
        elif message.language.HasField('null'):
            data['language'] = None
        return data

    def data_to_message(self, data):
        message = snippets_pb2.Snippet(
            id=data['id'],
            title=data['title'],
        )
        if data['language'] is None:
            message.language.null = NullValue.NULL_VALUE
        else:
            message.language.value = data['language']
        return message


class SnippetService(mixins.UpdateModelMixin,
                     generics.GenericService):
    queryset = Snippet.objects.all()
    serializer_class = SnippetProtoSerializer