I'm sorry if this has already been asked, I've been through tons of posts and docs, but nothing quite sounds like what I'm trying to do, even if I think that it's rather simple.
I'm building a tiny web app. It has 2 directories : api (node, working on :8080) and app (angular, working on :4200). They work pretty well separately, my database is ready, everything is fine. Thanks to Json Proxy (I don't use CORS), my API routes are working in my Angular app, for instance :
localhost:4200/api/users URL will GET all my users, no problem. I thought I've done the hardest part, but now I'm stuck on one simple thing : How the hell do I use these API routes in TypeScript for my Angular Service. Like, from this service, I want to manipulate the datas already accessible from localhost:4200/api/users. Nothing more. How to use/call this URL/route in code ?
I'm confused by the lack of doc on this matter, sounds like such a basic thing to me. If anyone can point me to the right direction, I'd be glad. Thanks a lot !
Angular and nodejs routes are different. localhost:4200/api/users
//services.service.ts
callapifunction(name: string, pass: string, confirmPass: string): Observable<any> {
const body = new HttpParams()
.set('username', name)
.set('password', pass)
return this.http.post(
`localhsot:8080/api/users`,
body
)
.pipe(
tap(_ => console.log(_)),
catchError(this.handleError<any>('verify'))
);
}
You can call it any component. Thats it. Angular routers declared in router.
//app-routing.module.ts
import {Route} from '#angular/router';
import { HomeComponent } from './home/home.component';
export const routerConfig: Route[] = [
{
path: '',
children:[
//admin
{
path: 'api/users',
component: DashboardComponent
},
{
path: 'main/login',
component: LoginComponent
},
]},
{
path: '**',
redirectTo: '/'
}
];
Related
I'm coding for an API connection area, that's predominately graphql but needs to have some REST connections for certain things, and have equivalent to the following code:
foo.js
module.exports = {
routes: () => {
return [
{
method: 'GET',
path: '/existing_endpoint',
handler: module.exports.existing_endpoint
},
{
method: 'POST',
path: '/new_endpoint',
handler: module.exports.new_endpoint // <--- this not passing variables
}
]
},
existing_endpoint: async () => {
/* endpoint that isn't the concern of this */
},
new_endpoint: async (req, res) => {
console.log({req, res})
return 1
}
}
The existing GET endpoint works fine, but my POST endpoint always errors out with the console of {} where {req, res} should have been passed in by the router, I suspect because the POST isn't receiving. I've tried changing the POST declaration in the routes to module.exports.new_endpoint(req, res), but it tells me the variables aren't found, and the lead-in server.js does have the file (it looks more like this...), and doing similar with the server.js, also getting similar results, implying that's probably wrong too. Also, we have a really strict eslint setup, so I can't really change the format of the call.
Every example I've seen online using these libraries is some short form, or includes the function in the routes call, and isn't some long form like this. How do I do a POST in this format?
/* hapi, environment variables, apollog server, log engine, etc. */
/* preceeding library inclusions */
const foo = require('./routes/foo')
const other_route = require('./routes/other_route')
const startServer = async () => {
const server = Hapi.server({port, host})
server.route(other_route.routes())
server.route(foo.routes())
}
This is a bug with Hapi in node v16. I just opened an issue.
Your current solutions are either:
Upgrade to Hapi v20
Use n or another method to downgrade to node v14.16 for this project. I can confirm that POST requests do not hang in this version.
I am working on migrating an existing app to a new tech stack that uses Node and MongoDB on the backend and Vue on the frontend. I have a fairly large number of pages that will need to be redirected to new URLs (over 50). I know I can do something like this in the frontend:
const appRouter = new Router({
mode: 'history',
routes: [
{ path: '/a', redirect: '/a2' },
{ path: '/b', redirect: '/b2' },
{ path: '/c', redirect: '/c2' },
]
});
However it doesn't strike me as particularly elegant. I could see keeping the redirects in another file and importing them to keep my router file neater, but that seems like just a formatting benefit.
I'm wondering how other people handle a large number of redirects in Vue? Would this be better to do at the server-level with Node?
If boilerplate is the problem, you can use something like:
const router = new VueRouter({
routes: [
{ path: '/([abc])', redirect: to => {
returect to.path + '2'; // to.path will be like '/a'
}}
]
})
Notice that the part inside () is a regex that can be customized.
I have a fairly large number of pages that will need to be redirected to new URLs
When we talk about redirecting a Uniform Resource Locator (URL) in the context of a Single Page Application (SPA) like Vue with Vue Router, hosted by a web server like Node.js, we might mean one of two things:
we've changed the route of a view within our Vue SPA
we've changed the location of our SPA (the resource) from one location to another.
To determine which kind of redirect you need to do, we can examine how the URL will change. URLs are made up of these components:
scheme:[//[user[:password]#]host[:port]][/path][?query][#fragment]
By default, Vue Router uses the #fragment (hash) portion of the URL to change views, so if this changes then we should redirect using Alias or Redirect.
If any other portion of the URL changes, we should have Node.js return an HTTP status code for redirect, like 301 Moved Permanently or 302 Moved Temporarily.
Normally the solution from #acdcjunior is good enough, but sometimes you may prefer hooking beforeRouteUpdate to implement the redirect.
You can check vue-router: dynamic Routing for more details.
Below is one simple sample is from the official document:
const User = {
template: '...',
beforeRouteUpdate (to, from, next) {
if ( to.match(new RegExp('your_regex_expression'))) {
next('redirect_url')
} else {
// default
next()
}
}
}
Or in main.js by using global guards:
import router from './router'
router.beforeEach((to, from, next) => {
if ( to.match(new RegExp('your_regex_expression'))) {
next('redirect_url')
} else {
// default
next()
}
})
I have a strange problem with my application. I get an error, and I can't solve it. First at all, I installed a new project, so everything is clean. Someone sent me this repo to use for an Angular, Electron and Nodejs Application. Everything worked fine, but then I decided to install an embedded database like sqlite3. For this I found NeDB, and the module is perfect for my needs. First I had the problem, has nothing to do with my general problem, that I can't create a database file. So I read that I can only create files in my application path, because something about Electron and that's working in a browser.
I found the getAppPath() method that is implemented in my app object from the Electron module. Here starts the problem. For hours I tried to get the application path from this object. Finally, I wrote this code.
import { Injectable } from '#angular/core';
var nedb = require('nedb');
import { app } from 'electron';
import * as path from 'path';
#Injectable()
export class DatabaseService {
app: typeof app;
Database: any;
constructor() {
this.app = window.require("electron").app;
this.Database = new nedb({ filename: path.join(this.app.getAppPath(), '/diary.db'), autoload: true, timestampData: true });
var scott = {
name: 'Scott',
twitter: '#ScottWRobinson'
};
this.Database.insert(scott, function(err, doc) {
console.log('Inserted', doc.name, 'with ID', doc._id);
});
}
}
And I get this error.
I found this posting, but I don't really understand what the post is trying to tell me. I followed the links, but nothing seems to help. Anyone have an idea?
I have been playing around with PouchDB (using express-pouchdb and pouchdb-find) for a while and realized that I needed to work with some streams through Rxjs for my Angular 5/Electron app.
For my current setup, I run express-pouchdb to set up a localized PouchDB for persistence and then in Angular I have the following:
#Injectable()
export class PouchdbService {
private _localdb = 'http://localhost:3000/main';
private _pouchDb: any;
constructor() {
this._pouchDb = new PouchDB(this._localdb);
PouchDB.plugin(PouchDBFind);
this.createIndexes();
}
private createIndexes(): void {
this._pouchDb.createIndex({
index: {
fields: [ 'tags' ]
}
});
this._pouchDb.createIndex({
index: {
fields: [ 'date' ]
}
})
this._pouchDb.createIndex({
index: {
fields: [ 'title' ]
}
});
}
This provides my service to the express app through _localdb property. I could keep the PouchDB express app and just call it through RxDB by rewriting my service and refactoring the code. However, I guess that I need have to call sync on every collection.
Though, I would rather drop the express application if there was a way to run with persistence with RxDB directly.
I ended up using the websql adapter which apparently stores information between application loads and dropped express-pouchdb.
I want to reuse same set of validators on client and server side with Angular 4.4.5 and NodeJS 7.10.1 (latest in Ubuntu repos). I believe it's possible.
My basic idea is to have HTTP endpoint working on NodeJS and Express which accepts POST request with JSON data from Angular form, creates same form with received data and checks it.
My attempts were unsuccessful, I don't know how to use same version of Typescript as Angular uses and how to import component with form. It would be ideal to see some simple example that work. I'll share my attempts soon.
By now I managed to instantiate Component this way.
Create cli.ts to test standalone creation of Angular component:
import 'reflect-metadata';
import { CuComponent } from './app/cu.component';
console.log(new CuComponent())
Run tsc with some settings from tsconfig.json:
tsc -t es5 --lib es2016,dom --experimentalDecorators src/cli.ts
Got output:
CuComponent {
registration:
FormGroup {
validator: null,
asyncValidator: null,
_onCollectionChange: [Function],
_pristine: true,
_touched: false,
_onDisabledChange: [],
controls: { familyName: [Object], givenName: [Object], phone: [Object] },
_valueChanges:
EventEmitter {
_isScalar: false,
observers: [],
closed: false,
isStopped: false,
hasError: false,
thrownError: null,
__isAsync: false },
_statusChanges:
EventEmitter {
_isScalar: false,
observers: [],
closed: false,
isStopped: false,
hasError: false,
thrownError: null,
__isAsync: false },
_status: 'VALID',
_value: { familyName: null, givenName: null, phone: null },
_errors: null } }
Component is created.
After a long search I found a solution. Angular now supports workspaces with libraries and server side rendering of forms (ssr) using Node and Express.js. So Angular 8+ basically already has everything needed.
What I do is I put all my shared code in a library so I can use it in the frontend and also reuse it on a SSR app (validation). I don't think that this is necessary, but a clean structure is helpful.
To create the structure I just used the cli:
Create new workspace.
Generate library for shared code.
Generate application for the frontend (normal ng app).
Generate application for the validation server and run ng add #nguniversal/express-engine on it.
You can find all relevant information on how to do this in the tutorials:
SSR/Universal: https://angular.io/guide/universal
CLI: https://angular.io/cli
Reactive Forms: https://angular.io/guide/reactive-forms
Now I used the generated server.ts and deleted most of it (example handlers).
At fist, I had some problem with JSON parsing. But the body-parser can do it.
// ...
import * as bodyParser from "body-parser";
// ...
export function app() {
const server = express();
server.use(bodyParser.json());
// ...
Then I added this handler:
server.post('/api/validate', (req, res) => {
// createFormGroup is from my code,
// because I generate the form from TypeScript classes.
// You can just use a FormBuilder in your component
// and export the function so you can use it here.
const fg = createFormGroup();
fg.patchValue(req.body);
res.status(200).send({
"accepted" : "VALID" === fg.status
// You can send additional information, like errors
});
});
Calling fg.updateValueAndValidity() does not seem to be necessary as patchValue already does all that.
Time to build and start the server.
Somehow I now have a problem where the build script doesn't work with --prod.
But this does:
ng build; ng run validation:server:production; npm run serve:ssr
You should get:
Node Express server listening on http://localhost:4000
And that's it. Really easy.
I use curl for testing:
curl.exe --data "#data.json" -H "Content-Type: application/json" -X POST http://localhost:4000/api/validate
I don't know how to debug this, but console.log works just fine. And to test the code that you use on this server you should just use unit tests (jasmine) anyway. So even though this is slow to start I'm just glad I can now validate code on the server.
It might make sense to compare req.body and fg.value recursively for equality, to make sure it's still the same data after validation.