How to Turn GraphQL into a High‑Performance Edge CDN Gateway

This article explains how to use GraphQL as a BFF gateway, migrate Apollo Server to Alibaba Cloud EdgeRoutine's serverless environment, implement CDN edge caching for query requests, and build a complete weather‑query demo with TypeScript, GraphQL SDL, resolvers, and Playground debugging.

Alibaba Terminal Technology
Alibaba Terminal Technology
Alibaba Terminal Technology
How to Turn GraphQL into a High‑Performance Edge CDN Gateway

Introduction

If you are not familiar with GraphQL, you can start with the team’s lectures and articles.

GraphQL official site: https://graphql.cn/

Apollo official site: https://apollographql.com/

Our CCO technology department has adopted GraphQL as the sole standard for describing, exposing, and invoking APIs internally and externally. Major companies like Facebook, Netflix, GitHub, PayPal, Microsoft, Volkswagen, and Walmart also use GraphQL at scale.

1. GraphQL as a Gateway Layer

We consider GraphQL most suitable as a BFF (Backend for Frontend) gateway, aggregating raw HSF interfaces and third‑party RESTful APIs into a Service Façade layer. Its characteristics make it easy to integrate with existing HTTP‑based gateways and to serve as a Serverless/FaaS gateway with a single HTTP trigger.

1.2 GraphQL Gateway and CDN Edge Computing

EdgeRoutine is Alibaba Cloud CDN’s new Serverless platform that provides a ServiceWorker‑like container, leveraging global CDN nodes for high‑availability, high‑performance distributed computing. It is currently free and in trial, with a public release planned for early September.

Query‑type requests dominate traffic, yet each request still hits the backend service even though the data rarely changes.

We propose using EdgeRoutine as a proxy for GraphQL query requests: the first query goes through the CDN to the GraphQL gateway, then to the backend service, and the response is cached at the CDN. Subsequent requests can be served from cache based on TTL rules, dramatically reducing QPS on the origin service.

2. Porting Apollo GraphQL Server to EdgeRoutine

Apollo Server is the most widely used open‑source GraphQL server, but its Node.js version cannot run directly in EdgeRoutine’s ServiceWorker environment. We created apollo-server-edge-routine to adapt it.

2.1 Build TypeScript Development Environment and Scaffold

We set up a TypeScript environment for EdgeRoutine, using a ServiceWorker TypeScript library, Webpack for local debugging, and hot‑reload via WebSocket.

2.2 Implement Custom ApolloServer for EdgeRoutine

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));
        }
      }
    });
  }
}

2.3 Implement handleGraphQLRequest

import { GraphQLOptions, GraphQLRequest } from 'apollo-server-core';
import { ApolloServer } from './ApolloServer';
/** Parse HTTP request into GraphQL query, execute, and return response */
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 Demo

3.1 What We Build

We wrap the third‑party weather service (tianqiapi.com) with a GraphQL CDN gateway. The free tier limits QPS to 300 per day, so we cache the first successful query per city at the CDN edge.

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 OK

Example 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 must include the EdgeRoutine lib and types:

{
  "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 must polyfill Node.js modules such as assert, buffer, crypto-browserify, etc.

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' } }));
  }
}

3.9 Full Project Code

All code will be open‑sourced on the author’s GitHub after EdgeRoutine’s official release.

Future Outlook

We plan to use EdgeRoutine’s KV database to cache query results and automatically invalidate caches on mutations by leveraging GraphQL’s type‑level IDs. More details can be found in the video at graphcdn.io.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ServerlessTypeScriptEdge ComputingCDNGraphQLApollo Server
Alibaba Terminal Technology
Written by

Alibaba Terminal Technology

Official public account of Alibaba Terminal

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.