Search code examples
node.jsamazon-s3graphqlgatsbygatsby-image

Gatsby `S3Object` that doesn't exist in the schema. Use `createTypes` to add the type before adding resolvers


Im trying to pull remote images from my S3 Bucket in Gatsby with the below code. I have a schema.graphql that builds a classic S3Object. But Gatsby Node throws the below error. I've been in the docs for days in this issue, can anyone point me in the right direction? I just need to get the image into the data layer of Gatsby so I can use Gatsby-image.

I have a feeling I need to update the S3Object to extend the Node Interface, i'm working on this now.

Error:

warn `createResolvers` passed resolvers for type `S3Object` that doesn't exist in the schema. Use `createTypes` to add the type before adding resolvers.

schema.graphql

type PortfolioItem @model @key(fields: ["title", "createdAt"]) {
  id: ID!
  title: String!
  file: S3Object
  thumbnailUrl: String
  ...
}

type S3Object {
  bucket: String!
  key: String!
  region: String!
}

gatsby-node.js

exports.createResolvers = ({ actions, cache, createNodeId, createResolvers, store, reporter }) => {
  const { createNode } = actions;
  createResolvers({
    S3Object: {
      imageFile: {
        type: `File`,
        resolve(source, args, context, info) {
          return createRemoteFileNode({
            url: 'https://my-aws-bucket-url.s3.us-east-2.amazonaws.com/' + source.key,
            store,
            cache,
            createNode,
            createNodeId,
            reporter,
          });
        },
      },
    },
  });
};

Solution

  • Ok guys,

    After literal weeks of investigating this. This is the answer, I know this will help dozens of people out there dealing with Gatsby and remote Images.

    The entire goal here, was to have direct access to a remote image on a field on a Model in graphql DIRECTlY. No looping over long arrays of images from some Gatsby listAllImages query and crap like that. This adds an actual USEABLE GATSBY-IMAGE directly onto a field of your model to be used instantly.

    1. Define an S3Object in your Schema.Graphql like below.
    type S3Object {
      bucket: String!
      key: String!
      region: String!
    }
    
    1. The answer here is creating a custom resolver in your gatsby node file. And the trick here, is going into the gatsby level schema and seeing the REAL name of your model. This is the secret. You need to run:
    gatsby repl
    

    This will put you into Gatsby's CLI and then enter:

    schema
    

    THIS WILL SHOW YOU THE COMPILED SCHEMA LEVEL NAMES. So your S3Object is actually called <your_api_name>_s3object. Using this name, that aparently had your api name prepended to it....smfh....is to be used with a custom resolver WITH a gql query inside of it to add a file to your model. See below. Now, where ever you add S3Object as a field type, you will have access to the image with an image-sharp query! You must also use gatsby-s3-image-source to grab all the images to be used into your files system!

    This was a super complicated solve for a noob like me to Gatsby, I hope this solves someone elses remote file issue like mine!

    exports.createResolvers = ({ createResolvers }) => {
      const resolvers = {
        ryanthedev_S3Object: {
          imageFile: {
            type: 'File', // this needs to be 'File', since it's not returning an 'ImageSharp' node anymore
            resolve: (source, args, context, info) => {
              // A promise is expected to be returned anyway so don't need
              // to `await` the result here, if all we're doing is returning
              // the `File` node
              return context.nodeModel.runQuery({
                query: {
                  filter: {
                    base: { eq: source.key },
                  },
                },
                type: 'File',
                firstOnly: true,
              });
            },
          },
        },
      };
      createResolvers(resolvers);
    };