Skip to content

Protobuf & TypeScript

Protobuf is the recommended format for applications. Compact binary messages reduce data transfer, and generated encoders and decoders process them efficiently. Generate the client once during development, then use typed requests and responses in your app.

Save these four files together in your project’s proto/ directory:

2. Generate the client and TypeScript types

Section titled “2. Generate the client and TypeScript types”

Install the runtime and development tools:

Terminal window
npm install protobufjs
npm install --save-dev protobufjs-cli typescript
mkdir -p src/generated

Run these commands from your project directory:

Terminal window
npx pbjs -t static-module -w es6 -o src/generated/planner.js proto/PlanRequest.proto proto/PlanResult.proto proto/Modes.proto proto/DirectionType.proto
npx pbts -o src/generated/planner.d.ts src/generated/planner.js

You now have:

FilePurpose
src/generated/planner.jsEncodes requests and decodes responses
src/generated/planner.d.tsTypeScript types and editor autocomplete

This setup suits a browser application using a bundler such as Vite. Include both generated files in your project. The app uses the generated JavaScript at runtime; the .proto files are inputs to the generation step.

Regenerate both files when you update the schemas. You can add the two commands to a generate:proto script in your package.json.

import { planner } from "./generated/planner";
const input: planner.IPlanRequest = {
fromPlace: "52.0894,5.1102",
toPlace: "52.0925,5.1813",
timestamp: new Date().toISOString(),
timeSlack: 0,
userPreferences: {
walkingSpeed: planner.UserSpeed.AVERAGE,
bikingSpeed: planner.UserSpeed.AVERAGE,
},
};
const request = planner.PlanRequest.create(input);
const bytes = planner.PlanRequest.encode(request).finish();

Use generated enum constants for modes, speeds and travel class. For example, planner.model.enumerations.TransitMode.RAIL selects the rail enum value.

Connect to the public Infoplaza endpoint with your api_key. Protobuf is the default; mode=proto is optional. See API-key setup. Set binaryType so the browser delivers binary frames as an ArrayBuffer.

const endpoint = new URL("wss://api.infoplaza.com/v1/transit/implanner");
endpoint.searchParams.set("api_key", INFOPLAZA_API_KEY); // From your app configuration
const socket = new WebSocket(endpoint);
socket.binaryType = "arraybuffer";
socket.addEventListener("open", () =>
socket.send(new Uint8Array(bytes).buffer),
);
socket.addEventListener("message", (event) => {
if (typeof event.data === "string") {
const message = JSON.parse(event.data);
if (message.type === "error") {
console.error(message.payload.message);
}
return;
}
const result = planner.model.PlanResult.decode(new Uint8Array(event.data));
for (const trip of result.trips) {
console.log(trip.duration, trip.legs);
}
});

Each binary frame contains one PlanResult. Keep listening for more journeys until the search completes. See the complete first request and connection lifecycle.

The recipe pages use readable enum names. Convert a recipe’s payload to a Protobuf message with fromObject:

const request = planner.PlanRequest.fromObject(recipe.payload);
const bytes = planner.PlanRequest.encode(request).finish();

To turn a decoded result into a plain object with named enums:

const object = planner.model.PlanResult.toObject(result, {
enums: String,
longs: String,
defaults: false,
});

For a JSON connection, send { type: 'planTrip', payload: input } as text and parse each response with JSON.parse. Both connections use text JSON envelopes for server errors.

The generation commands use the official protobufjs CLI. A downloadable Node.js client is also available.