Graphql相关的框架和The Graph的多链查询
前面已经部署好了graph-node和使用the graph client进行事件部署
Javascript Graphql相关的框架
- GraphQL Mesh https://the-guild.dev/graphql/mesh/docs
- GraphQL Yoga https://the-guild.dev/graphql/yoga-server/docs
- Apollo Server https://www.apollographql.com/docs/apollo-server/
相同点
- GraphQL 支持:所有三个框架都支持 GraphQL 查询和变更操作。
- 扩展性:都可以通过插件或自定义逻辑进行扩展。
- 多环境支持:都可以在多种环境中运行,如服务器、无服务器架构等。
不同点
- 数据源支持:GraphQL Mesh 支持多种非 GraphQL 数据源,而 Apollo Server 和 GraphQL Yoga 主要专注于 GraphQL 数据源。
- 设置和配置:GraphQL Yoga 提供开箱即用的默认配置,适合快速启动;Apollo Server 则更适合需要细粒度控制和生产环境的应用。
- 性能优化:GraphQL Yoga 强调性能优化,如缓存和持久化查询;Apollo Server 提供生产就绪的特性,适合大规模应用。
关于代码方面的不同点
- GraphQL Mesh:基本不用写代码,可以自动从多种数据源生成 schema。
- GraphQL Yoga:需要手动提供 schema,可以使用 codegen 根据schema生成代码,支持多种构建库,如 Pothos、GraphQL Nexus、gqtx 等,提供了灵活性和多样性。
- Apollo Server:需要手动编写 schema,可以使用 codegen 根据schema生成代码,但是实际的查询逻辑实现需要手写,适合需要精细控制和自定义的应用。它提供了强大的插件系统和广泛的社区支持,适合复杂的生产环境。
GraphQL Mesh 可以直接根据多种数据源(如 REST、gRPC、OpenAPI 等)自动生成 GraphQL schema。这使得它非常适合需要整合多个异构数据源的场景。
TIP
因为 the graph 的项目在我们部署好多个链对应的 graph node 之后,已经有了多个可以查询的节点, the graph 官方提供了 graph client 生成工具
首先,请确保在您的项目中安装 [The Graph Client CLI]:
shell
yarn add -D @graphprotocol/client-cli
# or, with NPM:
npm install --save-dev @graphprotocol/client-cli
创建一个配置文件(名为.graphclientrc.yml )并指向 The Graph 提供的 GraphQL 端点,例如:
点我查看 .graphclientrc.yml 代码
yaml
# .graphclientrc.yml
sources:
- name: uniswapv2
handler:
graphql:
endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2
# 需要安装额外的依赖,具体参考 https://the-guild.dev/graphql/mesh/docs/handlers/handlers-introduction
- name: postgres_db
handler:
postgraphile:
connectionString: postgres://dbuser:dbpwd@ip:54321/dbname
通过命令 graphclient build
直接从 endpoint 和 数据库🔗 读取元数据生成代码到项目根目录
使用 graphclient serve-dev
可以直接启动一个 graph-mesh 服务用于查询
项目集成
graph-mesh 官方还未提供将 graph-mesh 集成到 nestjs 使用的方法
1. 在 mesh.controller.ts 控制器中集成 createBuiltMeshHTTPHandler。
typescript
// mesh.controller.ts
import { Controller, All, Req, Res, Next } from '@nestjs/common';
import { createBuiltMeshHTTPHandler } from '../../.graphclient';
@Controller('graphql')
export class GraphqlController {
private meshHTTP: ReturnType<typeof createBuiltMeshHTTPHandler>;
constructor() {
this.meshHTTP = createBuiltMeshHTTPHandler();
}
@All('/')
async handleGraphQL(@Req() req: Request, @Res() res: Response) {
return this.meshHTTP(req, res);
}
}
2. 新建 mesh.module.ts, 将控制器添加到模块中。
typescript
// mesh.module.ts
import { Module } from '@nestjs/common';
import { GraphqlController } from "./mesh.controller";
@Module({
controllers: [GraphqlController],
})
export class GraphqlModule {}
3. 在 AppModule 中导入 GraphqlModule
typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphqlModule } from "./graph-mesh-support/mesh.module";
@Module({
imports: [GraphqlModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
现在通过 http://localhost:3000/graphql 应该可以访问到 graph-mesh 的服务
eg:
graphql
query MyQuery {
events(
first: 10
where: {or: [{to: "0x340a6fc05592aa06feff089d391269ad0a818c39"}, {from: "0x340a6fc05592aa06feff089d391269ad0a818c39"}]}
) {
id
price
from
to
}
}
附:Apollo Server 实现 graphQL 查询修改
typescript
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
const typeDefs = `#graphql
type Book {
title: String
author: String
}
type Query {
books: [Book]
transfers(where:String, first:Int): [Transfer]
}
type Mutation {
updateBook(title: String!, author: String!): Book
addBook(title: String!, author: String!): Book
}
`;
const books = [
{
title: 'The Awakening',
author: 'Kate Chopin',
},
{
title: 'City of Glass',
author: 'Paul Auster',
},
];
const resolvers = {
Query: {
books: () => books,
},
Mutation: {
updateBook: (_, { title, author }) => {
const book = books.find(book => book.title === title);
if (book) {
book.author = author;
}
return book;
},
addBook: (_, { title, author }) => {
const newBook = { title, author };
books.push(newBook);
return newBook;
}
}
};
const server = new ApolloServer({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
});
console.log(`🚀 Server ready at: ${url}`);