Skip to main content

RestAPI转为GraphQL的API

· 4 min read

实际上是把 RestAPI 作为 GraphQL 的数据源。官网的例子太复杂了,不适合初学者。而这篇博文就写得很好,阐明了如何创建 RestAPI 到转化为 GraphQL。

创建 RestAPI

仓库在

这里其实很简单,使用了jsonServer库,将一个Json的文件映射到路由上。

const jsonServer = require("json-server");
const server = jsonServer.create();
const router = jsonServer.router("db.json");
const middlewares = jsonServer.defaults();

server.use(middlewares);
server.use(router);
server.listen(process.env.PORT || 3000, () => {
console.log(
`🚀 JSON Server is running on port ${process.env.PORT || 3000}`
);
});

现在有这两个路由地址

http://localhost:3000/jokes
http://localhost:3000/ratings

甚至支持增删查改。

转为 GraphQL

仓库在

类型定义

const typeDefs = gql`
type Joke {
id: Int!
content: String!
ratings: [Rating]
}

type Rating {
id: Int!
jokeId: Int!
score: Int!
}

type Query {
joke(id: Int!): Joke
jokes: [Joke]
rating(id: Int!): Rating
ratings: [Rating]
}

type Mutation {
rating(jokeId: Int!, score: Int!): Rating
}
`;

这里值得看的是Mutation,但是我还没弄懂这里。

数据源

class JokesAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = "http://localhost:3000/";
}

async getJoke(id) {
return this.get(`jokes/${id}?_embed=ratings`);
}

async getJokes() {
return this.get("jokes?_embed=ratings");
}

async postJoke(jokeContent) {
return this.post("jokes", jokeContent);
}

async replaceJoke(joke) {
return this.put("jokes", joke);
}

async updateJoke(joke) {
return this.patch("jokes", { id: joke.id, joke });
}

async deleteJoke(id) {
return this.delete(`jokes/${id}`);
}
}

利用apollo-datasource-rest库,将 RestAPI 增删查改转为 JokesAPI 类的方法。

解析器 Resolver

const resolvers = {
Query: {
joke: async (_source, { id }, { dataSources }) =>
dataSources.jokesAPI.getJoke(id),
jokes: async (_source, _args, { dataSources }) =>
dataSources.jokesAPI.getJokes(),
rating: async (_source, { id }, { dataSources }) =>
dataSources.ratingsAPI.getRating(id),
ratings: async (_source, _args, { dataSources }) =>
dataSources.ratingsAPI.getRatings(),
},
Mutation: {
rating: async (_source, { jokeId, score }, { dataSources }) => {
const rating = await dataSources.ratingsAPI.postRating({
jokeId,
score,
});
return rating;
},
},
};

Query中定义的是四种能查询的数据,注意到这些数据都是来自数据源JokesAPIratingsAPI的。

获取数据的过程:当使用gql语句获取数据的时候,首先用解析器来解析。解析器下面的Query中是四种能解析的数据,而这四种能解析的数据的格式,由typeDefs中的Query来定义。实际上要获取的数据,是通过JokesAPIratingsAPI来拿到的,拿到的数据当然也符合定义。

启动服务器

先说启动最简单的服务器apollo-server

首先导入并且生成实例:

const { ApolloServer } = require("apollo-server");
const apollo_server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({
jokesAPI: new JokesAPI(),
ratingsAPI: new RatingsAPI(),
}),
});

然后启动这个服务器

apollo_server.listen(5000).then(() => {
console.log(`
Server is running!
Listening on http://localhost:5000
Explore at https://studio.apollographql.com/sandbox
`);
});

接着打开 apollo 的沙盒来预览

image-20211228154906524

注意到这里query下面根查询的两个对象,一个是jokes一个是joke,都是直接在typeDefs中的Query中定义的。

并且它还能使用一些变量,譬如上面的$jokeId$,这个变量的赋值可以在左下角中看到。

前端的话按照来配置即可,然后就能拿到对应的数据。

注意apollo-server库对应@apollo/client/core,而apollo-server-express库的作用是把GraphQL 再变成RestAPI发出去,这就让人难以捉摸。