RESTful API development in .NET 5 with Protocol Buffers and Cybtans-CLI
Introduction
The Cybtans Command Line Interface aka Cybtans CLI is a cross-platform Protocol Buffers compiler for the development of RESTful APIs with AspNet Core driven by definitions in the Protobuf language. Using methodology improves productivity by generating a lot of boilerplate code, thus allowing the developer to focus on the application logic. Which results in a clean architecture with auto-generated code for AspNet Core Controllers and client libraries. The integration between backend and frontend teams is also improved due to code documentation for client libraries and services are generated directly from the protobuf definitions. In addition, the Cybtans CLI allows the developer to create a project structure ready for microservice development.
Generating RESTful Apis using proto files
As mentioned before the Cybtans protobuf compiler uses proto files to create Rest services instead of gRPC. Rest services provide a wide range of integration options for web apps. while gRPC is suitable for internal service communications.
To generate REST Apis using proto files, download the cybtans cli for your platform. Extract it and add the location to your PATH.
Next, create a file named cybtans.json
in the project’s directory. This file defines configuration settings and is organized into several steps.
Each step represents a code generation process. In the example below there are two steps defined. The first one is for generating a proto file with messages from classes in a .net assembly file. The second step compiles the specified proto file and generates C# code for service interfaces, API controllers, DTOs, and client libraries.
In order to generate messages in protobuf from POCO classes, you need to add the following package. This allows you to mark the classes you want to include in the proto file when the reverse-engineering to the .NET assembly is applied.
dotnet add package Cybtans.Entities.Proto
Then decorate the POCO classes you want to generate message from with the GenerateMessage attribute as shown below. In addition, you can use the MessageExcluded attribute for excluding a property into its corresponding protobuf message.
Now, in order to run the steps in the cybtans.json file, you need to open a terminal and execute the cybtans-cli command-line tool.
> cybtans-cli [route to your project's directory]
The cybtans-cli generates the following data.proto file. This file contains message definitions from the WeatherService.Data
project. This is especially useful when you generate entity-type classes from a database, using Entity Framework Reverse Engineering.
Now you can define a service in the weather.proto file like the one shown below. The weather.proto is the entry point for the cybtans compiler. You can import other files as well like the data.proto and use those messages. In addition, you can define the namespace in the proto file, but the cybtans.json configuration takes precedence and overrides the service namespace.
The cybtans compiler leverages some options to generate AspNetCore controllers and documentations. The extended options can be found in the cybtans.proto file. So after the code is generated, you can provide the service implementation like in the following code snippet.
The cybtans protobuf compiler can generate as well code for typescript for angular and react as specified in the cybtans.json. The typescript models are generated as interfaces as shown in the following code.
On the other hand, the cybtans compiler can generate the client’s code for a specific framework or library. For example the clients for React leverage a fetch-like function as shown below. Be aware that in this case the typescript clients' classes are generic enough and do not contains react-specific code.
In contrast, the clients for Angular uses Angular dependencies like the HttpClient abstraction, and observables as shown below.
Generating Restful proxies for gRPC services
The cybtans compiler can generate Rest Apis which communicates with upstream gRPC services. These services are commonly known as API Gateways or Backend for Frontends. Generally, the API Gateway service takes care of authentication and authorization for the upstream gRPC calls, this approach improves the gRPC reusability. Even more, you can provide a GraphQL endpoint for aggregating data from multiple gRPCs. The cybans compiler can help you with this approach by generating all the schema and resolvers, I will cover this topic with more details further in this article.
In order to expose a gRPC through a Rest API, you need to set up a gRPC project first by using for example the Visual Studio template or the DotNet CLI, for example:
dotnet new grpc -o GrpcGreeter
Then copy the cybtans.proto to the Protos folder and import the file as shown below
In addition, ensure the cybtans.proto is not compiled by the gRPC toolchain by adding this to the .csproj file.
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Both" />
<Protobuf Include="Protos\cybtans.proto" GrpcServices="None" /></ItemGroup>
Now create an AspNetCore with Visual Studio or the CLI
dotnet new webapi -o ApiGateway
Once the Web API project is created go ahead and add the following cybtans.json to the gRPC project.
Then after running the cybtans-cli, you will notice the following code is generated, including the service interface, DTO models, controllers, and the service implementation that calls the gRPC.
The next step to finish this example is to register the service class and the gRPC client with DI in the ConfigureServices method of the Startup class.
Generating GraphQL endpoints for Grpc Services
The cybtans protobuf compiler can generate GraphQL type schemas for graphql-dotnet along with asynchronous resolver functions to pull data from multiple gRPCs. To enable this functionality you can add the following option to the RPC as shown below: option (graphql).query = “hello”;
To complete the setup for GraphQL generation you need to add the GraphQL configuration section to the cybtans.json as shown below.
Note the GraphQL section goes inside the Services section. Then when running the cybtans-cli you can notice the following code is generated.
In the previous code snipped you can see the Query Schema was not generated, neither the constructor for the GraphQLQueryDefinitions class. This is intentional so you can add customize your query and add additional fields from other protos as shown below.
Now to finish the GraphQl setup you need to register the Schema with DI and add the GraphQL middleware to the AspnetCore pipeline.
services.AddSingleton<ISchema, ApiGatewayDefinitionsSchema>();services.AddGraphQL(options =>{
options.EnableMetrics = true;
})
.AddErrorInfoProvider(opt => opt.ExposeExceptionStackTrace = true)
.AddSystemTextJson()
.AddGraphTypes(typeof(Startup), ServiceLifetime.Singleton);
You can add the GraphQl middleware in the Configure method of the Startup class as shown below.
// add http for Schema at default url /graphql
app.UseGraphQL<ISchema>();// use graphql-playground at default url /ui/playground
app.UseGraphQLPlayground("/ui/playground");
Conclusions
The cybtans protobuf compiler is a powerful tool that can save you a lot of time when developing microservice applications. It can generate Restful Apis, API Gateways, and GraphQL endpoints from proto files. This making your proto files the source of truth for your backend services.
The cybtans compiler supports several options for authorization like roles and policy-based authorization. In especial, the policy-based authorization can be used as well for authorization based on the result data.
The advantage the cybtans compilers provides to front-end developers is that they don’t have to spend time writing integration code for backend services liked DTOs and clients components in typescript. Moreover, front-end developers can leverage the autogenerated GraphQL endpoints to fetch data from multiple microservices using a single request, thus improving the app responsiveness and user experience.