GRPC Playground logo

Backstage GRPC Playground Plugin

Created by Zalopay-OSS

gRPC Playground gives engineers a simple way to explore and call gRPC services from the browser. It is a GUI client that lives inside Backstage. Point it at your protobuf files, see the service methods, craft requests, then send them. You can try unary calls, stream requests, or stream responses. You can view docs generated from your protos too. The backend handles requests and supports TLS, so you can test real services in a safe way.

The Backstage plugin adds this workflow to your service catalog. Teams keep proto files next to the code that owns them. The plugin reads those definitions and turns them into an interactive client and a readable reference. Use it to verify a new API before building a client. Use it during development to debug message shapes. Use it to share a repeatable request with a teammate or with another team.

If you run a self hosted Backstage and you ship gRPC, this plugin helps you test calls faster, keep docs close, and reduce tool switching.

Installation Instructions

These instructions apply to self-hosted Backstage only.

Install the frontend package

Run this from your Backstage project root

Copy
yarn --cwd packages/app add backstage-grpc-playground

Add the gRPC widget to ApiDocs

This replaces the default ApiDocs widget for entities with type grpc

Copy
// packages/app/src/apis.ts
import { AnyApiFactory, createApiFactory } from '@backstage/core-plugin-api';
import { apiDocsConfigRef, defaultDefinitionWidgets } from '@backstage/plugin-api-docs';
import { ApiEntity } from '@backstage/catalog-model';
import { GrpcPlaygroundComponent } from 'backstage-grpc-playground';

// keep your other imports

export const apis: AnyApiFactory[] = [
  // keep your existing api factories

  createApiFactory({
    api: apiDocsConfigRef,
    deps: {},
    factory: () => {
      const definitionWidgets = defaultDefinitionWidgets();

      return {
        getApiDefinitionWidget: (apiEntity: ApiEntity) => {
          if (apiEntity.spec.type === 'grpc') {
            return {
              type: 'grpc',
              title: 'gRPC Playground',
              component: GrpcPlaygroundComponent,
            };
          }

          return definitionWidgets.find(d => d.type === apiEntity.spec.type);
        },
      };
    },
  }),
];

Add a standalone page

This gives you a page at path /grpc-playground

Copy
// packages/app/src/App.tsx
import React from 'react';
import { FlatRoutes } from '@backstage/core-app-api';
import { Route } from 'react-router-dom';
import { GrpcPlaygroundPage } from 'backstage-grpc-playground';

// keep your other imports

export default function App() {
  return (
    <FlatRoutes>
      {/* keep your existing routes */}

      <Route path="/grpc-playground" element={<GrpcPlaygroundPage />} />
    </FlatRoutes>
  );
}

Install the backend package for the legacy backend system

The backend plugin handles proto files and request execution

Copy
yarn --cwd packages/backend add backstage-grpc-playground-backend

Create a backend plugin module that exposes the router

Copy
// packages/backend/src/plugins/grpcPlayground.ts
import { Router } from 'express';
import { Logger } from 'winston';
import { PluginEnvironment } from '../types';
import { createRouter } from 'backstage-grpc-playground-backend';

// add imports your backend already uses such as Config if needed

export default async function createPlugin(
  env: PluginEnvironment,
): Promise<Router> {
  // Many Backstage backend routers only need logger and config
  // Add other env fields if your TypeScript compiler requests them
  return await createRouter({
    logger: env.logger as Logger,
    config: env.config,
  });
}

Wire it into the backend HTTP router

Copy
// packages/backend/src/index.ts
import grpcPlayground from './plugins/grpcPlayground';

// keep your existing imports and bootstrap code

async function main() {
  // keep your existing env creation
  const grpcEnv = useHotMemoize(module, () => createEnv('grpc-playground'));

  // keep your existing apiRouter
  apiRouter.use(
    '/grpc-playground',
    await grpcPlayground(grpcEnv),
  );

  // keep your existing server start
}

Your backend routes will be served under /api/grpc-playground if you mount apiRouter under /api in your app server

Install the backend package for the new backend system

At the time of writing the backend package targets the legacy backend system. If your app uses the new backend system you can still mount the Express router. Create a small module that calls createRouter from the backend package and mounts it on the http router at /grpc-playground. Use the same logger and config services you already pass to other routers in your new backend. Keep the mount path consistent with the legacy example

Provide proto files to the backend

The backend plugin looks for proto files on the backend side. The default location is the proto folder in packages/backend. Add your proto files here

Copy
packages
  backend
    proto
      your files go here

You can also keep common google proto files under a subfolder if your protos import them

Define a gRPC API entity

Add an API entity with type grpc. Put the YAML below in a catalog file that your Backstage catalog loads

This example shows the structure supported by the plugin. Replace the file names and URLs with your own. You can also use file paths relative to your repo if you serve them from source

Copy
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
  name: my-grpc-service
  description: Example gRPC API
spec:
  type: grpc
  lifecycle: experimental
  owner: team-a
  definition: |
    files:
      - file_name: hello.proto
        url: https://raw.githubusercontent.com/org/repo/main/protos/hello.proto
        imports:
          - file_name: common.proto
            url: https://raw.githubusercontent.com/org/repo/main/protos/common.proto
    imports:
      - file_name: timestamp.proto
        url: https://raw.githubusercontent.com/protocolbuffers/protobuf/main/src/google/protobuf/timestamp.proto
    libraries:
      - name: google-apis
        path: packages/backend/proto/google

Notes

  • files is a list of proto files used by this API
  • Each file can list its own imports if it depends on other protos
  • imports at the root are common imports shared across files
  • libraries lets you point to a local folder with pre collected proto definitions such as google APIs

Use the plugin in Backstage

  • Open an API entity with type grpc in the ApiDocs page. The page shows the gRPC Playground widget
  • Or go to /grpc-playground to use the standalone page

You can upload missing imports from the UI if the plugin asks for them. TLS for requests is supported from the UI

Tips when calls fail due to missing imports

  • If a proto imports another local file upload the folder that contains both files
  • If a proto imports google APIs add a google folder with the needed protos under packages /backend/proto then reference it using the libraries field as shown above

Changelog

The GRPC Playground plugin has not seen any significant changes since a year ago.

Set up Backstage in minutes with Roadie