Newbie FeathersJS user here. I'm obviously missing some key bit of understanding.
I'm trying to create a simple REST API using MySQL models. I'm attempting to follow the code structure referenced by the docs in this issue thread. Routes I define in my initial app.use() block work, but not those defined after it. Partial code here, rest in this gist
const app = feathers();
app.configure(configuration(path.join(__dirname, '..')));
app.use(compress())
.options('*', cors())
.use(cors())
.use(favicon(path.join(app.get('public'), 'favicon.ico')))
/* THIS ROUTE WORKS FINE */
.use('/', serveStatic(app.get('public')))
.use(bodyParser.json())
.use(bodyParser.urlencoded({
extended: true
}))
.configure(hooks())
.configure(rest())
.configure(socketio())
.configure(models)
.configure(services)
.configure(middleware);
const appModels = app.get('models');
const beerOptions = {
Model: appModels.beer,
paginate: {
default: 15,
max: 50
}
};
/* NEITHER OF THESE ROUTES WORK */
app.use('/beer', service(beerOptions));
// IF YOU DELETE THE DEFINITION ABOVE AND UNCOMMENT
// THIS NEXT LINE, THE ROOT URL GIVES A 404
// app.use('/', serveStatic(app.get('public')));
I don't get any errors when npm starting the app. But, my /beer route just 404s as does any route defined there. I've been through the guides looking for the source of my misunderstanding. But I'm kinda stuck.
Just like in Express the order of middleware (and additionally for Feathers, configure calls) matters. In the case of the generated application, .configure(middleware); has to run last after everything else because it registers a notFound handler which will throw a 404 error. Any middleware after that (except the error handler) will never run.
Related
I have created a REST full APi, which works as I would be expecting if I am running Postman. I run the Test from an index.js file which would have the routes saved as per below file.
const config = require('config');
const mongoose = require('mongoose');
const users = require('./routes/users');
const auth = require('./routes/auth');
const express = require('express');
const app = express();
//mongoose.set();
if (!config.get('jwtPrivateKey'))
{
console.log('Fatal ERRORR: jwtPrivateKey key is not defined')
process.exit(1);
}
mongoose.connect(uri ,{
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
})
.then(()=>console.log('Connected to MongoDB...'))
.catch(err=> console.log('Not Connected, bad ;(', err));
app.use(express.json());
//THis is only for posting the user, e.g. Registering them
app.use('/api/users', users);
app.use('/api/auth', auth);
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}...`));
The real code is happening here. Testing this in Postmon I could establish, that the values are saved in MongoDB.
router.post('/', async (req, res) => {
//validates the request.
const { error } = validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
let user = await User.findOne({email: req.body.email});
if (user) return res.status(400).send('User Already Register, try again!');
user = new User(_.pick(req.body, ['firstName','lastName','email','password','subscription']));
const salt = await bcrypt.genSaltSync(15);
user.password = await bcrypt.hash(user.password, salt);
//Here the user is being saved in the Database.
await user.save();
//const token = user.generateAuthToken();
//const token = jwt.sign({_id: user._id}, config.get('jwtPrivateKey'));
const token = user.generateAuthToken();
//We are sending the authentication in the header, and the infromation back to client
res.header('x-auth-token',token).send( _.pick(user, ['_id','firstName','lastName','email','subscription']));
});
Now my question's are:
How can I call the second code block from a , in one particular html file. When using Action="path to the users.js", the browser opens the js file code but doesn't do anything.
Do I need to rewrite the Post block part so that it would as well include the connection details to the DB? And would this mean I would keep open the connection to MongoDB once I insert Read etc.? Wouldn't this eat a lot of resources if multiple users would e.g. log in at the same time?
Or is there a way how I can use the index.js + the users.js which is refereed in the index.js file together?
All of these are theoretical questions, as I am not quite sure how to use the created API in html, then I created as walking through a tutorial.
Do I need to change the approach here?
After some longs hours I finally understood my own issue and question.
What I wanted to achieve is from an HTML page post data in MongoDB through API (this I assume is the best way how to describe this).
In order to do this I needed to:
Start server for the API function e.g. nodemon index.js, which has the information regarding the API.
Opened VS Code opened the terminal and started the API server (if I can call it like that)
Opened CMD and startet the local host for the index.html with navigating to it's folder and then writting http-server now I could access this on http://127.0.0.1:8080.
For the register.html in the form I needed to post:
This is the part which I didn't understood, but now it makes sense. Basically I start the server API seperatly and once it is started I can use e.g. Postmon and other apps which can access this link. I somehow thought html needs some more direct calls.
So After the localhost is started then the register.html will know where to post it via API.
Now I have a JOI validate issue, though on a different more simple case this worked, so I just need to fix the code there.
Thank You For reading through and Apologize if was not clear, still learning the terminology!
I have several instances of a react-slick carousel. Each of them requires a different set of config options.
Currently, I have the carousel component bundled up via webpack and then deployed to multiple locations. Unfortunately, this means that the bundle is slightly different in each case, as the config file changes the overall bundle! What's the right approach for this solution?
I feel like I can think of the following solutions:
1) Load the config file asynchronously. Seems like a lazy solution, because making an extra round trip is overkill.
2) Try to use require.ensure to split out the config file into it's own chunk.
What's the right approach for this solution?
Thanks!
To reply for point 1, I've managed to accomplish runtime loading of config this way:
import xhr from 'xhr'
class Config {
load_external_config = (cb) => {
xhr.get("config.json", {
sync: true,
timeout: 3000
},(error, response, body)=>{
if(response.statusCode==200) {
try{
const conf = JSON.parse(body);
for(var i in conf) {
this[i] = conf[i];
}
}catch(e){
/* Manage error */
}
} else {
/* Manage error */
}
})
}
}
export let config = new Config();
The class above has two basic functions, on the one hand it is a "singleton", so every time you import it in each file of your project, the istance remain the same and will not be duplicated. On the other hand, through a XHR package it loads (synchronously) an external json file and puts every config voice in its instance as a first level attribute. Later, you will be able to do this:
import { config } from './config'
config.load_external_config();
config.MY_VAR
For point 2 I would like to see some examples, and I will remain tuned to this post for someone more skilled than me.
I have created a reproduction of this bug here (ugly use of Aurelia but to prove the point): https://jberggren.github.io/GoogleAureliaBugReproduce/
If I load Google API and try to list my files in Google Drive my code derived from Googles quickstart works fine. If I use the same code after loading Aurelia I get a script error from gapi stating
Uncaught Error: arrayForEach was called with a non array value
at Object._.Sa (cb=gapi.loaded_0:382)
at Object._.eb (cb=gapi.loaded_0:402)
at MF (cb=gapi.loaded_0:723)
at Object.HF (cb=gapi.loaded_0:722)
at Object.list (cb=gapi.loaded_0:40)
at listFiles (index.js:86)
...
When debugging it seems to be some sort of array check (Chroms says 'native code') that failes after Aurelia is loaded. In my search for an answer I found two other people with the same problem but no solution (Aurelia gitter question, SO Question). Don't know if to report this to the Aurelia team, Google or where the actual problem lays.
Help me SO, you are my only hope.
This is not a perfect solution but works.
aurelia-binding
https://github.com/aurelia/binding/blob/master/src/array-observation.js
Aurelia overrides Array.prototype.* for some reasons.
gapi (especially spreadsheets)
Gapi lib checks to make sure that is it native code or not.
// example
const r = /\[native code\]/
r.test(Array.prototype.push)
conclusion
So, we have to monkey patching.
gapi.load('client:auth2', async () => {
await gapi.client.init({
clientId: CLIENT_ID,
discoveryDocs: ['https://sheets.googleapis.com/$discovery/rest?version=v4'],
scope: 'https://www.googleapis.com/auth/spreadsheets',
});
// monkey patch
const originTest = RegExp.prototype.test;
RegExp.prototype.test = function test(v) {
if (typeof v === 'function' && v.toString().includes('__array_observer__.addChangeRecord')) {
return true;
}
return originTest.apply(this, arguments);
};
});
So the aurelia app gets bootstrapped from the main.js
bootstrap(function(aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging();
aurelia.start().then(() => aurelia.setRoot('app', document.body));
});
The source code tells me there is a router() method you can call on the FrameworkConfiguration which is what aurelia.use gives you.
But the implementation gives you no hooks, it just includes the framework-templating-router.
The reason I want a hook in, is because I want to do an api call in the activate() of the app.js however, I wish to slide in a Navigation Pipeline middleware before the api call is made.
configureRouter is called after activate() which is obvious. This means I can dynamically inject menu items (api behind authorised walls) to build up my initial screen. If I get a 401 it rejects the activate() promise - which I want - however what would be better is if the pipeline step could Redirect('login').
If I were to put custom login the activate() then I would have two places of redirection, but also it just doesn't fit into the aurelia design very well.
There is an alternative solution which is to defer configuring the router till a child view of the app.js but it doesn't seem as nice.
In your app.js, you can do this:
import {Router} from 'aurelia-router';
#inject(Router)
export class App {
constructor (router) {
this.router = router;
this.router.configure(config => ...);
}
activate () {
...
}
}
Essentially....you don't have to use the configureRouter method. It's just there as a convenience. Using the constructor allows more flexibility in this case.
I'm working on an AngularJs/MVC app with Web API etc. which is using a CDN. I have managed to whitelist two URLs for Angular to use, a local CDN and a live CDN (web app hosted in Azure).
I can successfully ng-include a template from my local CDN domain, but the problem arises when I push the site to a UAT / Live environment, I cant be using a template on Localhost.
I need a way to be able to dynamically get the base url for the templates. The location on the server will always be the same, eg: rooturl/html/templates. I just need to be able to change the rooturl depending on the environment.
I was thinking if there was some way to store a global variable, possibly on the $rootScope somewhere that I can get to when using the templates and then set that to the url via Web API which will get return a config setting.
For example on my dev machine the var could be http://Localhost:52920/ but on my uat server it could be https://uat-cdn.com/
Any help would be greatly appreciated as I don't want to store Js, css, fonts etc on the CDN but not the HTML as it feels nasty.
Thanks I'm advance!
I think it's good practice to keep environment and global config stuff outside of Angular altogether, so it's not part of the normal build process and is harder to accidentally blow away during a deploy. One way is to include a script file containing just a single global variable:
var config = {
myBaseUrl: '/templates/',
otherStuff: 'whatever'
}
...and expose it to Angular via a service:
angular.module('myApp')
.factory('config', function () {
var config = window.config ? window.config : {}; // (or throw an error if it's not found)
// set defaults here if useful
config.myBaseUrl = config.myBaseUrl || 'defaultBaseUrlValue';
// etc
return config;
}
...so it's now injectable as a dependency anywhere you need it:
.controller('fooController', function (config, $scope), {
$scope.myBaseUrl = config.myBaseUrl;
}
Functionally speaking, this is not terribly different from dumping a global variable into $rootScope but I feel like it's a cleaner separation of app from environment.
If you decide to create a factory then it would look like this:
angular.module('myModule', [])
.factory('baseUrl', ['$location', function ($location) {
return {
getBaseUrl: function () {
return $location.hostname;
}
};
}]);
A provider could be handy if you want to make any type of customization during config.
Maybe you want to build the baseurl manually instead of using hostname property.
If you want to use it on the templates then you need to create a filter that reuses it:
angular.module('myModule').filter('anchorBuilder', ['baseUrl', function (baseUrl) {
return function (path) {
return baseUrl.getBaseUrl() + path;
}
}]);
And on the template:
EDIT
The above example was to create links but if you want to use it on a ng-include directive then you will have a function on your controller that uses the factory and returns the url.
// Template
<div ng-include src="urlBuilder('path')"></div>
//Controller
$scope.urlBuilder = function (path) {
return BaseUrl.getBaseUrl() + path;
};
Make sure to inject the factory in the controller