Does app.js get processed only once?. In that case, does it make sense to run setup queries in app.js so that I don't have to run it on every request?.
I have a table to countries and regions that I need in several requests.
I am looking at an implementation something like this https://stackoverflow.com/a/21133217/406659
No putting this in app.js does not make sense. I would create a models folder and encapsulate all of your database logic in a module within that folder. Then on startup of the app (ie on app.listen() callback) I would call a method from that module which does the setup for me. For example:
Some DB module in models
module.exports = {
setup: () => {
// Set up logic here - checking if tables exist etc
}
}
Then in app.js or equal
require <SOME DB MODULE>
app.listen(<PORT>, () => {
<SOME DB MODULE>.setup();
})
Note this is a generalised approach as I don't know the specifics of your setup - This approach just ensures encapsulated and reusable code. I've also used ES6 syntax where possible.
Hope this helps
Dylan
Related
I have data (JSON) in a file that I want to expose through an API. I know the data at build time but I don't know how to create static API routes or even expose the files through the API routes statically.
I googled two solutions for this:
Create a static page that returns a JSON file (couldn't find a solution, it always returned HTML).
Use the pages/api/[something] to generate the API (but it seems to always be dynamic).
My last resort is to try to access the file through the function on the /pages/api/[something].js but this is dynamic and not static.
The dynamic function that comes by default in /pages/api/hello.js folder:
export default (req, res) => {
res.statusCode = 200;
res.json({ name: "John Doe" });
};
What is the typical strategy here? I feel that I'm missing something.
FWIW, this is the dynamic way I found to generate the API dynamically:
// on file /pages/api/[article].js
import { getArticle } from "../../lib/api";
export default (req, res) => {
// It gets an article from a file, also can be used with getStaticProps
const article = getPost({article: req.article});
res.statusCode = 200;
// returns the JSON.
res.json(article);
}
I'd still prefer to have it static to not need any serverless functions running.
Use the pages/api/[something] to generate the API (but it seems to always be dynamic).
No it's not dynamic. From [something].js,if you export getStaticPath(this will generate static routes for you) and getStaticProps(this will inject the data to be served from corresponding routes), next build will have your static files generated, and ready to be served as api pages with raw json data.
Hope this had been what you were trying to solve.
I have been trying to learn NodeJS for quite some time now. All the books and tutorials seems to follow similar pattern of structuring their code. Example -
const express = require('express');
const app = express();
app.set('view engine','hbs');
app.get('/', (req, res) =>{
res.render('index');
});
app.get('/getName', (req, res) =>{
// Mock DB call to fetch Name
res.render('displayName');
});
app.listen(3000, () => {
console.log("Started server on port : 3000");
});
As you can see above, the /getName controller is performing DB call as well as returning the view. So the business logic as well as the CRUD operation is being done at the same place.
I come from the world of JAVA and there we do it slightly differently. For example, a Spring Boot application would contain the following structure -
DTO
Repository
Service
Controller
So, controller classes are the actual endpoints which do not perform any business logic but call the underlying service class to handle all that. The service classes implement the business logic and persist/fetch data required for it with the help of the repository classes. The repository on the other hand handles the CRUD operations.
This seemed like a sane way to develop software. Given that each class has their defined roles, it becomes really easy to handle any change.
I understand the NodeJs is a dynamic but -
1. Is there a way to separate out the functionality like we do in Spring ? If not,
2. How to structure large projects having multiple endpoints and DB transactions.
Regards
EDIT -
Consider the following scenario -
I have a requirement, where I need to fetch a list of users from the database whose status is True ( assume status is a boolean field in the model ).
In Java -
#Service
public class UserService {
#Autowired
UserDetailRepository userDetailRepository;
#Override
public UserDetail getUserDetail (boolean status) {
UserDetail userDetail = UserDetailRepository .findUserDetailByStatus(status);
return userDetail ;
}
Controller.java -
#GetMapping("/getUserDetails")
public ArrayList<UserDetail> getUserDetail(){
return UserService.getUserDetail(true);
}
Now, if the requirement changes and there needs to be a new endpoint that returns only top 10 user details whose status is true. In that case, we can add a new controller and just limit the returned results to 10. We can make use of the same business logic/ service class.
Controller.java
#GetMapping("/getUserDetailsTop10")
public ArrayList<UserDetail> getUserDetail(){
List<UserDetails> users = UserService.getUserDetail(true);
// Filter the list to send top 10
// return users .
}
If I have to implement the same use case in NodeJS, I'll have to write the business logic to fetch the user twice -
const express = require('express');
const app = express();
app.set('view engine','hbs');
app.get('/getUserDetails', (req, res) =>{
// Call DB and get users whose status is True
res.send(userdetails);
});
app.get('/getUserDetailsTop10', (req, res) =>{
// Call DB and get users whose status is True
// Filter the returned results and limit the result to 10 values only
res.send(userdetails);
});
app.listen(3000, () => {
console.log("Started server on port : 3000");
});
At best, I can abstract away this logic into a function, that will return a list of users with status True but then again this approach is not very scalable. There has to be a complete separation of Business logic from controller.
Not really an answer... but some thoughts, as I come from C# and started as a NodeJs developer 3 years ago.
Dependency Injection
This is (sadly) rarely used in many NodeJs projects that I see. There are some npm modules that provide this feature, but none of them have convinced me with a proper approach and API. Dependency Injection is still perfectly possible, only, a bit uglier because of some boilerplate code you have to write. So sadly no easy #autowire approaches. So yes you can do Dependency Injection like with Spring, but not as convenient. But let my opinion not stop you from researching Dependency Injection libraries for node.
Architecture
You can still use the concepts of DTOs, Repositories, Services and Controllers. Only for some (odd) reason, the majority of tutorials and guides out there forget about common sense architecture and just throw everything within a single controller. Don't let them seduce you in forgetting about the concepts you learned in Java. Not that OOP and Java doesn't have flaws, but there is a difference in "writing JavaScript style code" and "let's forget about proper architecture all together".
Do note that you might see some more "functional programming" patterns rise in the NodeJs community, which is not bad (but neither is OOP).
How to structure large projects having multiple endpoints and DB
transactions.
Ignore the bad examples you see out there, just follow your gut feeling from your Java experience how to structure your code, with the right layers, responsibilities and Design Patterns. Only keep in mind that you don't have interfaces and there is no easy alternative to that. So you'll have to learn to work your way around that, but you can still write elegant code without them.
Middleware
Middleware is a common concept for NodeJs applications, they are similary-ish to the proxy/aspect oriented programming style. You might find example projects with excessive amount of middleware, don't let yourself be tempted by that either. Middleware is good for auth/serialisation/headers/security but not for business logic. I've seen middleware hell and middleware driven development, it ain't pretty.
Repository
A lot of people use directly the MongoDb/Mongoose/SQL client without using the adapter pattern like Repository, leaking MongoDb queries all over their solution.
My advice for you would be, just use the same structure and approach you are familiar with, but with the tools that JavaScript gives you. I genuinely love JavaScript, but it makes me cringe when I look at the lack of design and architecture that I see in the mainstream resources, sure small projects and PoC's don't need extensive design, but often when project grow, they don't clean up. How you structure a project should be agnostic to the language and framework you are writing in.
Happy coding 😄
An idea:
const express = require('express');
const app = express();
const { userDetails } = require('./usersBusinessLogic.js')
app.set('view engine','hbs');
app.get('/getUserDetails', async (req, res) =>{
const limit = parseInt(req.query.limit || '0')
if (IsNaN(limit)) {
res.status(400)
return res.end('limit expected to be a number')
}
const detailsResponse = await userDetails({ limit })
res.send();
});
And then you write your logic as function userDetails({ limit, ...rest } = { limit: 0 }).
In another file i.e. usersBusinessLogic.js:
async function userDetails({ limit, ...restOfTheOptions } = { limit: 0 }) {
console.log({ limit, restOfTheOptions }) // TODO logic here.
// const result = await db.find('users', {...})
// return serialize(result)
}
// function serialize(result) {
// return JSON.stringify(result)
// }
module.exports = {
userDetails
}
After which you can call GET /userDetails or GET /userDetails?limit=10.
Let me know what do you think.
UserService.js
import { userDetailRepository } from '../models/user';
class UserService {
getUserDetail (status) {
const userDetail = UserDetailRepository.findUserDetailByStatus(status);
return userDetail;
}
}
export const userService = new UserService();
UserController.js
import { userService } from '../services/user';
#RouterAdapter
class UserController {
#GetMapping("/getUserDetails")
getUserDetail() {
return userService.getUserDetail(true);
}
#GetMapping("/getUserDetailsTop10")
getUserDetailsTop10() {
return userService.getUserDetail(true).slice(10);
}
}
export const userController = new UserController();
app.js
import * as express from 'express';
import { userController } from './controllers/user';
const app = express();
app.set('view engine','hbs');
app.use(userController);
app.listen(3000, () => {
console.log("Started server on port : 3000");
});
I intentionally "warp" my js code to match with java style so perhaps you feel at home. Personally I don't write js this way, I prefer using function way more than class.
I did not include the implementation of two decorators (#RouterAdapter, #GetMapping) I used, that's a detail not related to the discussion. I can assure you this is doable in js. The only thing missing is that js doesn't have runtime method overload, so I have to name 2 diff controller methods.
The point I'm making here is that design patterns are mostly language agnostic. If you're familiar with the lang, you can always find a way to handle separation of concern well.
Now I intentionally use class in above example, but a function acting as a UserService doesn't make it less reusable. I don't see why you think "it doesn't scale".
I'm trying to get a practical grasp of MVC model implementation (not the conceptual understanding) in JavaScript.
As for the start, I thought it would be worth making an effort and try building a MVC app in plain JS. I've read dozens of articles and book chapters referring to MVC and its variations. Of course I googled lots of examples to see how it's done for real. The most understandable and with the proper meaning is in my opinion this one:
https://github.com/tastejs/todomvc/tree/master/examples/vanillajs
In the end, I was able to refactor my own app in the todomvc-vanillajs way.
However, there is one thing that still bothers me. All these apps and examples are very basic, so there is only one Model, View and Controller specified for the whole app.
What if I wanted to add more (equally complex) features to such app?
Should I add them one by one to my controller.js view.js and model.js files or whether should I stop developing spaghetti code and add new files instead, thus creating new models, controllers and views for each of the new feature individually?
It seems to me, that every feature should have its own view, controller and model, or at least, could have, depending on the subjective evaluation. But I'm not quite sure how such implementation should look at this situation in terms of code structure, namespacing etc.?
What if I want to imitate a scale by creating multiple views, models and controllers on every single functionality like e.g. handling an "add task to the list" or "delete the task" actions.
For the purpose of my dilemma, I've created my own MVC draft, which has two models, controllers and views. Whether such an approach would make sense? What happens when further developing my application, I quickly get to the point where I have dozens and more specific (coresponding) models, views and controllers.
Heres is the aforementioned fiddle.
;(function () {
'use strict';
/**
* #file ./App.js
*/
var App = {
Model : {},
Controller : {},
View : {}
};
console.log('start');
window.App = App;
})();
/* -------------Views-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
/**
* #file Views/buildAdd.js
*/
var buildAdd = {
// render
// event
// pass the reference to event handler in Controller
};
App.View.buildAdd = buildAdd;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
/**
* #file Views/buildDelete.js
*/
var buildDelete = {
// render
// event
// pass the reference to event handler in Controller
};
App.View.buildDelete = buildDelete;
})(App);
/* -------------Controllers-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var addController = {
// handle the event and decide what the Model has to do
// handle the response from Model and tells the View how to update
};
App.Controller.addController = addController;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var deleteController = {
// handle the event and decide what the Model has to do
// handle the response from Model and tells the View how to update
};
App.Controller.deleteController = deleteController;
})(App);
/* -------------Models-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var addModel = {
// send request
// get response
};
App.Model.addModel = addModel;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var deleteModel = {
// send request
// get response
};
App.Model.deleteModel = deleteModel;
})(App);
/* -------------separate-file-----------------------*/
Thus, I found this question very similar to mine, but the provided answers are not entirely satisfactory, at least to me.
Check my implementation of so called Single Page Application framework. The whole thing is of 60 lines of code. It uses jQuery but can be implemented in VanilaJS.
Basic idea is simple - your app is just a collection of pages a.k.a. views
<section id="route1" src="content1.htm" />
<section id="route2" src="content2.htm" />
...
Sections id's define set of possible "routes"
SpAPP catches browser's navigate event and load requested view on the route.
And partial content1..N.htm files contain view markup, setup and controller functions.
Data model here is JS data received from server and stored in memory or in local storage.
As of MVC frameworks in general... You cannot bring joy to everyone and free of charge. That small SpAPP thing that can easily be understood and adjusted to particular project's needs is a way to go I think.
Looking at my experience in Ruby on Rails framework, I don't always need all three elements of MVC pattern. Sometimes you need a model for a database but it's only accessed internally, not by the client. Or sometimes you only need a generic helper class.
As a convention, the files are split, each one has its own controller, model and view, following a naming convention, maybe something like:
articles-view.html
articles-controller.js
articles-model.js
Views are split for each action in the controller:
articles-index.html
articles-show.html
articles-update.html
...
articles-controller.js
articles-model.js
Inside the controller, you will have the "actions", the functions for everything semantically related to an Article in a blog.
function ArticlesController() {
function index() { ... }
function create() { ... }
function edit() { ... }
...
function delete() { ... }
}
In models, you basically have the class / prototype itself, something that is built with the given data.
function Article() {
this.name = "";
this.author = "";
this.text = "";
this.dateCreated = "";
}
And finally, your views should have element with the same name used in the model.
If you have a basic CRUD system, for example, you can have just one controller and one model, but different views (one for listing all items, one for creating and editing, one for just one item, etc).
Taking examples from Rails and NodeJS, a way to write less code for the views is by using "partials". Common HTML structures can be saved on a file and imported into other HTML files as needed, such a form, the headers, the footer of a page and so on.
Example:
Instead of having a form on articles-create.html and another on articles-edit.html, you will have something like:
_articles-form.html <- this is your partial!
articles-create.html
articles-edit.html
"_articles-form.html" will be imported / appended into the create and edit pages.
Other common features can be consider as "Helpers". They are not a letter in "MVC", but often used. Like the Datepicker library, a simple validation function, a parser, etc. Something that can be used by everyone, not a specific feature of a class.
The project structure could be something like:
app/
app/controllers/
app/controllers/articles-controller.js
app/models/
app/models/articles-model.js
app/views/
app/views/articles/
app/views/articles/index.html
app/views/articles/create.html
app/views/articles/edit.html
app/views/articles/delete.html
app/views/articles/_form.html
Also, having a Manager functionality as you described above, will help you load all the data needed. Some function that maybe will read a json file, looking for the feature's name and parsing through the file's names, loading everything.
The manager would check if there is a model file, a controller file and a folder with N view files in it, containg the word "articles". The same would happen to "authors", "comments", "users" and so on.
I understand that you are proposing this question for study reasons and you took JS as a personal preference, so I´m not saying "don't try it" or something like that. But something to consider: the MVC pattern tackles applications that involves both client and server side. Unless your are developing on a full stack with NodeJS and MongoDB (or other similar technologies), HTML and Javascript are more on the View side of the application (or as helpers).
And if you are developing something like a library, you'll end up putting everything on a single file and minifying/uglifying it. Take JQuery as an example. Javascript developers often go with the Module pattern. They create an object, expose methods and variables that the other developer needs to know and that's it.
So, probably (but not for sure, you never know!), you won't see or work on many vanilla Javascript applications implementing MVC pattern.
I would like to have a sub part in my application:
For instance, all requests send to www.example.com/backoffice/user should be redirected in my BackofficeUserController.js.
I ue sails.js, I know I have to do that with the config/routes.js, I just don't know how.
I tried this:
'/backoffice/:controller/:action?': {
controller : 'backoffice' + ':controller',
action : ':action'
}
But it doesn't works. Any idea?
The doc doesn't explains too much about dynamic routes. http://sailsjs.org/#!documentation/routes
This is actually a decent use-case for nested controllers. If you do sails generate controller backoffice/user, you'll end up with a controllers/backoffice/userController.js file corresponding to a controller class called Backoffice/UserController. All requests to /backoffice/user/:action will then be automatically routed to that controller.
All captured params get passed to the controller's action method on your request object. Maybe you should be more explicit when defining your routes or use your UserController as a proxy.
You could have backoffice users?
'/user/backoffice': 'UserController.backoffice'
or having a backoffice controller handle user requests
'/backoffice/user/:id': 'BackofficeController.user'
or (i'm not sure if controllers are global but you could require the controller from another controller and use its methods inside UserController)
module.exports = {
'/backoffice/user/:id': 'UserController.backoffice'
};
and then in your UserController
var BackofficeController = require('./BackofficeController');
module.exports = {
user: function(req, res) {
// Do something using BackOffice methods conditionally?
}
};
Many ways to achieve the same result. Not sure what the best approach is since I haven't run into this personally. But I would suggest sticking with Sailsjs conventions.
I have a Meteor template that should be displaying some data.
Template.svg_template.rendered = function () {
dataset_collection = Pushups.find({},{fields: { date:1, data:1 }}, {sort: {date: -1}}).fetch();
a = moment(dataset_collection[0].date, "YYYY/M/D");
//more code follows that is also dependent on the collection being completely loaded
};
Sometimes it works, sometimes I get this error:
Exception from Deps afterFlush function: TypeError: Cannot read property 'date' of undefined
I'm not using Deps in any context. As I understand it, the collection is being referenced before it is completely finished loading.
I therefore would like to figure out how to simply say "wait until the collection is found before moving on." Should be straightforward, but can't find an updated solution.
You are right, you should ensure that code depending on fetching the content of a client-side subscribed collection is executed AFTER the data is properly loaded.
You can achieve this using a new pattern introduced in Meteor 1.0.4 : https://docs.meteor.com/#/full/Blaze-TemplateInstance-subscribe
client/views/svg/svg.js
Template.outer.onCreated(function(){
// subscribe to the publication responsible for sending the Pushups
// documents down to the client
this.subscribe("pushupsPub");
});
client/views/svg/svg.html
<template name="outer">
{{#if Template.subscriptionsReady}}
{{> svgTemplate}}
{{else}}
Loading...
{{/if}}
</template>
In the Spacebars template declaration, we use an encapsulating outer template to handle the template level subscription pattern.
We subscribe to the publication in the onCreated lifecycle event, and we use the special reactive helper Template.subscriptionsReady to only render the svgTemplate once the subscription is ready (data is available in the browser).
At this point, we can safely query the Pushups collection in the svgTemplate onRendered lifecycle event because we made sure data made its way to the client :
Template.svgTemplate.onRendered(function(){
console.log(Pushups.find().fetch());
});
Alternatively, you could use the iron:router (https://github.com/iron-meteor/iron-router), which provides another design pattern to achieve this common Meteor related issue, moving subscription handling at the route level instead of template level.
Add the package to your project :
meteor add iron:router
lib/router.js
Router.route("/svg", {
name: "svg",
template: "svgTemplate",
waitOn: function(){
// waitOn makes sure that this publication is ready before rendering your template
return Meteor.subscribe("publication");
},
data: function(){
// this will be used as the current data context in your template
return Pushups.find(/*...*/);
}
});
Using this simple piece of code you'll get what you want plus a lot of added functionalities.
You can have a look at the Iron Router guide which explains in great details these features.
https://github.com/iron-meteor/iron-router/blob/devel/Guide.md
EDIT 18/3/2015 : reworked the answer because it contained outdated material and still received upvotes nonetheless.
This is one of those problems that I really wish the basic meteor documentation addressed directly. It's confusing because:
You did the correct thing according to the API.
You get errors for Deps which doesn't point you to the root issue.
So as you have already figured out, your data isn't ready when the template gets rendered. What's the easiest solution? Assume that the data may not be ready. The examples do a lot of this. From leaderboard.js:
Template.leaderboard.selected_name = function () {
var player = Players.findOne(Session.get("selected_player"));
return player && player.name;
};
Only if player is actually found, will player.name be accessed. In coffeescript you can use soaks to accomplish the same thing.
saimeunt's suggestion of iron-router's waitOn is good for this particular use case, but be aware you are very likely to run into situations in your app where the data just doesn't exist in the database, or the property you want doesn't exist on the fetched object.
The unfortunate reality is that a bit of defensive programming is necessary in many of these cases.
Using iron-router to wait on the subscription works, but I like to keep subscriptions centrally managed in something like a collections.js file. Instead, I take advantage of Meteor's file load order to have subscriptions loaded before everything else.
Here's what my collections.js file might look like:
// ****************************** Collections **********************************
Groups = new Mongo.Collection("groups");
// ****************************** Methods **************************************
myGroups = function (userId) {
return Groups.find({"members":{$elemMatch:{"user_id":userId}}});
};
// ****************************** Subscriptions ********************************
if(Meteor.isClient){
Meteor.subscribe("groups");
}
// ****************************** Publications *********************************
if(Meteor.isServer){
Meteor.publish("groups", function () {
return myGroups(this.userId);
});
}
I then put collections.js into a lib/ folder so that it will get loaded prior to my typical client code. That way the subscription is centralized to a single collections.js file, and not as part of my routes. This example also centralizes my queries, so client code can use the same method to pull data:
var groups = myGroups(Meteor.userId());