DEV Community

Jeremy Pollock
Jeremy Pollock

Posted on

Postman-powered testing of Akka Serverless gRPC APIs

Over the holidays, 2021, Postman gifted a fine upgrade to its users: beta support for the gRPC protocol in its API platform. As a Product Manager for Lightbend and helping out on its new gRPC native PaaS for building and running APIs and microservices, I was excited, to say the least. In another, recent blog post, I mentioned my desire to leverage UI test-and-try tools for APIs (my time in the REST API world of Mashery and PubNub was the source of such desire). In that same post though, I noted the lack of several important gRPC features, like server reflection and more robust import capabilities, as blockers; hence, my deep dive, in that post, into the CLI tool, Evans.

But just because one builds APIs and services in Akka Serverless, using gRPC as a first class citizen, doesn't mean that one has to rely solely on gRPC tooling. When running your logic on this serverless platform, you can access your developed, and running, APIs through direct HTTP requests. The product has an "always-on" feature called HTTP transcoding, and its default behaviour is to expose every gRPC method as a POST request to a URI of /<fully qualified service name>/<method name> , with that resource accepting a JSON representation of the full protobuf message. One simply has to look at their API definitions, as captured in a protobuf to get the URIs that are needed. Let's check out what that really means!


NOTE

If you just want to go make some API calls in Postman, you can access the demo collection using the below:
Run in Postman


Parsing out URIs from a protobuf

Ready to parse, human? To read through a possibly strangely constructed file and deduce URIs that match the above format of /<fully qualified service name>/<method name>? Well, even if you're not, let's learn!

Below is a protobuf file. If you have no idea what protobuf is, you might want to check out this site: https://developers.google.com/protocol-buffers. For purposes of this post, it can be thought of as our API contract. WSDL? OpenAPI specification? Well, like those, yes. The below file defines what API requests can be made, and what the inputs and outputs are Knowing this, we can look at the API contract and divine an API request.

syntax = "proto3";

// This will be part of the fully qualified service name <1>
package com.example;

import "akkaserverless/annotations.proto";
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";

option java_outer_classname = "CounterApi";

message IncreaseValue {
    string counter_id = 1 [(akkaserverless.field).entity_key = true];
    int32 value = 2;
}

message DecreaseValue {
    string counter_id = 1 [(akkaserverless.field).entity_key = true];
    int32 value = 2;
}

message ResetValue {
    string counter_id = 1 [(akkaserverless.field).entity_key = true];
}

message GetCounter {
    string counter_id = 1 [(akkaserverless.field).entity_key = true];
}

message CurrentCounter {
    int32 value = 1;
}

// This will be part of the fully qualified service name, appended to the package name <2>
service CounterService {
    option (akkaserverless.codegen) = {
        value_entity: {
            name: "com.example.domain.Counter"
            entity_type: "counter"
            state: "com.example.domain.CounterState"

        }
    };

    // each of the below can be an URI API call, appended to the fully qualified service name (separated by a forward slash) <3>
    rpc Increase (IncreaseValue) returns (google.protobuf.Empty);
    rpc Decrease (DecreaseValue) returns (google.protobuf.Empty);
    rpc Reset (ResetValue) returns (google.protobuf.Empty);
    rpc GetCurrentCounter (GetCounter) returns (CurrentCounter);
}
Enter fullscreen mode Exit fullscreen mode

Going from top to bottom, let me call out the critical parts, respective of our URI generation exercise.

  1. We pick up the first part of our fully qualified service name in the package line. In this case, as we start building our URI, /com.example starts us off!
  2. The second important line is the service CounterService one; it contains the structure of the API requests that are supported by the API service. To our fully qualified service name string, we will append the CounterService to form /com.example.CounterService. And as such, we're done with that.
  3. Onward to determining the method name. For each of the rpc lines, contained within the service, there will be an URI created, appending method to our fully qualified service name. What this looks like, would be a set of partial URIs:

    /com.example.CounterService/Increase
    /com.example.CounterService/Decrease
    /com.example.CounterService/Reset
    /com.example.CounterService/GetCurrentCounter
    

We're ready to go! Get me to Postman!

Well, not so fast. We know that the Always-on HTTP Transcoding feature in Akka Serverless is expecting a POST with a body, in JSON format, representing the API inputs. Where do we find these?

As you look back at the part of the protobuf file that had the method names, as marked by the rpc designation, you will notice that immediately after the method name, there is additional text, wrapped in parentheses. This is the input that the API method in question is expecting. Those input names, e.g. IncreaseValue, map to messages defined further up in the protobuf. And from those messages, we can determine the appropriate JSON to send in our API requests. We simply create a JSON attribute, with values matching the data type specified in the message. For example, message IncreaseValue:

message IncreaseValue {
    string counter_id = 1 [(akkaserverless.field).entity_key = true];
    int32 value = 2;
}
Enter fullscreen mode Exit fullscreen mode

The following JSON could be used as an input to our API request:

{"counter_id": "foo", "value": 1}
Enter fullscreen mode Exit fullscreen mode

Putting the two (URI and body) together, adding the hostname of the running service, we can build a curl command:

curl -XPOST -H "Content-Type: application/json" -d '{"counter_id": "foo", "value": 1}' https://nameless-thunder-9740.us-east1.akkaserverless.app/com.example.CounterService/Increase
Enter fullscreen mode Exit fullscreen mode

Now we're ready for Postman!

Creating HTTP Requests in Postman

Postman has great documentation and is a very intuitive application. So really, I'm not sure I need to lay out the steps to do this. But given that this approach is all about making everyday "normal" HTTP requests to a gRPC service/API, perhaps a quick run-through will be good.


NOTE

When you have to make a choice, blue pill or red...Wait. This isn't The Matrix! But with the recent beta release of gRPC support in Postman, you'll be tempted to pick that path when creating a new request. Don't! Choose HTTP Request!


Let's do this!

  1. If you don't have Postman installed on your machine, head here.
  2. Once you're ready, open up the Postman application.
  3. Click on New.

    Creating a new request in Postman

  4. Click on HTTP Request.

    Choosing request type

  5. Change HTTP Method from GET to POST.

  6. Fill in the Enter request URL text field with our API URI:

    https://nameless-thunder-9740.us-east1.akkaserverless.app/com.example.CounterService/Increase
    

    Your request should look like this now:

    Entering URI

  7. Click on Body.

  8. Click on raw.

    If you're not finding the above two, they're here:

    Adding body

  9. Fill in the large text area with the above POST body:

    {"counter_id": "foo", "value": 1}
    
  10. Change Text type to JSON.

    Changing content type

  11. Click Send.

  12. Profit!

Your Postman app should looking something like this. 200 OK, in green, means success!

Completed request

You can rinse-and-repeat the above steps for each of the four API requests defined the protobuf file. You can also access a fully-finished Postman Collection (a set of API requests) by clicking on the below button.

Run in Postman

Where to go next

If you're wanting to build out your first gRPC API (or just build more!), head to Akka Serverless to get a free account. Or if you want to read first, the docs are at https://developer.lightbend.com/docs/akka-serverless/quickstart/index.html.

Discussion (0)