What is the best way to make calls to my own API on a live node server? - node.js

I have made a web application with a simple API. The code for the front-end and and the API are both served from the same host. The front end consumes the API by making basic http requests. While developing, I have been making these requests within the front-end using port 3000 from the locally run server.
What is the best way to do this on a production server (An AWS EC2 instance)?
How do I easily generalize this in the development code so I don't have to change it from
axios.get("localhost:3000" + otherParams)
.then(response => {
//use the response to do things
});
})
to
axios.get("http://99.999.999.999:80" + otherParams)
.then(response => {
//use the response to do things
});
})
every time I push an update to the live server? Is this just something that web developers have to put up with? Sorry if this is a dumb question..

We definitely don't have to put up with changing our code like that every time! (Thank the coding gods)
So I think what you are after is environment variables
For example: You could setup an environment variable called SERVER_URL
Then when you are running locally that variable is localhost:3000 but when you deploy to amazon it can be set to http://99.999.999.999:80
in node you consume the variable like this
process.env.WHATEVER_YOUR_VARIABLE_NAME_IS
So in your case it would be
axios.get(process.env.SERVER_URL + otherParams)
a popular module to help create these variables is dotenv, which is worth looking at.
As a little bonus answer to help (and hopefully not confuse you too much), axios lets you create your own instance of axios so that you don't have to repeat yourself. Their example is
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
So you could do something like
const api = axios.create({
baseURL: process.env.SERVER_URL
});
then you can replace your axios calls with your new instance of axios (api)
Something like this.
api.get(otherParams)
Hope that makes some sense and gets you back on track!

You can create a config.js file:
var configs = {};
configs.appPort = 3000;
configs.host = '192.168.99.100';
module.exports = configs;
Importing the configure file:
var configs = require('./config');
Axios:
axios.get(configs.host + ":" + configs.appPort + "/" + otherParams)
.then(response => {
//use the response to do things
});
})
You can also create environment variables like this:
configs.isProduction = false;
configs.localHost = "localhost";
configs.productionHost = "192.168.99.100";
And then you can check in your app if it is production, use productionHost, otherwise, use localHost.

Related

Can Open Telemetry Instrument Two Express Services in the Same Node Program?

Let's say I have a NodeJS program that has two separate instances of an express server running.
const express = require('express')
const app1 = express()
app1.listen(3000, () => { //... })
//...
const app2 = express()
app2.listen(3001, () => { //... })
I've been able to instrument a program like this via open telemetry, and have my spans sent/exported successfully to Zipkin. All I needed to do is/was add code like the following to the start of my program.
const { NodeTracerProvider } = require('#opentelemetry/node');
const { ZipkinExporter } = require('#opentelemetry/exporter-zipkin');
const provider = new NodeTracerProvider({
plugins: {
express: {
enabled: true,
},
http: {
requestHook: (span, request) => {
span.setAttribute("custom request hook attribute", "request");
},
},
}
});
const options = {
url: 'http://localhost:9411/api/v2/spans',
serviceName: 'service-main'
}
const zipkinExporter = new ZipkinExporter(options);
provider.addSpanProcessor(new SimpleSpanProcessor(zipkinExporter))
provider.register();
and make sure that the express and http plugins were/are installed
npm install #opentelemetry/plugin-http #opentelemetry/plugin-express
This all works great -- except for one thing. Open Telemetry sees both my express services running as the same service-main service.
When I instrumented these services directly with Zipkin -- I would add the Zipkin middleware to each running express server
app1.use(zipkinMiddleware({tracer: tracer1}));
app2.use(zipkinMiddleware({tracer: tracer2}));
Each tracer could be instantiated with its own service name, which allowed each service to have its individual name and show up as a different service in Zipkin.
(/main, /hello, and /goobye are all service via a different express service in the above URL)
Is this sort of thing (instrumenting two services in one program) possible with Open Telemetry? Or would I need to separate these two services out into separate programs in order to have each services have an individual name? This question is less about solving a particular problem, and more about understanding the semantics of Open Telemetry.
It is possible to create two separate tracer providers. Only one of them will be the global tracer provider, which the API will use if you call API methods. You can't use the plugins in this configuration, which means you will have to manually instrument your application. If this is a use-case which is important to you, I suggest you create an issue on the github repo.
yes, you can have multiple express running in the same node process (thats how clustering works in node as well)
but you will need to have them running on different ports.;
# const express = require('express')
const app1 = express()
app1.listen(3001, () => { //... })
//...
const app2 = express()
app2.listen(3002, () => { //... })

Get my Action’s server URL in (JavaScript) fulfilment code

I am using actionssdk and I build my Action fulfilments using Javascript and node.js + Express.
I am looking for a way to get the url (protocol + host name + port) of the server where the fulfilment is hosted.
Is there a simple way to do this? E.g. in the MAIN intent? Is there some conv-property I can use? Can I get hold of a req-parameter in the MAIN-intent, from which I can deduct hostname etc?
const express = require('express');
const expressApp = express();
const { actionssdk, ... } = require('actions-on-google');
const app = actionssdk({
ordersv3: true,
clientId: ...
});
expressApp.post('/fulfilment', app);
app.intent('actions.intent.MAIN', (conv) => {
let myUrl: string = ... // ???????
...
});
(background: obviously I know myself to where I deployed my fulfilment code. But I have a reusable template for fulfilment code in which I want to refer to the host url, and I do not want to type that in manually each time I develop a new Action).
You can get access to the request object in a middleware via Framework Metadata which is by default of type BuiltinFrameworkMetadata which contains objects used by Express
For example, you can use it like this, which will be ran before each request:
app.middleware((conv, framework) => {
console.log(framework.express.request.headers.host)
})

Creating an API to wrap an... API?

This isn’t a specific issue question, but I’m trying to wrap my head around the concept of REST APIs and calling an API within your own API.
For example, if I develop an App called “BeesBees”, where users can buy bees, and I have a database of logins and passwords and obviously the bees, and how much each cost, I understand that I can used my own apps BeesBees API to get the list of bees (and if I make it open for other people, they can also use my GET /bees point to get, well, the bees)
But if I want to allow customers to buy the bees, and I don’t want to build a whole platform for doing so, so I integrate Stripe - could I have a POST /:users/charges/:priceOfBee API call that, in turn, called the Stripe API function somewhere somehow? For example, pointing to the URL of a Node.js project that will make the charge using Stripe’s Node.js SDK.
Or, in a case like this, would it be better to just implement the Stripe SDK for my device’s platform and make the charge using the device?
I have no code base so there’s nothing to pick apart, but I couldn’t think of anywhere else to ask, sorry y’all
You can certainly wrap APIs with other APIs, it's really just a form of composition, delegate to other services where it makes sense to do so.
Stripe integration might well be a good example of where it could make sense to follow this pattern. You certainly don't want to roll your own payment service.
Here's a trivial example of a local Express server making an API request:
const express = require("express");
const port = 3000;
const app = express();
const request = require('request');
app.get("/api/example", (req, res) => {
// Make external REST request here...
let options = {
url: 'https://httpbin.org/get',
qs: { parameter1: 42 },
json: true
}
request(options, (err, response, body) => {
if (err) {
res.status(500).send(err.message);
} else {
res.status(200).send(body);
}
});
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('running at http://' + host + ':' + port)
});
console.log(`Serving at http://localhost:${port}`);

Frequent requests with React and Express GraphQL

I'm creating a website using React and Express GraphQL, with a MariaDB database. I've come across a problem with making frequent requests/subscriptions to the GraphQL API, however.
After the page in question loads in React, I call this:
componentDidMount() {
this.setState({
waitingTimer: setInterval(this.queryWaiting.bind(this), 1000)
});
}
where queryWaiting is a function that carries out a fetch request to my GraphQL server at localhost:3000/graphql. That URL itself is a proxy defined in my setupProxy.js file which proxies the URL from localhost:4000/graphql, so that I don't need to use CORS.
It's worth noting that I also clearInterval this waitingTimer in componentWillUnmount.
In my GraphQL server file, which I'm simply running with node, I set up my server like this:
var app = express();
app.use("/graphql", graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
app.listen(4000);
Where schema is a valid schema, and root is my root resolver.
The API query that I'm repeatably calling is called getWaitingCount, and it acts like this:
getWaitingCount: () => {
return new Promise((resolve, reject) => {
var currentTime = Date.now() / 1000;
if (cachedWaitingTime + cachedWaitingInterval > currentTime) {
return cachedWaiting;
}
connection.query("SELECT COUNT(*) FROM profiles WHERE isWaiting=1;", function (error, results, fields) {
if (error)
reject(error);
else {
// Update cache values
cachedWaiting = results[0]["COUNT(*)"];
cachedWaitingTime = Date.now() / 1000;
resolve(cachedWaiting);
}
});
});
}
I've implemented some caching to reduce server load. The caching variables are defined elsewhere.
The problem I experience is that, after between 2-10 seconds, the POST requests for this specific query from my React app stop getting resolved, and I have to reload the page for them to start getting accepted again. Weirdly, other requests go through fine.
I've tried various solutions, such as switching to using the proxy method I'm using currently, and I've also considered the possibility of a built-in anti-DDOS mechanism in the Express code, but I can't find any evidence for that.
Any help with this issue is very much appreciated.
Turns out the best solution is to type out and explain your code :)
This code:
if (cachedWaitingTime + cachedWaitingInterval > currentTime) {
return cachedWaiting;
}
is inside a promise, so really, it should do:
resolve(cachedWaiting);
instead of returning it.
That is all. I am currently kicking myself.

Where do I put database connection information in a Node.js app?

Node.js is my first backend language and I am at the point where I am asking myself "where do I put the database connection information?".
There is a lot of good information regarding this issue. Unfortunately for me all the examples are in PHP. I get the ideas but I am not confident enough to replicate it in Node.js.
In PHP you would put the information in a config file outside the web root, and include it when you need database data.
How would you do this in Node.js? using the Express.js framework.
So far I have this:
var express = require('express'), app = express();
var mysql = require('mysql');
app.get('/', function(req,res) {
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'store'
});
var query = connection.query('SELECT * from customers where email = "deelo42#gmail.com"');
query.on('error', function(err) {
throw err;
});
query.on('fields', function(fields) {
console.log('this is fields');
});
query.on('result', function(row) {
var first = row.first_name;
var last = row.last_name;
res.render('index.jade', {
title: "My first name is " + first,
category: "My last name is " + last
});
});
});
app.listen(80, function() {
console.log('we are logged in');
});
As you can see I have a basic express application with 1 GET route. This route sets off the function to go to the database and pull out information based on an email address.
At the top of the GET route is the database connection information. Where do I put that? How do I call it? How do I keep it out of web root, and include it like PHP ? Can you please show me in a working example. Thanks!
I use the Express Middleware concept for same and that gives me nice flexibility to manage files.
I am writing a detailed answer, which includes how i am use the config params in app.js to connect to DB.
So my app structure looks something this:
How i connect to DB? (I am using MongoDB, mongoose is ORM, npm install mongoose)
var config = require('./config/config');
var mongoose = require("mongoose");
var connect = function(){
var options = {
server: {
socketOptions:{
keepAlive : 1
}
}
};
mongoose.connect(config.db,options);
};
connect();
under the config folder i also have 'env' folder, which stores the environment related configurations in separate files such as development.js, test.js, production.js
Now as the name suggests, development.js stores the configuration params related to my development environment and same applies to the case of test and production. Now if you wish you can have some more configuration setting such as 'staging' etc.
project-name/config/config.js
var path = require("path");
var extend = require("util")._extend;
var development = require("./env/development");
var test = require("./env/test");
var production = require("./env/production");
var defaults = {
root: path.normalize(__dirname + '/..')
};
module.exports = {
development: extend(development,defaults),
test: extend(test,defaults),
production: extend(production,defaults)
}[process.env.NODE_ENV || "development"]
project-name/config/env/test.js
module.exports = {
db: 'mongodb://localhost/mongoExpress_test'
};
Now you can make it even more descriptive by breaking the URL's into, username, password, port, database, hostname.
For For more details have a look at my repo, where you can find this implementation, in fact now in all of my projects i use the same configuration.
If you are more interested then have a look at Mean.js and Mean.io, they have some better ways to manage all such things. If you are beginner i would recommend to keep it simple and get things going, once you are comfortable, you can perform magic on your own. Cheers
I recommend the 12-factor app style http://12factor.net which keeps all of this in env vars. You never should have this kind of information hard-coded or in the app source-code / repo, so you can reuse it in different environments or even share it publicly without breaking security.
However, since there are lots of environment vars, I tend to keep them together in a single env.js like the previous responder wrote - although it is not in the source code repo - and then source it with https://www.npmjs.org/package/dotenv
An alternative is to do it manually and keep it in, e.g. ./env/dev.json and just require() the file.
Any of these works, the important point is to keep all configuration information separate from code.
I agree with the commenter, put it in a config file. There is no ultimate way, but nconf is also one of my favourites.
The important best practise is that you keep the config separate if you have a semi-public project, so your config file will not overwrite other developers.
config-sample.json (has to be renamed and is tracked with for example git)
config.json (not tracked / ignored by git)

Resources