Cloudflare Workers-based backend-for-frontend (BFF) that exposes a GraphQL API backed by the upstream gRPC-Web service defined by GRPC_TARGET_ORIGIN. GraphQL resolvers translate queries into protobuf payloads generated from proto/stationapi.proto, forward them via gRPC-Web, and map responses back into the GraphQL schema. Development, testing, and deployment rely on Wrangler v4 and Vitest.
- Node.js 18 or later
- npm, pnpm, or another Node.js package manager
- Cloudflare account (required for deployment)
Wrangler is bundled as a devDependency, so npx wrangler works without a global install.
npm installGRPC_TARGET_ORIGIN(required): Origin of the upstream gRPC-Web endpoint, for examplehttps://grpc.example.com. The worker returns HTTP 500 if this value is missing or invalid.GRPC_ALLOWED_ORIGINS(optional): Comma-separated list of origins allowed via CORS. Omit to allow all origins.
For local development set these in .dev.vars or the vars section of wrangler.jsonc. Configure environment-specific values before deploying.
npm run dev- Runs
wrangler devand exposes the worker athttp://localhost:8787/. - The
compatibility_dateis2025-10-11; update it when adopting newer runtime capabilities.
- GraphQL endpoint is exposed at
/graphql(POSTfor queries,GETreturns the SDL). - The runtime schema is declared in
schema.graphqland mirrored insrc/graphqlGateway.ts. POSTalso accepts Apollo ClientBatchHttpLinkpayloads such as[{ query, variables, operationName }], returning results in the same order as received.- Supported queries include:
station(id: Int!)— UsesGetStationByIdRPCstations(ids: [Int!]!)— UsesGetStationByIdListRPCstationsNearby(latitude: Float!, longitude: Float!, limit: Int)— UsesGetStationsByCoordinatesRPCstationsByName(name: String!, limit: Int, fromStationGroupId: Int)— UsesGetStationsByNameRPCstationGroupStations(groupId: Int!)— UsesGetStationByGroupIdRPClineGroupStations(lineGroupId: Int!)— UsesGetStationsByLineGroupIdRPCline(lineId: Int!)— UsesGetLineByIdRPClinesByName(name: String!, limit: Int)— UsesGetLinesByNameRPClineStations(lineId: Int!, stationId: Int)— UsesGetStationsByLineIdRPCstationTrainTypes(stationId: Int!)— UsesGetTrainTypesByStationIdRPCroutes(fromStationGroupId: Int!, toStationGroupId: Int!, pageSize: Int, pageToken: String)— UsesGetRoutesMinimalRPC (optimized with deduplicated line data)routeTypes(fromStationGroupId: Int!, toStationGroupId: Int!, pageSize: Int, pageToken: String)— UsesGetRouteTypesRPCconnectedRoutes(fromStationGroupId: Int!, toStationGroupId: Int!)— UsesGetConnectedRoutesRPC
The routes query uses the GetRoutesMinimal RPC which returns normalized/deduplicated line data for efficient transmission. The BFF automatically reconstructs full Station objects by resolving line references.
Customize or extend the schema by editing schema.graphql and updating the resolvers in src/graphqlGateway.ts.
query Example($from: Int!, $to: Int!) {
routes(fromStationGroupId: $from, toStationGroupId: $to, pageSize: 10) {
routes {
id
stops {
id
name
}
}
nextPageToken
}
}npm test- Uses
cloudflare/testand@cloudflare/vitest-pool-workersto exercise the Worker in a production-like environment, including gRPC-Web framing, CORS handling, and GraphQL execution.
npm run deploy- Run
npx wrangler loginthe first time to authenticate with Cloudflare. - Ensure
GRPC_TARGET_ORIGIN,GRPC_ALLOWED_ORIGINS, and any additional bindings are defined for the target environment prior to deployment.
npm run cf-typegen- Wrangler refreshes
worker-configuration.d.tsso theEnvtypes stay aligned with your bindings.
npm run proto:generate- Compiles
proto/stationapi.prototosrc/generated/stationapi.jsandsrc/generated/stationapi.d.tsusingprotobufjs. - Re-run tests afterwards to ensure the GraphQL↔gRPC translations still behave as expected.
src/index.ts— Worker entry point delegating requests to the GraphQL gateway.src/graphqlGateway.ts— GraphQL schema/resolver wiring, CORS handling, and gRPC-Web invocation helpers.src/generated/stationapi.js— ProtobufJS static module generated fromproto/stationapi.proto.proto/stationapi.proto— Source protocol buffer definitions for the upstream service.schema.graphql— SDL representation of the public GraphQL schema.test/index.spec.ts— Vitest suite covering GraphQL queries and gRPC-Web interactions.vitest.config.mts— Vitest configuration targeting the Workers pool.wrangler.jsonc— Worker metadata, compatibility date, and development/deployment settings.
This project is released under the MIT License.
