How to Deploy GraphQL as a BFF Gateway on Alibaba Cloud EdgeRoutine
This article explains how to use GraphQL as a Backend‑for‑Frontend gateway on Alibaba Cloud EdgeRoutine, covering the migration of Apollo Server, TypeScript setup, CDN edge caching, resolver implementation, and adding a Playground debugger, with full code examples and deployment tips.
1. Introduction
If you are unfamiliar with GraphQL, you can start with the resources listed below:
Official website: GraphQL CN
Apollo: Apollo GraphQL
Lecture & Demo (Session 3): Control Your Tesla with GraphQL
Technical articles:
GraphQL and Apollo workflow
Replace Redux with GraphQL and Apollo?
TypeScript + GraphQL = TypeGraphQL
Data export based on GraphQL
After four years of effort, GraphQL has become the sole standard for API description, exposure, and invocation in our CCO technology department. Companies such as Facebook, Netflix, GitHub, PayPal, Microsoft, Volkswagen, and Walmart also use GraphQL at large scale, and Apollo secured $130 million in Series D funding. A global front‑end developer survey shows GraphQL as the most interested technology to learn.
1.2 GraphQL Gateway and CDN Edge Computing
EdgeRoutine is Alibaba Cloud CDN's new Serverless platform. It provides a ServiceWorker‑like container that leverages global CDN nodes for distributed elastic computing. It is completely free for internal users (still in trial) and will be officially released in early September.
Query‑type requests constitute a large proportion of traffic, yet they often return data that changes rarely or never. Sending each request to the backend server is inefficient.
We propose using CDN EdgeRoutine as a proxy layer for GraphQL query requests. The first query is forwarded to the GraphQL gateway, which then calls the backend service (e.g., via HSF). The response is cached at the CDN edge, and subsequent identical queries can be served from cache based on TTL rules, dramatically reducing QPS on the origin application.
2. Porting Apollo GraphQL Server
2.1 Build TypeScript Development Environment and Scaffold
We create a TypeScript environment for EdgeRoutine using a custom TypeScript definition library and a local simulator. Webpack serves as the dev server, and ServiceWorker APIs provide hot‑reload capabilities.
2.2 Implement ApolloServer for EdgeRoutine
Apollo does not provide documentation for EdgeRoutine, but by extending ApolloServerBase we can add a listen(path: string) method that registers a fetch event listener.
import { ApolloServerBase } from 'apollo-server-core';
import { handleGraphQLRequest } from './handlers';
/** Apollo GraphQL Server implementation on EdgeRoutine. */
export class ApolloServer extends ApolloServerBase {
/** Listen for GraphQL POST requests on the specified path. */
async listen(path = '/graphql') {
this.assertStarted('listen');
addEventListener('fetch', async (event: FetchEvent) => {
const { request } = event;
if (request.method === 'POST') {
const url = new URL(request.url);
if (url.pathname === path) {
const options = await this.graphQLServerOptions();
event.respondWith(handleGraphQLRequest(this, request, options));
}
}
});
}
}The handleGraphQLRequest function parses the HTTP request body, executes the GraphQL operation, and returns a JSON response while preserving any HTTP headers.
import { GraphQLOptions, GraphQLRequest } from 'apollo-server-core';
import { ApolloServer } from './ApolloServer';
export async function handleGraphQLRequest(
server: ApolloServer,
request: Request,
options: GraphQLOptions
): Promise<Response> {
let gqlReq: GraphQLRequest;
try {
gqlReq = await request.json();
} catch (e) {
throw new Error('Error occurred when parsing request body to JSON.');
}
const gqlRes = await server.executeOperation(gqlReq);
const response = new Response(JSON.stringify({ data: gqlRes.data, errors: gqlRes.errors }), {
headers: { 'content-type': 'application/json' },
});
for (const [key, value] of Object.entries(gqlRes.http.headers)) {
response.headers.set(key, value);
}
return response;
}3. Simple Weather Query GraphQL CDN Proxy Example
3.1 What We Do
We wrap the third‑party weather service (tianqiapi.com) with a GraphQL CDN gateway. The free tier allows 300 QPS per day, so we cache the first request for a city and serve subsequent requests from CDN.
3.2 Weather API Overview
Example request:
Request URL: https://www.tianqiapi.com/free/day?appid={APP_ID}&appsecret={APP_SECRET}&city=%E5%8D%97%E4%BA%AC
Request Method: GET
Status Code: 200 OKExample response (JSON):
{
"air": "94",
"city": "南京",
"cityid": "101190101",
"tem": "31",
"tem_day": "31",
"tem_night": "24",
"update_time": "14:12",
"wea": "多云",
"wea_img": "yun",
"win": "东南风",
"win_meter": "9km/h",
"win_speed": "2级"
}3.3 Define GraphQL SDL
type Query {
versions: Versions!
weatherOfCity(name: String!): Weather!
}
type City {
id: ID!
name: String!
}
type Versions {
api: String!
graphql: String!
}
type Weather {
city: City!
updateTime: String!
code: String!
localized: String!
tempOfDay: Float!
tempOfNight: Float!
}3.4 Implement Resolvers
import { version as graphqlVersion } from 'graphql';
import { apiVersion } from '../api-version';
import { fetchWeatherOfCity } from '../tianqi-api';
export function versions() {
return { api: apiVersion, graphql: graphqlVersion };
}
export async function weatherOfCity(parent, args: { name: string }) {
const raw = await fetchWeatherOfCity(args.name).then(res => res.json());
return {
city: { id: raw.cityid, name: raw.city },
updateTime: raw.update_time,
code: raw.wea_img,
localized: raw.wea,
tempOfDay: raw.tem_day,
tempOfNight: raw.tem_night,
};
}3.5 Create and Start Server
import { ApolloServer } from '@ali/apollo-server-edge-routine';
import typeDefs from '../graphql/schema.graphql';
import * as resolvers from '../resolvers';
const server = new ApolloServer({ typeDefs, resolvers });
server.start().then(() => server.listen());3.6 Build Configuration
tsconfig.json:
{
"compilerOptions": {
"alwaysStrict": true,
"esModuleInterop": true,
"lib": ["esnext", "webworker"],
"module": "esnext",
"moduleResolution": "node",
"outDir": "./dist",
"preserveConstEnums": true,
"removeComments": true,
"sourceMap": true,
"strict": true,
"target": "esnext",
"types": ["@ali/edge-routine-types"]
},
"include": ["src"],
"exclude": ["node_modules"]
}Webpack fallback for Node polyfills:
resolve: {
fallback: {
assert: require.resolve('assert/'),
buffer: require.resolve('buffer/'),
crypto: require.resolve('crypto-browserify'),
os: require.resolve('os-browserify/browser'),
stream: require.resolve('stream-browserify'),
zlib: require.resolve('browserify-zlib'),
util: require.resolve('util/')
}
}3.7 Add CDN Cache
export async function fetchWeatherOfCity(city: string) {
const url = new URL('http://www.tianqiapi.com/free/day');
url.searchParams.set('appid', '23035354');
url.searchParams.set('appsecret', '8YvlPNrz');
url.searchParams.set('city', city);
const urlString = url.toString();
if (isCacheSupported()) {
const cached = await cache.get(urlString);
if (cached) return cached;
}
const response = await fetch(urlString);
if (isCacheSupported()) cache.put(urlString, response);
return response;
}3.8 Add Playground Debugger
addEventListener('fetch', (event) => {
const response = handleRequest(event.request);
if (response) event.respondWith(response);
});
function handleRequest(request: Request): Promise<Response> | void {
const url = new URL(request.url);
const path = url.pathname;
if (request.method === 'GET' && path === '/graphql') {
return Promise.resolve(new Response(rawPlaygroundHTML, { status: 200, headers: { 'content-type': 'text/html' } }));
}
}4. Looking Ahead
The demo does not yet show a secondary GraphQL proxy layer, but you can watch a video at graphcdn.io for more details. Future work includes using CDN edge KV storage to cache query results and automatically invalidate caches when mutations affect related entities.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Taobao Frontend Technology
The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
