I created 4 serverless routes
/api/list (GET)
/api/add (POST)
/api/update/:id (PUT)
/api/remove/:id (DELETE)
I included them in the api/now.json file like this:
{"src": "/api/list", "dest": "./list.js", "methods": ["GET"]},
{"src": "/api/add", "dest": "./add.js", "methods": ["POST"]},
{"src": "/api/update/*", "dest": "./update.js", "methods": ["PUT"]},
{"src": "/api/remove/*", "dest": "./remove.js", "methods": ["DELETE"]}
The /api/list and /api/add routes which don't use parameters are working, but /api/update and /api/remove aren't working, because I probably didn't use the regex on the api path in the above quoted now.json file correctly.
The handler for the router looks like this (only the relevant path)
app.put('/api/update/:id', (req, res) => {
...
});
module.exports = app;
The src is the incoming request path that you want to match, and dest is the file that should execute.
That means you don't need any routes for your first two because visiting /api/list will execute the function in your file /api/list.js and /api/add will execute /api/add.js.
You can use rewrites in a now.json file to define routes similar to express patterns:
{
"rewrites": [
{ "source": "/update/:id", "destination": "/api/update" },
{ "source": "/remove/:id", "destination": "/api/remove" }
]
}
An example function in /api/remove.js would look like:
module.exports = (req, res) => {
const { id } = req.query;
res.send('Removing ID ' + id);
});
Alternatively, you could name your file /api/remove/[id].js and then you wouldn't need to define rewrites configuration at all. This is called Path Segments.
Related
We have blog in a NuxtJs project deployed using docker and traefik's PathPrefix('/blog') so instead of being served from https://example.com/ is served from
https://example.com/blog/
version: "3.9"
services:
{{ project_id }}-awesome-blog-{{ awesome_blog_env }}:
# etc..
labels:
- traefik.http.routers.awesome_blog-{{ awesome_blog_env }}-router.rule=Host(`{{ awesome_blog_host_dns }}`) && PathPrefix(`/blog`)
# etc..
- {{ docker_network }}
networks:
{{ docker_network }}:
external: true
The issue is that because of the PathPrefix Nuxt does not seem to know the actual page. As it's receiving /blog/ as path it doesn't match any expected route
this is what this.$router prints out in the server on the server from https://example.com/blog/
{
"name": null,
"meta": {},
"path": "/blog/",
"hash": "",
"query": {},
"params": {},
"fullPath": "/blog/",
"matched": []
}
And this is what it prints in local from http://localhost.com:3000/
{
"name": "index___en",
"meta": {},
"path": "/",
"hash": "",
"query": {},
"params": {},
"fullPath": "/",
"matched": [{
//...etc
name: "index___en",
// ..etc
}]
}
I tried using the
router: {
base: '/blog/
}
Which in local works but in the server seems not to work (doesn't even get to the nuxt site and printing the server 404)
As an "ugly" alternative I tried copying all the pages inside the /blog/ folder and they do respond but my serverMiddleware does not (returns 404)
this serverMiddleware is setup like this:
nuxt.config.js
serverMiddleware: ['~/server-middleware/index.js'],
server-middleware/index.js
const nocache = require('nocache');
const express = require('express')
const buildRouter = require('../server/router.js')
const app = express()
app.use(express.json())
app.use(nocache());
buildRouter(app)
module.exports = app
server/router.js
module.exports = function (app) {
const buildApiRoute = require('./controllers/api')
buildApiRoute(app, '/api')
}
Tried with /blog/api, too
module.exports = function (app) {
const buildApiRoute = require('./controllers/api')
buildApiRoute(app, '/blog/api')
}
Anyways, is there any way to tell nuxt to ignore the /blog/ slug of the url o something similar?
Magic code
// Before anything
this.$router.fullPath = this.$router.fullpath.replace('/blog', '/')
this.$router.path = this.$router.path.replace('/blog', '/')
I'm doing a products page using express with pug as a template and storing the data in a JSON file, but on the products page the images are not loading, I just receive the links back.
let me know if you need me to show you something else, I also have a route.js file.
JSON
[
{
"name": "Jetpack pitus",
"price": 150000,
"model": "2021",
"img_url": "https://cdn2.unrealengine.com/Fortnite%2Fpatch-notes%2Fv4-2-contentupdate%2Fheader-v4-2-content-update%2FJetpack-1920x1080-20e524ca933c434a4c07719a5405e60041b47a1f.png"
},
{
"name": "Jetpack venus",
"price": 125000,
"model": "2020",
"img_url": "https://www.ginx.tv/uploads/Iron_Man_Stark_industries.png"
},
{
"name": "Jetpack enormus",
"price": 200000,
"model": "2022",
"img_url": "https://www.x-jetpacks.com/wp-content/uploads/Jetpack-NX-Square-front-and-back.jpg"
}
]
pug:
extends layout
block content
each product in data
p=product.name
p=product.price
p=product.model
p=product.img_url
p
a.btnOrder(href='/orders') Make an order!!!
index.js:
const express = require('express');
const pug = require('pug');
const path = require('path');
const routes = require('./routes/routes');
const app = express();
app.set('view engine', 'pug');
app.set('views', __dirname + '/views');
app.use(express.static(path.join(__dirname, '/public')));
const urlendcodedParser = express.urlencoded({
extended: false
});
app.get('/', routes.index);
app.get('/products', routes.productsData);
app.get('/orders', routes.orders);
app.get('/submitted', routes.submitted);
// app.post('/submitted', urlendcodedParser, routes.submitted);
app.listen(3000);
Assuming you are invoking the render method correctly and passing in your array as data, then to show images it should be something like:
each product in data
p=product.name
p=product.price
p=product.model
p
img(src=product.img_url)
p
a.btnOrder(href='/orders') Make an order!!!
You might also want to make the order request more specific rather than a common page for all products:
a.btnOrder(href="/orders?model="+product.model) Make an order!!!
Of course you have to code the route /orders to read the query string.
I have an Express API already in production using Firebase Cloud Functions but I need to add custom domain to it. I followed these instructions to create a custom domain for Cloud Functions using Firebase Hosting and end up with the following firebase.json
{
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint",
"npm --prefix \"$RESOURCE_DIR\" run build"
],
"source": "functions"
},
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"emulators": {
"functions": {
"port": 5001
},
"firestore": {
"port": 8080
},
"ui": {
"enabled": false
}
},
"hosting": [{
"site": "devbp",
"target:":"devbp",
"public": "public",
"rewrites": [
{
"source": "/api/**",
"function": "api"
}
]
}]
}
index.ts
import { functions } from './utils/exports-converter';
import App from './web-api/configs/app';
export * from './functions';
export * from './backup/schedules';
export * from './firestore-triggers/credits/credits-triggers'
export * from './schedules/transactions/aggregations-schedules';
export const api = functions.runWith({
memory: '1GB',
timeoutSeconds: 300
}).https.onRequest(App.express);
exports-converter.ts
import * as express from "express";
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
export { express, functions, admin };
app.ts
import * as cors from "cors";
import * as bodyParser from "body-parser";
import Routes from "./routes";
import { express } from "../../utils/exports-converter";
class App {
public express: express.Application;
constructor() {
this.express = express();
this.init();
this.mountRoutes();
}
private init() {
const corsOptions = { origin: true };
this.express.use(cors(corsOptions));
this.express.use(bodyParser.raw());
this.express.use(bodyParser.json());
this.express.use(bodyParser.urlencoded({ extended: true }));
}
private mountRoutes() {
Routes.mount(this.express);
}
}
The problem is that the endpoints inside the api are not reachable, e.g. GET devbp.web.app/api/user?id=123 which returns Cannot GET /api/user. This response indicates that Express is handling the requests (if not, the Hosting would throw a 404 page) but not as expected.
I believe that I'm missing something in my firebase.json because the same api, as said above, is currently in production.
Any thoughts on it?
According to the documentation (here as well) hosting syntax is:
"hosting": {
...
}
while in the presented firebase.json you have [{ ... }].
Try to remove square brackets.
I am not sure, if I am following the logic, however I don't see any new App anywhere in the code. If I understand correctly if you do not create new App object you will not run it's constructor so express app will not be created.
2nd thing I think :) is that, again according to my understanding, there should be Express get() method called when GET request is called by http GET requst.
I found this tutorial it's not cloud function, however the logic is similar. New instance App is created and get method invoked.
this is my config file:
import nconf from "nconf";
import path from "path";
nconf.argv()
.env()
.file({
file: path.join(
__dirname,
`manifest.${process.env['NODE_ENV'] || 'development'}.json`
)
});
var manifest = {
server: nconf.get('server'),
connections: nconf.get('connections'),
plugins: nconf.get('plugins')
};
export default manifest;
and this is the config file
{
"server": {},
"connections": [
{
"port": 3000,
"labels": ["api"]
}
],
"plugins": [
{
"vision": {},
"visionary": {
"engines": {
"jsx": "hapi-react-views"
},
"relativeTo": __dirname,
"path": ""
}
}
]
}
unfortunately I get the following error:
throw new Error("Error parsing your configuration file: [" + self.file +
^
Error: Error parsing your configuration file: [/Users/mazzy/vagrant-devbox/hapi-react-es6/server/config/manifest.development.json]: Unexpected token _
at [object Object].File.loadSync (/Users/mazzy/vagrant-devbox/hapi-react-es6/node_modules/nconf/lib/nconf/stores/file.js:14
I believe the problem is here:
"relativeTo": __dirname,
nconf is assuming your config file is JSON, but this isn't valid JSON.
If you need JavaScript in your config file, one option is to require (or import) it and then use .defaults instead of .file (you'll probably want to change the filename from .json to .js to make it clear that it's JavaScript, not JSON):
import nconf from "nconf";
import path from "path";
import config from `./manifest.${process.env['NODE_ENV'] || 'development'}`;
nconf.argv()
.env()
.defaults(config);
// ...
I haven't tested this, but hopefully it helps.
I'm creating a angular app that talks to a node backend express application and using a config file to set env variables in my node app I can access my config file like this:
index.js
var port = config.get("server:port");
var server = app.listen(port, function() {});
My config file looks like this:
app.config.js
module.exports =
{
"server":{
"host":"localhost",
"port":3000
},
"mongodb": "",
"redis": {
"loadBalancerInstance": {
"host": "server",
"port": {
"default": "6379"
}
}
},
"elastic": {
"server": "server",
"port": "9200",
"user":"foo",
"password":"bar"
},
"log": {
"level": "info",
"filename": "",
"console": true,
"logio": {
"port": "28777",
"node_name": "this-server-name",
"host": "server"
}
}
};
I have statically defined the route/port to a backend
datafactory.js
angular.module('dashboard.factories')
.factory('DataFactory', function($http, $q, FormatFactory) {
var backend = function(apiEndPoint, clientKey) {
clientKey = clientKey || "";
var deferred = $q.defer();
$http.get("http://localhost:3000/<-(pull this from config file)" + apiEndPoint + "/" + clientKey)
My question is how can I access app.config.js within angular and dynamically set host/port within my angular service
I suppose if you're stuck on using the same configuration file that your node server uses, you'll have to make the .js file available to a GET request from your app, which you'll then have to parse out the string into JSON.
Edit:
You're going to have to have two configuration files, one available to your node server, and one for your angular app. Now, if you want the source to be one file, you could build that into your build process - if you use something like gulp or grunt, this would be reasonably easy. It could take the singular config file and build two files - the node server config file, and an angular module (I would suggest a constant or value) that you could inject into your data services.
If you're serving the config file at localhost:3000/config, you can do this:
angular.module('dashboard.factories')
.factory('DataFactory', function($http, $q, FormatFactory) {
$http.get('localhost:3000/config')
.success(function(config) {
$http.get(config.server.host + ":" + config.server.port)
// whatever you want here
});
});