当根解析器 returns 可迭代时如何将数据库连接传递给子解析器

How to pass DB connection to a sub-resolver when the root resolver returns an iterable

简而言之,这个解析器 getAllArticles() returns 一个文章数组,每篇文章都有一个作者字段和一个标签字段,因此每篇文章都可以触发子解析器来获取该数据,但我无法找到最佳解决方案。

你必须知道一些背景故事:

app.js

我将数据库连接作为根值中的映射传递给顶级解析器。

const db = new Map()
db.set('Neo4J', Neo4J.getDriver())
db.set('MongoDB', MongoDB.getDB())

// GraphQL Endpoint
app.use('/graphql', bodyParser.json(), graphqlExpress((req) => {
    // ...
    return {
        schema,
        context,
        rootValue: {
            db
        }
    }
}))

getArticle.js

我通过将数据库连接分配给响应对象来将它们传递给子解析器。

const getArticle = async (root, args, context) => {
    const db = root.db
    const Neo4J = db.get('Neo4J')
    const MongoDB = db.get('MongoDB')
    // ...
    const article = { /* ... */ }
    return Object.assign({}, article , { db })
}

在我转移到 returns 一系列文章的 getAllArticles() 解析器之前,它工作得非常好(代码变得非常干净)。我看不到如何附加 db 地图。

getAllArticles.js

以下是可以立即添加的直观内容:

const getAllArticles = async (root, args, context) => {
    const db = root.db
    const Neo4J = db.get('Neo4J')
    const MongoDB = db.get('MongoDB')
    // ...
    const articles = [{ /* ... */ }, { /* ... */ }, { /* ... */ }]
    return Object.assign({}, articles, { db })
}

那不行,看了之后,为什么会这样?子解析器从父对象获取数据,在本例中是每个文章。

经过一些迭代,这是可行的解决方案:

app.js

import Neo4J from './connectors/neo4j'
import MongoDB from './connectors/mongodb'
const db = new Map([
    ['Neo4J', Neo4J.getDriver()],
    ['MongoDB', MongoDB.getDB()]
])

app.use('/graphql', bodyParser.json(), graphqlExpress((req) => {
    const context = {
        settings: { SECRET },
        person: req.person,
        db
    }
    return {
        schema,
        context,
        rootValue: null
    }
}))

everyResolver.js

const getSomething = async (root, args, context, info) => {
    const db = context.db
    const Neo4J = db.get('Neo4J')
    const MongoDB = db.get('MongoDB')

    const session = Neo4J.session()
    session.run(query) // etc

    const users = MongoDB.collection('users')
    users.findOne(ObjectID(id)) // etc

    return objectOrIterable
}

希望这对以后的其他人有所帮助。我真的很喜欢将数据库驱动程序连接传递给解析器的方法。它收紧了整体架构,并允许我轻松启动额外的解析器,因为它们随附电池。

If you pass DB connections into the GraphQL context parameter, just make sure you pass in a Map containing the DB connections, not an Object. Some values in the DB connections are functions. Maps are able to handle that. Objects are not. You may see horribly ambiguous detonations related to the DB connections in your sub-resolvers unless you pass around a Map.