Quickstart

We're going to create a simple service to view the users in the system.

Project Setup

Create a new Django project named grpc_tutorial

# Create the project directory
$ mkdir grpc_tutorial
$ cd grpc_tutorial

# Create a virtualenv to isolate our package dependencies locally
$ virtualenv env
$ source env/bin/activate

# Install the packages into the virtualenv
$ pip install django
$ pip install djangorestframework
$ pip install grpc-django

# Set up a new project with a single application
$ django-admin startproject config .  # Note the trailing '.' character
$ python manage.py startapp users

The project layout should look like:

$ pwd
<some path>/grpc_tutorial
$ find .
.
./grpc_tutorial
./grpc_tutorial/__init__.py
./grpc_tutorial/settings.py
./grpc_tutorial/urls.py
./grpc_tutorial/wsgi.py
./users
./users/migrations
./users/migrations/__init__.py
./users/models.py
./users/__init__.py
./users/apps.py
./users/admin.py
./users/tests.py
./users/views.py
./manage.py

Now sync your database for the first time:

python manage.py migrate

Create the Protocol Buffer file users/user.proto and define the GRPC service:

syntax = "proto3";

package user;

message User {
    int64 id = 1;
    string username = 2;
    string first_name = 3;
    string last_name = 4;
}

message GetPayload {
    int64 id = 1;
}

message Empty {}

service UserService {
    rpc GetUser (GetPayload) returns (User);
    rpc ListUsers (Empty) returns (stream User);
}

Settings

Add 'grpc_django' to INSTALLED_APPS. The settings module will be in grpc_tutorial/settings.py.

INSTALLED_APPS = (
    ...
    'grpc_django',
)

Add GRPC_SETTINGS in the settings module

from grpc_django import GRPCSettings, GRPCService


GRPC_SETTINGS = GRPCSettings(
    services=[GRPCService(
        # Name of the service as defined in .proto definition
        name='UserService',
        # The package name as defined in .proto definition (in our case it should look like `package user;`
        package_name='user',
        # The path (relative to `manage.py`) to the .proto definition 
        proto_path='users/user.proto',
        # This will be the list of RPCs similar to `urls.py` definition in Django
        rpc_conf='users.rpc'
    )]
)

Generating the client and server code

Next you need to generate the gRPC client and server interfaces from your users/user.proto service definition.

First, install the grpcio-tools package:

$ pip install grpcio-tools

Use the following Django management command to generate the Python code:

$ python manage.py generate_grpc_stubs

The above command will generate a python package grpc_codegen containing the following modules:

./manage.py
...
./grpc_codegen
./grpc_codegen/__init__.py
./grpc_codegen/user_pb2.py
./grpc_codegen/user_pb2_grpc.py
...

Serializers

Now we're going to define some serializers using Django REST framework. Let's create a new module named users/serializers.py that we'll be used for data representations.

from django.contrib.auth.models import User
from rest_framework.serializers import ModelSerializer


class UserSerializer(ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'first_name', 'last_name', 'username')

Please refer DjangoRESTFramework - Serializers for detailed usage of serializers

RPCs

We are gonna write some RPCs in users/views.py which should look familiar to Django Views or Django REST Framework Views

from grpc_django.views import RetrieveGRPCView, ServerStreamGRPCView
from grpc_codegen.user_pb2 import User as UserProto
from django.contrib.auth.models import User
from .serializers import UserSerializer

class GetUser(RetrieveGRPCView):
    """
    RPC to view a single user by ID
    """
    queryset = User.objects.all()
    response_proto = UserProto
    serializer_class = UserSerializer


class ListUsers(ServerStreamGRPCView):
    """
    RPC to list all users
    """
    queryset = User.objects.all()
    response_proto = UserProto
    serializer_class = UserSerializer

Similar to urls.py in Django, where we define API endpoints and link them to respective views, in GRPC Django we are gonna link views to corresponding RPCs as defined in the users/user.proto file. Create a module users/rpcs.py with the following:

from grpc_django.interfaces import rpc
from .views import GetUser, ListUsers


rpcs = [
    rpc(name='GetUser', view=GetUser),
    rpc(name='ListUsers', view=ListUsers)
]

Running the Server

Finally you can run your gRPC server by the following command:

$ python manage.py run_grpc_server

This will run your gRPC server on 127.0.0.1:55000

Testing Our Service

To test our gRPC service we need to create a client that would use the generated client code to access the RPCs. Create a python module test_grpc_client.py, and write the following sample code in it:

import grpc
import sys

from grpc_codegen.user_pb2 import GetPayload, Empty
from grpc_codegen.user_pb2_grpc import UserServiceStub


def run():
    # Create a connection with the server
    channel = grpc.insecure_channel("localhost:55000")
    try:
        grpc.channel_ready_future(channel).result(timeout=10)
    except grpc.FutureTimeoutError:
        sys.exit('Error connecting to server')
    else:
        stub = UserServiceStub(channel)

    # Test the GetUser RPC
    print("Calling GetUser with id = 1")
    response = stub.GetUser(GetPayload(id=1))
    if response:
        print("Received response for GetUser: {}".format(response))

    # Test the ListUsers RPC
    print("Calling ListUsers")
    response = stub.ListUsers(Empty())
    for _ in response:
        print(_)

    # Close the connection
    channel.close()


if __name__ == "__main__":
    run()

Run the above code using python test_grpc_client.py