title: React.js, Express.js and the dreaded CORS
body: <p>I'm sorry to be posting yet another question about CORS but I just can't figure this one out.</p>
  <p><a href="https://i.stack.imgur.com/nFrXr.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/nFrXr.png" alt="enter image description here" /></a></p>
  <p>I have a React app using an Express.js server (running on <code>http://localhost:9001</code>) to upload an image to a Google Cloud storage bucket. I keep getting a CORS error even though the image is uploaded successfully and this is preventing me from getting the image's URL returned. I don't really understand how I can get a CORS error even though the image is uploaded but that's what's happening.</p>
  <p>I have configured CORS on the Google Cloud storage bucket as follows:</p>
  <pre><code>[
      {
        &quot;origin&quot;: [&quot;http://localhost:3000&quot;],
        &quot;responseHeader&quot;: &quot;*&quot;,
        &quot;method&quot;: [&quot;POST&quot;],
        &quot;maxAgeSeconds&quot;: 3600
      }
  ]
  </code></pre>
  <p>When I inspect the CORS error I'm getting I see the following:</p>
  <p><a href="https://i.stack.imgur.com/56jGW.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/56jGW.png" alt="enter image description here" /></a></p>
  <p>The origin is <code>http://localhost:3000</code>, so that's configured correctly and I'm using <code>POST</code> to upload the image so that should be allowed as well.</p>
  <p>The function I've written to upload the image is as follows:</p>
  <pre><code>function postImage(file) {
      const formData = new FormData();
      formData.append('file', file);
  
      fetch(`${window.location.protocol}//${window.location.hostname}:9001/uploads`, {
          method: 'POST',
          mode: 'cors',
          cache: 'no-cache',
          // headers: {
          //     'Content-Type': 'multipart/form-data'
          // },
          body: formData
      })
          // .then((response) =&gt; response.json())
          .then((response) =&gt; console.log('This is your data:', response.data))
  
          .catch(error =&gt; {
              console.error('There has been a problem uploading your image', error);
          });
  }
  </code></pre>
  <p>I've commented out the headers as including them kept throwing up a <code>Multipart: Boundary not found</code> error that I've seen others have an issue with and removing the headers setting hasn't caused any other issues.</p>
  <p>I have a helper function on the Express server that uploads the image to the Google Cloud storage bucket:</p>
  <pre><code>const uploadImage = (file) =&gt; new Promise((resolve, reject) =&gt; {
      const { originalname, buffer } = file
  
      const blob = bucket.file(originalname.replace(/ /g, &quot;_&quot;))
      const filetype = blob.name.split('.').pop()
      const filename = `${uuidv4()}.${filetype}`
      const blobStream = blob.createWriteStream({
          resumable: false
      })
      blobStream.on('finish', () =&gt; {
          const publicUrl = format(
              `https://storage.googleapis.com/${bucket.name}/${filename}`
          )
          resolve(publicUrl)
      })
          .on('error', () =&gt; {
              reject(`Unable to upload image, something went wrong`)
          })
          .end(buffer)
  })
  </code></pre>
  <p>Here are the functions on my Express server:</p>
  <pre><code>import { typeDefs } from './graphql-schema'
  import { ApolloServer } from 'apollo-server-express'
  import express from 'express'
  import neo4j from 'neo4j-driver'
  import { makeAugmentedSchema } from 'neo4j-graphql-js'
  import dotenv from 'dotenv'
  import { initializeDatabase } from './initialize'
  const bodyParser = require('body-parser')
  const multer = require('multer')
  const uploadImage = require('./helpers/helpers')
  
  dotenv.config()
  
  const app = express()
  
      const schema = makeAugmentedSchema({
        typeDefs,
        config: {
          query: {
            exclude: ['RatingCount'],
          },
          mutation: {
            exclude: ['RatingCount'],
          },
        },
      })
      
      const driver = neo4j.driver(
        process.env.NEO4J_URI,
        neo4j.auth.basic(
          process.env.NEO4J_USER,
          process.env.NEO4J_PASSWORD
        ),
        {
          encrypted: process.env.NEO4J_ENCRYPTED ? 'ENCRYPTION_ON' : 'ENCRYPTION_OFF',
        }
      )
      
      const init = async (driver) =&gt; {
        await initializeDatabase(driver)
      }
      
      init(driver)
      
      const server = new ApolloServer({
        context: { driver, neo4jDatabase: process.env.NEO4J_DATABASE },
        schema: schema,
        introspection: true,
        playground: true,
      })
      
      // Specify host, port and path for GraphQL endpoint
      const port = process.env.GRAPHQL_SERVER_PORT || 4001
      const path = process.env.GRAPHQL_SERVER_PATH || '/graphql'
      const host = process.env.GRAPHQL_SERVER_HOST || '0.0.0.0'
      
      
      // Code for uploading files to Google Cloud
      app.use((req, res, next, err) =&gt; {
        console.error(err.stack)
        res.header(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);
        res.type('multipart/form-data')
        res.status(500).json({
          error: err,
          message: 'Internal server error!',
        })
        next()
      })
      
      const multerMid = multer({
        storage: multer.memoryStorage(),
        limits: {
          // no larger than 5mb.
          fileSize: 5 * 1024 * 1024,
        },
      })
      
      app.disable('x-powered-by')
      app.use(multerMid.single('file'))
      app.use(bodyParser.json())
      app.use(bodyParser.urlencoded({ extended: false }))
      
      app.post('/uploads', async (req, res, next) =&gt; {
        try {
          const myFile = req.file
          const imageUrl = await uploadImage(myFile)
          res
            .status(200)
            .json({
              message: &quot;Upload was successful&quot;,
              data: imageUrl
            })
        } catch (error) {
          next(error)
        }
      })
  
      server.applyMiddleware({ app, path })
      
      app.listen({ host, port, path }, () =&gt; {
        console.log(`GraphQL server ready at http://${host}:${port}${path}`)
      })
      
      app.listen(9001, () =&gt; {
        console.log('Node.js -&gt; GCP server now listening for requests!')
      })  
  </code></pre>
  <p>I've tried a lot of different things to get this working:</p>
  <ol>
  <li>I've tried adding http://localhost:9001 to the CORS configuration, as well as other URLs</li>
  <li>I've tried opening up all origins with <code>&quot;*&quot;</code> for</li>
  <li>I've read through all the documentation <code>[here][3]</code></li>
  <li>I've tried following all the troubleshooting documentation Google has <a href="https://cloud.google.com/storage/docs/configuring-cors#remove-cors-bucket" rel="nofollow noreferrer">here</a></li>
  <li>I've cleared my browser cache as I've seen that can cause the CORS errors to persist - see another post <a href="https://stackoverflow.com/questions/36047091/cloud-storage-no-access-control-allow-origin-header-is-present-on-the-reques">here</a></li>
  <li>I've tried waiting over night for my Google Cloud CORS configuration to take effect as I've heard the configuration can take a bit of time to propagate</li>
  </ol>
  <p>Despite all of this I'm still getting the CORS error but my upload is still working. I just need to clear the error so I can get the returned image URL.</p>