Node.js - how to implement api/:product_url - javascript

I am new to node.js and I am using Yeoman to fetch a product details from the list of products. I am getting data from a triple store database and converting to json. The only unique ID is in the form of URL with an hash encoded at last.
In demo.controller.js:
exports.index = function(req, res) {
res.json(response);
}
In index.js:
var controller = require('./demo.controller');
var router = express.Router();
router.get('/', controller.index);
module.exports = router;
Here, response output is the following json structure for URL/api/product_list:
[{
"url":"http://example.com/demo/32b9jkd902n2"
"product":"stack",
"name":"test",
"price":"233"
}, {
"url":"http://example.com/demo/5nf9djdkdks0"
"product":"flow",
"name":"dev",
"price":"433"
}]
Now, I want to get details of each product. something like URL/api/product_list/:product_url ?
Basically, when I access url with product_url from the list of products, I should be able to get the product details.
Can someone help me in implementing the URL with /api/product_list/:product_url with an output of single product?

So, as there is no other unique identifier besides the URL you could to one of the following:
Parse unique ID from the url to /api/product_list as id to the output and use that - /api/product_list/:id
Generate a hash (md5, sha1) of the whole url to the output as id and use that as an unique id.
Note: never used Yeoman before, so I don't know if you have some limitations from there.
I think /api/product_list/:url will not fly, and if it does, it sure will look ugly.

Related

Nodejs - How to route by name in url with express and mongoose?

I have an Express 4 server with CRUD routes for authors:
router.get('/authors', AuthorsController.index);
router.post('/authors', AuthorsController.store);
router.get('/authors/:name', AuthorsController.show);
router.put('/authors/:name', AuthorsController.update);
router.delete('/authors/:name', AuthorsController.remove);
Most tutorials I find will have the routes be /authors/:id and then do Author.findById(req.params.id). I'd instead like it to be the authors name so there are human readable URLs, like: /authors/jk-rowling.
Do I need to store the hyphenated string on the Authors model, what's the best way to achieve this with express and Mongoosejs?
My authors controller currently looks like this:
const AuthorsController = {
async index(req, res){
const authors = await Author.find().populate('books');
res.send(authors);
}
};
(I'm using express-async-errors package for the async-await functionality with express)
What's the best way to establish routes with human readable URLs for a CRUD REST API with Express and Mongoose?
You can index name field and in your views, find by name (assuming name is attribute of Author)
This requires no change in terms of db model. You can search via both id or name if needed.
For example
router.get('/authors/:name', AuthorsController.show);
will have below view
const AuthorsController = {
async show(req, res){
const authors = await Author.find({'name':req.params.name}).populate('books');
res.send(authors);
}
};
As you mentioned in problem, you will have to generate slug for name like one containing hyphens in place of spaces or other special characters which will be stored in model as well.

Passing mongoose documents to view and use in script tag node.js

I have an app running in Node.js with Express, and I wanted to dinamically change options on select object with jquery. This is actually not a big problem, but I'm having troubles on using the res.render parameters (which are mongoose documents) in the script tag. I use them without any trouble on the html (jade actually), but in the script tag I get a problem with the ObjectId not being a String.
This is an extract of the code:
On the backend:
router.get("/new", function(req, res){
res.render("session/documentos/new",
{
services: res.locals.services
});
});
On the view
block content
div
h1(class="text-center") New document
form(id="newDoc" action="/session/documentos" method="POST")
div(class="tab") Service:
div(class="form-group")
select(class="form-control" name="svc" id="svc")
option(value="undefined" disabled selected) Choose one
for service in services
option(value=service._id)=service.name
script.
$(document).ready(function() {
var sessLenght = 0;
var selectedSvc = #{services};
$("#svc").change(function(){
console.log("Service changed: " + selectedSvc);
});
});
And this is the error I'm getting:
Console error
And in Sources:
Source error on ObjectId
So I'm being able to use with no troubles the "services" collection of documents, but when trying to use them on the script tag I'm getting problems with the ObjectId element.
I was thinking that one soution would be to convert to string the ObjectId when querying the database, but I think there might be a cleaner solution to that. Which might be the best way to solve the issue?
Any thoughts appreciated! Thanks in advance
Try to change var selectedSvc = #{services};
to var selectedSvc = !{services};
or var selectedSvc = !{JSON.stringify(services)};

Display data from database (using mongodb) in hbs/html file Node.Js

I started studying node.js, and now I'm trying to do a "Todo-App".
I'm trying to find the best way to transfer data from my database (using mongodb) into my hbs files, so I could display it.
From the server.js -> server to the hbs -> client (correct to me if I'm wrong please, by assuming that server.js is the server of course and the hbs file is the client)
So, I succeeded to do it by passing an array.
but when I'm trying to display in html desing, it just looking bad.
The code:
app.get('/allTasks',(req,res)=>{ //get (go to) the allTasks (hbs file)
Todo.find().then((todos) => {
console.log(todos);
var arrayOfTodos = [];
todos.forEach(function(element){
console.log("\n\n\n\n\n elemnt details: ",element.text + "\n",element.completed+"\n");
arrayOfTodos.push(element.text,element.completed);
});
res.render("allTasks.hbs", {
pageTitle: "Your tasks: ",
todos: arrayOfTodos
});
});
});
The result is:
You can see a picture
As you can see, its just looking bad... cause it just display an array,
an I want to display each task seperately.
Any tips?
Thanks a lot,
Sagiv
Instead of using push just do:
Todo.find().toArray(function(err, result){
arrayOfTodos = result;
})
Once you have your array, the design got nothing to do with mongodb. You will need to learn how to use your render technology. You need to touch your html template, so you should start by posting that.
The problem solved.
I just had to learn how to handle the data in the hbs side.
so the code is: (in hbs)
{{#each todos}}
{{missionNumber}} <br>
{{text}}<br>
completed = {{completed}}<br><br>
{{/each}}
as you can see, the each is a loop , that pass on the todos parameter (my array)
and i just have to display the data in the way i want it to be displayed.
thanks for your help.

Serve dynamic javascript file with nodejs

Questions
How to serve javascript file dynamically? Specifically, the scripts maintain most of its body but with some variables changable (imagine HTML Jade template, but this is for pure javascript).
Scenario
When user or browser (http GET in general) visits /file.js passing parameter api, e.g. /file.js?api=123456, I would like to output pure javascript where I can take that 123456 and put in inside of my code, dynamically. Content-Type is application/javascript.
Sample:
var api = #{req.query.api}; //Pseudo
//The rest of my javascripts template
...
From my main .js file, I have set up the route:
app.get( '/file.js', function( req, res ) {
//Pseudo code that I would like to achieve
var name = req.query.name;
res.render( 'out_put_javascript_file_from_jade_file.jade', { name: name } );
});
So when a person visits /file.js, the script file will be rendered differently based on the parameter api passed in the URL. The only possible dynamic way I can think of is using Jade, but it doesn't allow pure javascript template. I believe there must be other solutions.
Please excuse my explanation. The problem is somewhat like this: How to generate a pure JavaScript file with Jade
If you want to do something quick and dirty, then you can do something like this (based on your example in the comments).
App init - read the .js template file and cache it:
// this should be async, but hey, not teaching you that part here yet
var fileJs = fs.readFileSync('file.js.template');
File.js:
(function() {
$(window).on('load', function() {
alert('Your api key is API_KEY_CONST');
});
})();
Request:
GET /api/file.js?key=123
Router:
app.get('/api/file.js', function(req, res) {
var key = req.query.key;
var key = fetchKeyFromDBSync(); // just to make it easier here, no async.
var out = fileJs.replace(API_KEY_CONST, key);
res.setHeader('content-type', 'text/javascript');
res.write(out);
res.end();
});
Now, this is really dumb and you should not try it at home, but it simply demonstrates how to do what you wanted.
Edit:
Depending on the file length, you might perform a bit better if you put the chunks of the file into an array, like:
var fileChunks = ['(function(){ blablabla;', 'var myAPIKey=', 'KEY_PLACEHOLDER', '; alert (myAPIKey);', '})()']
So later when you're resolving it with the real API key, you join the file.
fileChunks[2] = '12345';
var responseData = fileChunks.join('');
res.write(responseData);
But your last-accessed api key is then held in an array. Not quite future proof, but it shouls work if you need something quick.

How to access variable on client with express-expose?

I want to set a javascript variable on my index.html page when the page is returned by express.js. I am trying to use the express-expose middleware but I am not sure how to get variable set in the static html page that is rendered.
On the server I have:
app.get('/', function(req, res) {
var user = { name: 'tj' };
res.expose(user, 'user');
res.render(config.rootPath + '/public/index.html');
});
Index html I have
<script>
var myUser = user;
</script>
What I need is myUser to contain the json object user.
Examples I have seen use jade which i am not using.
You need to expose them like this
app.expose('var some = "variable";');
https://github.com/visionmedia/express-expose#raw-javascript
The way you're doing it, they're only available to the templating engine (jade). In which case you'll have to do something like this
script var some = #{variable}

Categories

Resources