无法获取默认的Apollo服务器缓存

时间:2019-07-05 16:44:53

标签: node.js caching graphql apollo-server

我实现了RESTDataSource,但是当我在操场上尝试查询时,相同的查询永远不会被缓存,并且总是从REST端点获取。

这些教程说,使用RESTDataSource时,基本的缓存系统无需额外配置即可工作,但显然我缺少一些东西。什么会使缓存失败?

我的ApolloServer创建:

/* ... */
const server = new ApolloServer({
    typeDefs,
    resolvers,
    dataSources: () => ({
        comicVineAPI: new ComicVineAPI(),
        firebaseAPI: new FirebaseAPI(getFirestore())
    })
});
/* ... */

我对REST端点的调用(在我的API类中扩展了RESTDataSource):

/* ... */
async request(path, params = {}) {
    params.format = 'json';
    params.limit = 50;
    params.api_key = process.env.COMIC_VINE_API_KEY;
    const response = await this.get(`${path}?${this.buildQuery(params)}`);
    return response.status_code === 1 && response;
}
/* ... */

谢谢您的帮助!

1 个答案:

答案 0 :(得分:0)

未缓存REST API响应的原因可能是上游Web服务没有缓存头:cache-control 。您可以阅读本文Layering GraphQL on top of REST以了解更多信息。

对于数据源,HTTP请求将根据REST API响应中返回的缓存标头自动缓存

知道这一点后,我举了一个例子:

rest-api-server.ts

import express from 'express';
import faker from 'faker';

function createServer() {
  const app = express();
  const port = 3000;

  app.get('/user', (req, res) => {
    res.sendFile('index.html', { root: __dirname });
  });

  app.get('/api/user', (req, res) => {
    console.log(`[${new Date().toLocaleTimeString()}] request user`);
    const user = { name: faker.name.findName(), email: faker.internet.email() };
    res.set('Cache-Control', 'public, max-age=30').json(user);
  });

  app.get('/api/project', (req, res) => {
    console.log(`[${new Date().toLocaleTimeString()}] request project`);
    const project = { name: faker.commerce.productName() };
    res.json(project);
  });
  return app.listen(port, () => {
    console.log(`HTTP server is listening on http://localhost:${port}`);
  });
}

if (require.main === module) {
  createServer();
}

export { createServer };

graphql-server.ts

import { ApolloServer, gql } from 'apollo-server-express';
import { RESTDataSource } from 'apollo-datasource-rest';
import express from 'express';
import { RedisCache } from 'apollo-server-cache-redis';
import { Request } from 'apollo-server-env';

class MyAPI extends RESTDataSource {
  constructor() {
    super();
    this.baseURL = 'http://localhost:3000/api/';
  }
  public async getUser() {
    return this.get('user');
  }
  public async getProject() {
    return this.get('project');
  }
  protected cacheKeyFor(request: Request) {
    return request.url;
  }
}

const typeDefs = gql`
  type User {
    name: String
    email: String
  }
  type Project {
    name: String
  }
  type Query {
    user: User
    project: Project
  }
`;

const resolvers = {
  Query: {
    user: async (_, __, { dataSources: ds }: IAppContext) => {
      return ds.myAPI.getUser();
    },
    project: async (_, __, { dataSources: ds }: IAppContext) => {
      return ds.myAPI.getProject();
    },
  },
};

const dataSources = () => ({
  myAPI: new MyAPI(),
});

interface IAppContext {
  dataSources: ReturnType<typeof dataSources>;
}

const app = express();
const port = 3001;
const graphqlPath = '/graphql';
const server = new ApolloServer({
  typeDefs,
  resolvers,
  dataSources,
  cache: new RedisCache({
    port: 6379,
    host: '127.0.0.1',
    family: 4,
    db: 0,
  }),
});

server.applyMiddleware({ app, path: graphqlPath });

if (require.main === module) {
  app.listen(port, () => {
    console.log(`Apollo server is listening on http://localhost:${port}${graphqlPath}`);
  });
}

rest-api-server.ts的日志:

HTTP server is listening on http://localhost:3000
[2:21:11 PM] request project
[2:21:14 PM] request project
[2:21:25 PM] request user

对于/api/user,我为其设置了cache-control响应头。因此,当您向graphql-server.ts发送graphql请求时,MyAPI数据源将发送 对REST API的请求。从REST API获得响应后,它将检测到cache-control响应标头,因此apollo数据源将缓存响应。 在缓存过期之前,对graphql服务器的以下请求将命中缓存。

发送graphql请求后,检查Redis实例中的缓存:

root@d78b7c9e6ac2:/data# redis-cli
127.0.0.1:6379> keys *
1) "httpcache:http://localhost:3000/api/user"
127.0.0.1:6379> ttl httpcache:http://localhost:3000/api/user
(integer) -2
127.0.0.1:6379> keys *
(empty list or set)

对于/api/project由于缺少缓存头,阿波罗数据源将不会缓存响应。因此,每次发送graphql请求时,它都会调用REST API。

发送graphql请求后,检查Redis实例中的缓存:

127.0.0.1:6379> keys *
(empty list or set)

P.S。如果您的REST API位于Nginx服务器之后,则应在Nginx服务器上启用缓存控制。

源代码:https://github.com/mrdulin/apollo-graphql-tutorial/tree/master/src/rest-api-caching