基于 Hapi 框架的 GraphQL 实践分享

前言

GraphQL 是一种用于 API 设计的查询语言和运行时。Hapi 是一个 Node.js 的 web 框架,具有高度的可扩展性和定制性。结合使用 Hapi 和 GraphQL 可以构建出高效、可靠的 API 服务。

本文将介绍如何在 Hapi 框架中使用 GraphQL,包括安装和配置,以及 GraphQL 的基本语法和实践案例。文章旨在提供深度的学习和指导意义。

安装和配置

在开始之前,首先需要安装 Hapi 和相关的插件。具体步骤如下:

  1. 安装 Hapi

  2. 安装 GraphQL 协议插件

  3. 安装 GraphQL 解析器插件

GraphQL 的基本语法

GraphQL 有三种类型的操作:查询、变异和订阅。我们将重点介绍查询操作,其中最基本的查询语句如下:

其中,FIELD_NAME 是你要查询的字段名。如果需要传入参数,则可以在 FIELD_NAME 后跟上参数列表,例如:

上述代码将查询 id 为 123 的用户的名字和邮箱地址。

如果需要查询多个字段,则可以使用花括号包含多个子查询:

上述代码将查询 id 为 123 的用户的名字和邮箱,以及作者 id 为 123 的所有文章的标题和内容。

实践案例

下面是一个基于 Hapi 和 GraphQL 的实践案例。假设我们要构建一个简单的图书管理系统,包括书籍、作者和出版商三个实体。我们需要能够查询书籍、作者和出版商的信息,以及根据不同条件获取它们的列表。

数据模型

首先,我们需要定义数据模型。我们可以使用 MongoDB 或其他数据库管理系统存储数据。下面是一个简单的 MongoDB Schema 定义:

const mongoose = require('mongoose');

const BookSchema = mongoose.Schema({
    title: String,
    author: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Author'
    },
    publisher: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Publisher'
    }
});

const AuthorSchema = mongoose.Schema({
    name: String,
    books: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Book'
    }]
});

const PublisherSchema = mongoose.Schema({
    name: String,
    books: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Book'
    }]
});

const BookModel = mongoose.model('Book', BookSchema);
const AuthorModel = mongoose.model('Author', AuthorSchema);
const PublisherModel = mongoose.model('Publisher', PublisherSchema);

module.exports = {
    BookModel,
    AuthorModel,
    PublisherModel
};

GraphQL Schema

然后,我们可以使用 GraphQL 构建数据查询模式。下面是一个简单的查询模式定义:

const {
    GraphQLObjectType,
    GraphQLSchema,
    GraphQLList,
    GraphQLID,
    GraphQLString
} = require('graphql');
const {
    BookModel,
    AuthorModel,
    PublisherModel
} = require('./models');

const BookType = new GraphQLObjectType({
    name: 'Book',
    fields: {
        id: { type: GraphQLID },
        title: { type: GraphQLString },
        author: {
            type: AuthorType,
            async resolve(parent, args) {
                return await AuthorModel.findById(parent.author);
            }
        },
        publisher: {
            type: PublisherType,
            async resolve(parent, args) {
                return await PublisherModel.findById(parent.publisher);
            }
        }
    }
});

const AuthorType = new GraphQLObjectType({
    name: 'Author',
    fields: {
        id: { type: GraphQLID },
        name: { type: GraphQLString },
        books: {
            type: new GraphQLList(BookType),
            async resolve(parent, args) {
                return await BookModel.find({ author: parent.id });
            }
        }
    }
});

const PublisherType = new GraphQLObjectType({
    name: 'Publisher',
    fields: {
        id: { type: GraphQLID },
        name: { type: GraphQLString },
        books: {
            type: new GraphQLList(BookType),
            async resolve(parent, args) {
                return await BookModel.find({ publisher: parent.id });
            }
        }
    }
});

const RootQuery = new GraphQLObjectType({
    name: 'RootQueryType',
    fields: {
        books: {
            type: new GraphQLList(BookType),
            args: {
                id: { type: GraphQLID },
                title: { type: GraphQLString },
                author: { type: GraphQLID },
                publisher: { type: GraphQLID }
            },
            async resolve(parent, args) {
                const query = {};
                if (args.id) {
                    query._id = args.id;
                }
                if (args.title) {
                    query.title = args.title;
                }
                if (args.author) {
                    query.author = args.author;
                }
                if (args.publisher) {
                    query.publisher = args.publisher;
                }
                return await BookModel.find(query);
            }
        },
        authors: {
            type: new GraphQLList(AuthorType),
            args: {
                id: { type: GraphQLID },
                name: { type: GraphQLString }
            },
            async resolve(parent, args) {
                const query = {};
                if (args.id) {
                    query._id = args.id;
                }
                if (args.name) {
                    query.name = args.name;
                }
                return await AuthorModel.find(query);
            }
        },
        publishers: {
            type: new GraphQLList(PublisherType),
            args: {
                id: { type: GraphQLID },
                name: { type: GraphQLString }
            },
            async resolve(parent, args) {
                const query = {};
                if (args.id) {
                    query._id = args.id;
                }
                if (args.name) {
                    query.name = args.name;
                }
                return await PublisherModel.find(query);
            }
        }
    }
});

const schema = new GraphQLSchema({
    query: RootQuery
});

module.exports = schema;

上述代码定义了三种类型:BookType、AuthorType 和 PublisherType,并通过 RootQuery 将它们关联起来。在 RootQuery 中,我们还定义了三个查询调用 books、authors 和 publishers 来获取列表。

Hapi Server

最后,我们将 GraphQL Schema 和 Hapi Server 整合在一起。下面是一个简单的 Hapi 服务器实现:

const Hapi = require('hapi');
const { graphqlHapi } = require('hapi-graphql');
const { connect } = require('mongoose');
const schema = require('./schema');

const server = new Hapi.Server({
    host: 'localhost',
    port: 8000
});

connect('mongodb://localhost/books', { useNewUrlParser: true })
    .then(() => {
        console.log('Connected to DB');
    })
    .catch(error => {
        console.log(error);
    });

server.register({
    plugin: graphqlHapi,
    options: {
        path: '/graphql',
        graphqlOptions: { schema },
        route: { cors: true }
    }
});

server.route({
    method: 'GET',
    path: '/',
    handler: async (request, h) => {
        return 'Welcome to GraphQL Server';
    }
});

server.start(error => {
    if (error) {
        console.log(error);
    }
    console.log(`Server started at: ${server.info.uri}`);
});

在上述代码中,我们首先使用 Mongoose 连接 MongoDB,然后注册 graphqlHapi 插件,将 GraphQL Schema 和 Hapi Server 集成在一起。最后,我们定义一个根路由,以确保服务器运行正常。

总结

本文介绍了如何在 Hapi 框架中使用 GraphQL,包括安装和配置,以及 GraphQL 的基本语法和实践案例。GraphQL 是一种灵活的查询语言和运行时,结合 Hapi 可以构建高效、可靠的 API 服务,提供了更加灵活的数据查询和处理能力。希望本文对你有所帮助,如果有任何问题或意见,请随时留言。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6590b298eb4cecbf2d5ff881


纠错
反馈