GraphQLGuide / apollo-datasource-mongodb

Apollo data source for MongoDB
MIT License
285 stars 64 forks source link

this.findOneById is not a function (SSR using SchemaLink) #42

Closed Robyrogers closed 3 years ago

Robyrogers commented 3 years ago

If my understanding is correct, I can use the SchemaLink to make an internal request to Apollo Graphql during SSR to avoid unnecessary network requests. SchemaLink doesn't take any dataSource function but I should still be able to pass the dataSource objects through the context after creating them. While doing so, I get the 'this.findOneById is not a function' error even though I can access all the other functions I defined.

// Apollo Client
function createIsomorphLink() {
    if (typeof window === 'undefined') {
        const { SchemaLink } = require('@apollo/client/link/schema')
        const { schema } = require('./schema')
        const { UserModel } = require('./models')
        const { User } = require('./datasource')
        return new SchemaLink({ 
            schema,
            context: (operation) => {
                const { req, res } = operation.getContext()
                return {
                    dataSources: {
                        user: new User(UserModel)
                    },
                    req,
                    res
                }
            } 
        })
    } else {
        const { HttpLink } = require('@apollo/client/link/http')
        return new HttpLink({
            uri: '/api/graphql',
            credentials: 'same-origin',
        })
    }
}

function createApolloClient() {
    return new ApolloClient({
        ssrMode: typeof window === 'undefined',
        link: createIsomorphLink(),
        cache: new InMemoryCache(),
    })
}
9at8 commented 3 years ago

@Robyrogers You would also need to call initialize after creating the data source.

// Apollo Client
function createIsomorphLink() {
    if (typeof window === 'undefined') {
        const { SchemaLink } = require('@apollo/client/link/schema')
        const { schema } = require('./schema')
        const { UserModel } = require('./models')
        const { User } = require('./datasource')
        const dataSources = { user: new User(UserModel) }

        // Assuming all data sources are created using apollo-datasource-mongodb
        Object.values(dataSources).forEach(dataSource => dataSource.initialize())

        return new SchemaLink({ 
            schema,
            context: (operation) => {
                const { req, res } = operation.getContext()
                return {
                    dataSources,
                    req,
                    res
                }
            } 
        })
    } else {
        const { HttpLink } = require('@apollo/client/link/http')
        return new HttpLink({
            uri: '/api/graphql',
            credentials: 'same-origin',
        })
    }
}

function createApolloClient() {
    return new ApolloClient({
        ssrMode: typeof window === 'undefined',
        link: createIsomorphLink(),
        cache: new InMemoryCache(),
    })
}
lorensr commented 3 years ago

It's lowercase: findById

Robyrogers commented 3 years ago

It's lowercase: findById

@lorensr Sorry, that was a typo. Will edit the original post.

Robyrogers commented 3 years ago

@Robyrogers You would also need to call initialize after creating the data source.

// Apollo Client
function createIsomorphLink() {
    if (typeof window === 'undefined') {
        const { SchemaLink } = require('@apollo/client/link/schema')
        const { schema } = require('./schema')
        const { UserModel } = require('./models')
        const { User } = require('./datasource')
        const dataSources = { user: new User(UserModel) }

        // Assuming all data sources are created using apollo-datasource-mongodb
        Object.values(dataSources).forEach(dataSource => dataSource.initialize())

        return new SchemaLink({ 
            schema,
            context: (operation) => {
                const { req, res } = operation.getContext()
                return {
                    dataSources,
                    req,
                    res
                }
            } 
        })
    } else {
        const { HttpLink } = require('@apollo/client/link/http')
        return new HttpLink({
            uri: '/api/graphql',
            credentials: 'same-origin',
        })
    }
}

function createApolloClient() {
    return new ApolloClient({
        ssrMode: typeof window === 'undefined',
        link: createIsomorphLink(),
        cache: new InMemoryCache(),
    })
}

Thank you so much @9at8 . This worked for me. Maybe add it to the docs so this could be referenced for future use.