How to store user email from your website to Google Cloud Storage
This guide walks through step-by-step of how to build a backend system to store user email id entered on your website to a google cloud storage and common errors when storing customer/user email to your cloud by deploying a Node.js Express API to Google Cloud Run that saves data to Firestore.
Prerequisite Checklist
- Google Cloud Project created & billing enabled.
- Firestore Database initialized in your chosen region (e.g.,
europe-west3
). - Project files (
index.js
,package.json
,Dockerfile
) are in the same directory.
1. Deployment Fails: Buildpack Detection Error
Error Message:
fail: google.python.poetry@0.1.0
fail: google.python.missing-entrypoint@0.9.0
ERROR: No buildpack groups passed detection.
ERROR: failed to detect: no buildpacks participating
Cause: The build system cannot identify how to run your application because the package.json
is missing the standard "start"
script.
Solution: Ensure your package.json
includes a "start"
script that launches your app.
{
"name": "email-subscriber",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node index.js"// <-- THIS LINE IS CRITICAL
},
"dependencies": {
"@google-cloud/firestore": "^7.0.0",
"express": "^4.18.0",
"cors": "^2.8.5"
}
}
2. Deployment Succeeds, But Container Crashes: PORT Error
Error Message:
Revision is not ready and cannot serve traffic.
The user-provided container failed to start and listen on the port defined by the PORT=8080 environment variable.
Cause: The container is crashing before it can start listening on port 8080, often due to an error initializing the Firestore client or a runtime exception.
Solution: Use this robust index.js
code with error handling and logging:
const express = require('express');
const cors = require('cors');
const { Firestore } = require('@google-cloud/firestore');
const app = express();
const port = process.env.PORT || 8080;
console.log(`Starting server. Port: ${port}`); // Log the port
// Initialize Firestore with error handling
let firestore;
try {
firestore = new Firestore();
console.log("Firestore client initialized.");
} catch (error) {
console.error("FATAL: Failed to init Firestore:", error);
process.exit(1);
}
// CORS: REPLACE with your actual website URL!
app.use(cors({ origin: 'https://your-actual-website.com' }));
app.use(express.json());
// Your POST route
app.post('/', async (req, res) => {
try {
const { email } = req.body;
// ... validation & save logic ...
res.status(200).json({ message: 'Success! Thank you for subscribing.' });
} catch (error) {
console.error('Error saving email:', error);
res.status(500).json({ error: 'Internal server error.' });
}
});
// Add a GET route for easy testing
app.get('/', (req, res) => {
res.send('API is running. Send a POST request with {"email": "address"}.');
});
app.listen(port, () => {
console.log(`✅ Server listening on port ${port}`);
});
3. Function Deploys but Returns 404 Error
Error Message: Error 404 (Not Found)
Cause: You are sending a GET request (e.g., from a browser address bar) to a route that only accepts POST requests (app.post('/')
).
Solution:
- Test correctly: Use
curl
or a tool like Postman to send a POST request.
curl -X POST -H "Content-Type: application/json" -d '{"email":"test@example.com"}' https://your-service-url.a.run.app
- Add a GET route: Add the
app.get('/')
route from the code above to provide a friendly message for browser visitors.
4. Browser Console Shows a CORS Error
Error Message: Access to fetch at 'https://your-service-url.a.run.app' from origin 'https://your-website.com' has been blocked by CORS policy.
Cause: The allowedOrigin
value in your Cloud Run function does not exactly match the URL of the website making the request.
Solution:
- In your
index.js
file, find the CORS configuration:
const allowedOrigin = 'https://your-actual-website.com';
- Change it to the exact URL of your frontend website, including
http://
orhttps://
.- Live Site:
https://myportfolio.com
- Local Development:
http://localhost:3000
orhttp://127.0.0.1:5500
- Live Site:
- Redeploy your Cloud Run function after making this change.
5. Function Runs but Can't Write to Firestore (Permission Denied)
Cause: The default service account running your Cloud Run function does not have permission to access Firestore.
Solution: Grant the correct IAM role.
- Find your Service Account:
- Go to your Cloud Run service's "Details" tab.
- Copy the "Service account" email address.
- Grant Permissions:
- Go to IAM & Admin > IAM in the Google Cloud Console.
- Click GRANT ACCESS.
- In "New principals", paste the service account email.
- Assign the role Cloud Datastore User (this is the correct role for Firestore).
Debugging Workflow Summary
- Check Cloud Run Logs: The first place to look for any runtime errors. Found in the "Logs" tab of your Cloud Run service.
- Check Browser Console: For CORS errors or frontend JavaScript issues.
- Check Browser Network Tab: To see the exact request and response from your API.
- Test with
curl
: Isolate the problem by testing the API directly from the command line, bypassing the browser. - Verify IAM Permissions: If the logs show a permission denial, ensure the service account has the
Cloud Datastore User
role.
By following this guide, you can systematically identify and fix the most common issues encountered when building this type of serverless application. Great work on getting it running