I'm starting with Firebase and trying to implement an api but I'm having trouble trying to create some routes using Express. Follow:
firebase.json
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [{
"source": "/api/**",
"function": "api"
},{
"source": "/api/auth/**",
"function": "api"
}]
},
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint"
]
}
}
index.js
const functions = require("firebase-functions");
const cors = require("cors");
const express = require("express");
const api = express();
api.use(cors({ origin: true }))
api.use("/auth", require("./routes/auth"));
exports.api = functions.https.onRequest(api);
routes/auth.js
var express = require("express");
module.exports = () => {
var auth = express.Router();
auth.post("/signin", (request, response) => {
var service = require("../services/auth/signin");
service(request, response);
});
return auth;
}
services/auth/signin.js
module.exports = (request, response) => {
response.status(200).send({
"success": true,
"request": request.body.email
});
}
I'm not sure if it's the best framework and if the modules are implemented properly. Any suggestions are very welcome. Thank you!
for endpoint to be /api/auth/signin try
api.use("/api", require("./routes/auth"));
and
auth.post("/auth/signin", (request, response) => {
then remove
,{
"source": "/api/auth/**",
"function": "api"
}
a little counter intuitive in that it seems to be mapping /api twice, but this is working for me in several apps
Related
For a project I have the following url:
https://beterbijons.nl/belevingsapp/?name=Natuurleerpad
The website is made with NextJS, when I test this locally I had to add the following code:
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
env: {
BASE_URL: process.env.BASE_URL,
},
trailingSlash: true,
images: {
loader: 'akamai',
path: '',
},
async redirects() {
return [
{
source: '/belevingsapp/',
has: [
{
type: 'query',
key: 'name',
value: '(?<paramName>.*)'
},
],
destination: '/belevingsapp/natuurleerpad-schipperskerk',
permanent: true,
},
]
},
}
module.exports = nextConfig
my firebase.json looks like:
{
"hosting": {
"public": "out",
"target": "productie-frontend",
"ignore": [
".firebase/**",
".firebaserc",
"firebase.json",
"**/node_modules/**"
],
"redirects": [ {
"regex": "/belevingsapp/?name=(.*)",
"destination": "/belevingsapp/natuurleerpad-schipperskerk",
"type": 301
}
]
}
}
This works. Only when I publish it to firebase hosting do I get a 'page not found' page, does anyone have a solution for this? The given url with ? I can't adjust..
We're using Firebase Hosting. We have a Next.js app, called "knowledge", deployed on Google Cloud Run in the same GCP project. We followed the instructions in the Firebase documentation. Our firebase.json is as follows:
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"hosting": {
"public": "build",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "/knowledge{,/**}",
"run": {
"serviceId": "knowledge",
"region": "us-central1"
}
},
{
"source": "**",
"destination": "/index.html"
}
]
}
}
We want every request to "/knowledge{,/**}" for server-side rendering through our Next.js app on Cloud Run. When we open any of these pages, it loaded, but it does not load any of the static file, showing many errors like the following in the console:
Uncaught SyntaxError: Unexpected token '<' (at webpack-df4cf1c8d23aa877.js:1:1)
framework-81da43a8dcd978d9.js:1
Our next.config.js is as follows:
module.exports = {
async rewrite() {
return [
{
source: "/knowledge",
destination: "/",
},
];
},
images: {
domains: ["firebasestorage.googleapis.com"],
},
};
Static files will be under /_next/, so add '/path*'.
module.exports = {
async rewrite() {
return [
{
source: "/knowledge",
destination: "/",
},
{
source: "/knowledge/:path*",
destination: "/:path*",
},
];
},
images: {
domains: ["firebasestorage.googleapis.com"],
},
};
Really new to firebase and very junior level at code. I am trying to figure out a bug where a custom 404 is not showing, or when rewrites changed then app does not work.
"rewrites": [
{
"source": "**",
"function": "app"
}
]
This redirects everything to the app and app functions properly. However, the 404.html doesn't show if a bad URL is attempted. There is a generic "Cannot GET /asdfasd"
Changed it to
"rewrites": [
{
"source": "/",
"function": "app"
}
]
This will now show the custom 404.html properly.
However, with this a function responds with 404 with this configuration, breaking the app. From functions/index.js:
app.post('/sendsmstoconsumer', (request, response) => {
client.messages
.create({body: request.body.message, from: '+15555555555', to: request.body.phone})
.then(message => {
response.send("Your message: " + request.body.message + " has been sent!")
});
})
I have tried a number of variations like below, but I'm just missing something.
{
"source": "/",
"function": "app"
},
{
"source": "/sendsmstoconsumer",
"function": "sms"
}
]
change functions/index.js:
exports.sms = functions.httpsOnRequest((request, response) => {
client.messages
.create({body: request.body.message, from: '+15555555555', to: request.body.phone})
.then(message => {
response.send("Your message: " + request.body.message + " has been sent!")
});
})
I would appreciate any help with the proper way to structure the rewrite, or change the function both the custom 404 and app work properly. I seem stuck with getting either one or the other.
Thank you.
As requested, editing to add the complete files:
firebase.json
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"function": "app"
}
]
},
"emulators": {
"functions": {
"port": 5001
},
"database": {
"port": 9000
},
"hosting": {
"port": 5000
},
"ui": {
"enabled": true
}
}
}
index.js
const functions = require('firebase-functions')
const express = require('express')
const app = express()
const accountSid = 'xxx'
const authToken = 'xxx'
const client = require('twilio')(accountSid, authToken)
const cors = require('cors')
// Enable cors for everything
// TODO: Re-enable cors at a later date
// src: https://www.npmjs.com/package/cors
app.use(cors())
app.post('/sendsmsverificationmessage', (request, response) => {
client.verify.services('xxx')
.verifications
.create({to: request.body.phone, channel: 'sms'})
.then(verification => {
response.send("Your verification code has been sent to your phone!" )
});
})
app.post('/verifyusersphonenumber', (request, response) => {
client.verify.services('xxx')
.verificationChecks
.create({to: request.body.phone, code: request.body.token})
.then(verification_check => {
response.send("Your phone has been verified!")
});
})
app.post('/sendsmstoconsumer', (request, response) => {
client.messages
.create({body: request.body.message, from: '+15555555555', to: request.body.phone})
.then(message => {
response.send("Your message: " + request.body.message + " has been sent!")
});
})
exports.app = functions.https.onRequest(app)
By default a rewrite does not "fall through" once matched, so the response sent by the Cloud Function will always be returned directly to the user. There is actually a way to get around this: if your response body includes a header of X-Cascade: PASS.
In this case, Firebase Hosting will fall through to the default 404 behavior (including a custom 404.html). You should be able to add this to your Express app like so:
// *AFTER* all other endpoints
app.use((req, res) => {
res.set('X-Cascade', 'PASS');
res.status(404).send('Not Found');
});
Thanks to Michael Bleigh's answer, we found a solution, but had to specify the 404.html file.
app.use((req, res) => {
res.set('X-Cascade', 'PASS')
res.status(404).redirect('404.html')
})
Now I created a file by node server like
const functions = require("firebase-functions")
const express = require("express")
/* Express */
const app = express()
app.get("/test", (request, response) => {
response.send("Hello from Express on Firebase!")
})
const api1 = functions.https.onRequest(app)
module.exports = {
api1
}
firebase.json
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
},
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint"
]
}
}
and I have deployed it to firebase hosting and try tried access it on firebase hosting the index.html show up to me but when I require the /test it's return as 404.html page ! what's I'm missing ?
after updated firebase.json and added rewrites to
{
"hosting":
{
"public": "public",
"rewrites": [
{
"source": "/test",
"function": "app"
}
]
}
}
the message is different now
The answer
I must to structured my project files to
-project (folder)
---functions (folder)(contains on all nodejs files)
---public (filder)
You need to include a rewrites section to your firebase.json file. That tells the Firebase servers how to route any requests that come in... and right now, you aren't telling it anything.
"hosting": {
"rewrites": [
{
"source": "**",
"function": "api1"
}
]
}
This answer isn't actually an answer to your question, but it demonstrates the proper way to set up rewrites with cloud function express apps.
My domain seems to redirect to the index.html and all the sub-links just fine.
Problem is it won't redirect to the api rule "source": "/api/**"
I've checked the API manually using the whole firebase url (no custom domain) and it works.
How can I get both domain.com/somelink and domain.com/api/somelink to work in union?
Here's the configuration.
firebase.json
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "/api/**",
"function": "api"
},
{
"source": "**",
"destination": "/index.html"
}
]
},
"storage": {
"rules": "storage.rules"
}
}
As noted here https://stackoverflow.com/questions/44959652/firebase-hosting-with-dynamic-cloud-functions-rewrites/45224176#45224176
Create a main app which hosts all other top-level functions.
const funtions = require('firebase-functions');
const express = require('express');
const app = express();
app.get('/users/:userId/:userData/json', (req, res) => {
// Do App stuff here
}
// A couple more app.get in the same format
// Create "main" function to host all other top-level functions
const main = express();
main.use('/api', app);
exports.main = functions.https.onRequest(main);
firebase.json
{
"source": "/api/**", // "**" ensures we include paths such as "/api/users/:userId"
"function": "main"
}
Use the main hook.
const hooks = express();
main.use('/hooks/, hooks);