Feathersjs know when server is offline(from the client) - feathersjs

I have an Angular app that connects to the Feathers API with socket.io and feathers-reactive using #feathersjs/authentication-client. This works great!
This is my client code:
import * as feathersRx from 'feathers-reactive';
import * as io from 'socket.io-client';
import feathers from '#feathersjs/feathers';
import feathersSocketIOClient from '#feathersjs/socketio-client';
export function fInit(options: FeathersOptions): void {
// eslint-disable-next-line #typescript-eslint/no-var-requires
const _feathersAuthClient = require('#feathersjs/authentication-client').default;
const _feathersApp = feathers();
const _socket: SocketIOClient.Socket = io(options.feathersIP, {
transports: ['websocket'],
forceNew: true
});
_feathersApp.configure(feathersSocketIOClient(_socket))
.configure(_feathersAuthClient({
storage: options.storage
}))
.configure(feathersRx({
idField: '_id'
}));
}
In this scenario I just started the app but not the API. Feathers gets initialized and looks for the server not finding it.
What I would like to know in the Angular app is when is the server down?
Is there any type of event, subscription, callback or anything else that I can get from the above code whenever an error like this occurs?
Any help/tip/pointer with this matter is greatly appreciated!
Thanks in advance
*Given the nature of the config with all the socketio, authentication-client, and feathers-reactive, I don't even know where the error is coming from.

So the message/error is from socket.io and socket.io has the following events that you can listen to like:
_socket.on("disconnect", () => changeServerState('disconnected'));
_socket.on("connect", () => changeServerState('connected'));
_socket.on("connect_error", () => changeServerState('error'));
_socket.on("connect_timeout", () => changeServerState('connect_timeout'));

Related

Google Functions v2 and NestJs

I'm looking into spinning up an api with nest using google cloud functions v2, looks like some people is doing it using nx: https://itnext.io/a-perfect-match-nestjs-cloud-functions-2nd-gen-nx-workspace-f13fb044e9a4, can this be done using nx?
I'm looking into a more vanilla example just using functions-framework and nest. Can somebody point me to any repo or example?
Thanks!
Nx is just tooling. It should be the same as you implement without NX. Can you try it in a normal Nestjs project?
// main.ts
const server = express()
import { http } from '#google-cloud/functions-framework'
export const createNestServer = async (expressInstance) => {
const app = await NestFactory.create(AppModule, new ExpressAdapter(expressInstance))
const globalPrefix = 'api'
app.setGlobalPrefix(globalPrefix)
app.enableCors()
return app.init()
}
createNestServer(server)
.then((v) => {
if (environment.production) {
Logger.log('🚀 Starting production server...')
} else {
Logger.log(`🚀 Starting development server on http://localhost:${process.env.PORT || 3333}`)
v.listen(process.env.PORT || 3333)
}
})
.catch((err) => Logger.error('Nest broken', err))
http('apiNEST', server)

Is it possible to perform an action with `context` on the init of the app?

I'm simply looking for something like this
app.on('init', async context => {
...
})
Basically I just need to make to calls to the github API, but I'm not sure there is a way to do it without using the API client inside the Context object.
I ended up using probot-scheduler
const createScheduler = require('probot-scheduler')
module.exports = app => {
createScheduler(app, {
delay: false
})
robot.on('schedule.repository', context => {
// this is called on startup and can access context
})
}
I tried probot-scheduler but it didn't exist - perhaps removed in an update?
In any case, I managed to do it after lots of digging by using the actual app object - it's .auth() method returns a promise containing the GitHubAPI interface:
https://probot.github.io/api/latest/classes/application.html#auth
module.exports = app => {
router.get('/hello-world', async (req, res) => {
const github = await app.auth();
const result = await github.repos.listForOrg({'org':'org name});
console.log(result);
})
}
.auth() takes the ID of the installation if you wish to access private data. If called empty, the client will can only retrieve public data.
You can get the installation ID by calling .auth() without paramaters, and then listInstallations():
const github = await app.auth();
const result = github.apps.listInstallations();
console.log(result);
You get an array including IDs that you can in .auth().

Getting correct ID without sharing URL

I have an Angular 4 application where I am trying to fetch a single row (using ID) from a MySQL database. I am using NodeJS with ExpressJS. However, I am struggling finding a way to get the ID from the URL without sharing the exact URL-path, as that would lead to the website only rendering the JSON-object, and not the components.
server.js
app.get('api/books/:id', (req, res) => {
console.log(req.params.id);
});
If the URL is localhost:3000/books/3, the console will log :id. localhost:3000/api/books/3 will however log the correct ID to the console. The issue is that using the latter as my URL in my Angular routing will result in a shared path, which will not work.
Here's an example of how I use Angular's HttpModule to send a GET-request to the server:
this.http.get('api/books/:id')
.map(res => res.json())
.subscribe(data => {
this.bookDetail = data;
});
Here is my path from the routing using Angular's RouterModule:
{ path: 'books/:id', component: BookDetailComponent }
How would I go about solving this issue?
You need to create a function that on the init of that component, the angular app triggers the HTTP request to the server. for example, I have a blog application.
{ path: 'blogs/:id', component: BlogComponent },
ngOnInit() {
this.route.params.subscribe(params => this.blog = params.id);
this.getBlog(this.blog);}
getBlog(blog) {
this.blogService.getBlog(blog).subscribe(
data => { this.foundBlog = data;
if (data.comments) {
this.comments = data.comments;
}
getBlog(blog): Observable<any> {
return this.http.get(`http://localhost:3000/api/blogs/${blog}`).map(res => res.json());
}
the first is my route, the second is the init function on my blog component
the third is the get blog function on the blog component
the last is the get blog function on my blogservice, that send the HTTP request
hopefully that helps.

How can I have multiple API endpoints for one Google Cloud Function?

I have a Google Cloud Function which contains multiple modules to be invoked on different paths.
I am using the serverless framework to deploy my functions, but it has the limitation of only one path per function.
I want to use multiple paths in one function just like we can in the AWS serverless framework.
Suppose a user cloud function will have two paths /user/add as well as /user/remove; both the paths should invoke the same function.
Something like this:
serverless.yml
functions:
user:
handler: handle
events:
- http: user/add
- http: user/remove
How can I have multiple API endpoints for one GCF?
Yes, indeed there is no actual REST service backing up Google Cloud Functions. It uses out of the box HTTP triggers.
To hustle the way around, I'm using my request payload to determine which action to perform. In the body, I'm adding a key named "path".
For example, consider the Function USER.
To add a user:
{
"path":"add",
"body":{
"first":"Jhon",
"last":"Doe"
}
}
To remove a user:
{
"path":"remove",
"body":{
"first":"Jhon",
"last":"Doe"
}
}
If your operations are purely CRUD, you can use request.method which offers verbs like GET, POST, PUT, DELETE to determine operations.
You could use Firebase Hosting to rewriting URLs.
In your firebase.json file:
"hosting": {
"rewrites": [
{
"source": "/api/v1/your/path/here",
"function": "your_path_here"
}
]
}
Keep in mind this is a workaround and it has a major drawback: you will pay for double hit. Consider this if your app has to scale.
You can write your functions in different runtimes. The Node.js runtime uses the Express framework. So you can use its router to build different routes within a single function.
Add the dependency
npm install express#4.17.1
The following example is using typescript. Follow these guidelines to initiate a typescript project.
// index.ts
import { HttpFunction } from '#google-cloud/functions-framework';
import * as express from 'express';
import foo from './foo';
const app = express();
const router = express.Router();
app.use('/foo', foo)
const index: HttpFunction = (req, res) => {
res.send('Hello from the index route...');
};
router.get('', index)
app.use('/*', router)
export const api = app
// foo.ts
import { HttpFunction } from '#google-cloud/functions-framework';
import * as express from 'express';
const router = express.Router();
const foo: HttpFunction = (req, res) => {
res.send('Hello from the foo route...');
};
router.get('', foo)
export default router;
to deploy run:
gcloud functions deploy YOUR_NAME \
--runtime nodejs16 \
--trigger-http \
--entry-point api \
--allow-unauthenticated
Currently, in google allows only one event definition per function is supported. For more
Express can be installed with npm i express, then imported and used more or less as normal to handle routing:
const express = require("express");
const app = express();
// enable CORS if desired
app.use((req, res, next) => {
res.set("Access-Control-Allow-Origin", "*");
next();
});
app.get("/", (req, res) => {
res.send("hello world");
});
exports.example = app; // `example` is whatever your GCF entrypoint is
If Express isn't an option for some reason or the use case is very simple, a custom router may suffice.
If parameters or wildcards are involved, consider using route-parser. A deleted answer suggested this app as an example.
The Express request object has a few useful parameters you can take advantage of:
req.method which gives the HTTP verb
req.path which gives the path without the query string
req.query object of the parsed key-value query string
req.body the parsed JSON body
Here's a simple proof-of-concept to illustrate:
const routes = {
GET: {
"/": (req, res) => {
const name = (req.query.name || "world");
res.send(`<!DOCTYPE html>
<html lang="en"><body><h1>
hello ${name.replace(/[\W\s]/g, "")}
</h1></body></html>
`);
},
},
POST: {
"/user/add": (req, res) => { // TODO stub
res.json({
message: "user added",
user: req.body.user
});
},
"/user/remove": (req, res) => { // TODO stub
res.json({message: "user removed"});
},
},
};
exports.example = (req, res) => {
if (routes[req.method] && routes[req.method][req.path]) {
return routes[req.method][req.path](req, res);
}
res.status(404).send({
error: `${req.method}: '${req.path}' not found`
});
};
Usage:
$ curl https://us-east1-foo-1234.cloudfunctions.net/example?name=bob
<!DOCTYPE html>
<html lang="en"><body><h1>
hello bob
</h1></body></html>
$ curl -X POST -H "Content-Type: application/json" --data '{"user": "bob"}' \
> https://us-east1-foo-1234.cloudfunctions.net/example/user/add
{"message":"user added","user":"bob"}
If you run into trouble with CORS and/or preflight issues, see Google Cloud Functions enable CORS?

How to add proxy to Node / Express site?

My site is running on Node and using the Express framework.
My goal is to gather data from the Yahoo Placefinder api. It does not support JSONP, so I need to send my JQuery.getJSON request to my own proxy. My proxy would then send an http request to the Placefinder api, and echo the response.
If I were using php instead of Node, I would just make a new php file that includes a curl request to the placefinder api and echo the response.
But, I am using Node and I'm not sure where to start.
And, I'm using the Express framework.
My Questions are:
Where would the proxy fit within the Express framework? The public folder?
Where can I find some info on how to code a proxy in Node?
Will I need to modify the configuration of my Rackspace cloud (ubuntu) server in order for this to be possible?
See node-http-proxy. It should be better than implementing your own proxy.
Express lets you add middlewares as arguments when you do express.createServer(). Or, you can add them afterwards by using .use(proxy).
I don't think so.
To give an example (untested code):
var httpProxy = require('http-proxy'), express = require('express');
var yahooProxy = httpProxy.createServer(80, 'yahoo.com');
var app = express.createServer();
app.configure(function () {
app.use('/yahoo', yahooProxy);
});
...
Here's another example with 1.0.X that demonstrates header injection.
var express = require( 'express' );
var proxy = require( 'http-proxy' ).createProxyServer;
var app = express();
app.configure(function() {
// Inject some request headers here before we proxy...
app.use( function( req, res, next ) {
req.headers[ 'x-my-header' ] = 'blah blah';
next();
});
// Proxy based on path...
app.use( '/stack', proxy({ target: 'http://stackoverflow.com'} ).web );
app.use( '/yahoo', proxy({ target: 'http://yahoo.com'} ).web );
app.use( function( req, res ) {
res.send({ ok: false, message: 'Not much here.' })
});
}).listen( 3000 );
You can just add another route to your express app, perhaps at /api/yahoo/....
This view function will then make a call to the Yahoo API, probably using: http://nodejs.org/docs/v0.4.9/api/http.html#http.request, and then when that request finishes you simple return the result as JSON.
However, keep in mind that your proxy is public and that anyone can make requests through it. I would suggest some basic authorization. A generated value which you provide to the page making the request should work.
Using http-proxy 1.0 with express:
var httpProxy = require('http-proxy');
var apiProxy = httProxy.createProxyServer();
app.get("/api/*", function(req, res){
apiProxy.web(req, res, { target: 'http://google.com:80' });
});
Nowadays this seems to be the easiest solution to add a proxy to Express:
https://www.npmjs.org/package/proxy-middleware