Two page templates that both render dynamically but share the same route - javascript

I have two custom page types that use dynamic routing, queried from Prismic CMS, service_page and about_page. I'm running into a problem in my express server custom routing however - if my servicePage route is listed first, the aboutPage wont render. But if its vice versa, the servicePage won't route but my aboutPages will. Is there a way to have two custom types with dynamic routes? I understand I can add a prefix to them (services/:uid or about/:uid) but I'd really rather avoid that for company purposes.
server.get('/:uid', (req, res) => {
const nextJsPage = '/servicePage';
const queryParams = { uid: req.params.uid };
app.render(req, res, nextJsPage, queryParams);
});
server.get('/:uid', (req, res) => {
const nextJsPage = '/aboutPage';
const queryParams = { uid: req.params.uid };
app.render(req, res, nextJsPage, queryParams);
});

What is your purpose?
When using routing in general the first listed url that matches the url you requested will be displayed. You can't expect any other behavior.
I don't think you can use Regex here if there is a difference between the ids (such as 9 digits vs. 2 digits for example), but you can try searching about it. Otherwise, you must use a prefix.

Related

Extract the common query path from RESTFUL URL (Ablate the resources) JS

I have a RESTFUL url design like this: GET /street/:streetName/house/:houseNumber or GET /street/:streetName/house/listings. As you can see, the :streetName and :houseNumber are resource names. I am trying to extract the static (common) parts from the url for some following logics which means I want to get /street/house and /street/house/listings (ablate all resources parts in the url).
I was trying to find a JS lib for this but didn't find one. Any pointers?
PS: I can do some string matching to achieve this like split by "/" then concat them and only care about the key words, so I can ignore all resource names. But this doesn't seem robust.
Assuming you have a route for each URL pattern, you can set an additional property req.staticParts in each middleware:
app.get("/street/:streetName/house/:houseNumber", function(req, res, next) {
req.staticParts = "/street/house";
...
})
...
.get("/street/:streetName/house/:houseNumber/listings", function(req, res, next) {
req.staticParts = "/street/house/listings";
...
})
.use(function(req, res) {
additionalLogic(req.staticParts);
});
This avoids string operations and is very explicit, therefore very robust.
Parsing the URL into staticParts without knowledge of the routes is problematic. For example, parsing the URL /street/house/25 based on keywords would lead to req.staticParts = "/street/house", but there is no matching route for it.

Express.js - Allow infinite subroutes, but at least one

I want to allow any subroute after /example/....
Example of valid URLs:
/example/one
/example/one/two
/example/one/two/three
But doing this:
server.get('/example/*', (req, res) => {
// ...
})
Is also allowing /example without any subroute. And I want to avoid this. How can I do it? Is there any way without using regex?
Thank you so much!
You could simply define two routes - one for /example and another for all /example-subroutes, you need to make sure the order is correct though:
app.get('/example', (req, res) => {
// render default page
});
app.get('/example/*', (req, res) => {
// do other stuff
});

Issue with multiple routes in one file - only two out of three work, the last one won't work

I'm working on making an API using express and MySQL. I'm having issues with my routes. I have it in a separate folder, requiring the different controller files and exporting the router at the end. Here's the issue. The last router.get function will not work. I can swap it and whatever is last will not work. I'll get back an empty array. I'm at a loss as to what can be wrong. Here's my code, the routes file:
const express = require('express');
const router = express.Router();
const getEmployeesController = require('../controllers/getEmployees');
const getEmployeesByIdController = require('../controllers/getEmployeesById');
const getEmployeesByFirstNameController = require('../controllers/getEmployeesByFirstName');
router.get('/', getEmployeesController.getEmployees);
router.get('/:id', getEmployeesByIdController.getEmployeesById);
router.get('/:first_name', getEmployeesByFirstNameController.getEmployeesByFirstName);
module.exports = router;
The 'first_name' router worked when it was second, after the '/', but now it won't. Same with the 'id', worked when its second, but not when it's third.
Here's the controller function, one as an example:
const mysql = require('mysql')
const pool = require('../mysql/connection')
const { handleSQLError } = require('../mysql/error')
const getEmployeesById = (req, res) => {
let sql = "SELECT ?? FROM ?? WHERE ?? = ?"
sql = mysql.format(sql, ['*', 'employees', 'emp_no', req.params.id])
pool.query(sql, (err, rows) => {
if (err) return handleSQLError(res, err)
return res.json(rows);
})
}
module.exports = { getEmployeesById };
/:first_name and /:id match the exact same URLs so only the first one you register is going to get all the matching URLs. They both match /anything.
You really can't define routes like that. There's no way Express knows which route handler you want to use with /anything is the requested URL.
Instead, you need to define a route structure where those two types of URLs are different and you can design a route handler that will uniquely catch each one. I personally don't ever use top level wildcard routes like this because they match every top level URL and they prohibit you using top level URLs for any other purpose in your site.
Instead, you might change your URL design to do this:
router.get('/id/:id', ...)
router.get('/firstname/:firstname', ...);
Then, it would be completely clear from the URL what type of resource was being requested and each route would match only the appropriate URLs.

Unknown value in req.param in node.js

I'm am learning node.js and therefore try to build a simple web app that shows the current news. The API that I am using offers several categories for the news.
So I create a route that takes the category as a param. My routes/index.js:
const router = require('express').Router();
const renderHome = require('../controllers/newsController');
const quotesCookie = require('./../middleware/quotesCookie');
router.get('/', quotesCookie, renderHome);
router.get('/:category', quotesCookie, renderHome);
module.exports = router;
My controllers/newsController.js looks like this:
const newsService = require('./../services/newsService');
const renderHome = async ( req, res ) => {
const category = req.params.category;
console.log(req.params);
const quote = res.quoteOfTheDay;
const { status, msg } = await newsService.topHeadlines(category);
res.render('home', {
title: 'News2Go',
author: quote.author,
quote: quote.quote,
articles: msg.articles
});
};
module.exports = renderHome;
When I for instance call http://localhost:3000/entertainment the console.log in the controller prints this to the console:
{ category: 'entertainment' }
{ category: 'sw.js' }
I have absolute no clue where the sw.js comes from... It appears a few milliseconds after the real category and ensures that topHeadlines is called twice.
Did someone know what this is? Did I miss something?
Apparently your web page has a script in it named sw.js. Because of that, the browser will request that with the URL http://localhost:3000/sw.js and your :category route will handle that request and log a category of sw.js.
Remember, ALL resources used on your site will be requested by the browser and will be seen by your Express server as incoming requests. Not just the top level page, but all scripts, images, fonts, CSS files, etc... used by your pages.
It's generally not a good idea to define a wide-open top level route handler like this:
router.get('/:category', ...)
Because that will grab ALL top level URLs and leave none for the rest of your site to use. It would probably make more sense to use a structure like this:
router.get('/category/:category', ...)
With a URL of http://localhost:3000/category/entertainment. Then, you can more clearly separate out the actual category requests from all the other requests in your site. Either that or you will have to move ALL other URLs used on your site to routes that come before this and/or use sub-directories in their page such as:
http://localhost:3000/scripts/sw.js
http://localhost:3000/styles/main.css

How do I exclude additional properties using express-validator?

I am using express-validator in my express app, and I am attempting to prevent additional fields being specified on POST requests. This is because I am passing the value of req.body to my ORM to insert into the database, and I want to avoid having to explicitly map between my inserted object and request body alongside adding validators.
Is this possible? I can't seem to find it in the documentation. Using JSON Schema you can do this with additionalProperties: false
After some more research, I found that it's possible to do with with the Matched Data API
In my express controller I can now do;
const { matchedData } = require('express-validator');
(req, res) => {
const matched = matchedData(req, {
includeOptionals: true,
});
db.insert(matched)
...
}

Categories