Use google-spreadsheets with nodejs with service account? - node.js

How can use a service account with nodejs in order to access at a sheet on google with google api?
I tried with the nodejs (npm) module google-spredsheet but when the loadInfo() it returns always Request failed error 404
edit1:
ii already have a service account and the key file downloaded and in my directory.
Here's the actual script:
const express = require("express"),
{GoogleSpreadsheet} = require('google-spreadsheet'),
creds = require('./client_secret.json'),
app = express();
app.set("view engine", "ejs");
app.use(express.static(__dirname+"/public"));
app.get("/google-spreadsheet", async function(req, res){
// Identifying which document we'll be accessing/reading from
var doc;
doc = new GoogleSpreadsheet('1XKcnyJkTyq15AlvhAs3V_2wnP8vgwY3mWXAijyiINVs/edit#gid=0');
// Authentication
await doc.useServiceAccountAuth(creds);
await doc.loadInfo(); // loads document properties and worksheets
console.log("test: "+doc.title);
});
app.listen(8080, () => {
console.log('[EXPRESS] Web Server active on: ' + 8080);
});

I believe your current situation and goal as follows.
Your client_secret.json is for the service account.
You are using "google-spreadsheet" of the latest version.
You want to access to the Google Spreadsheet using "google-spreadsheet" with the service account.
Modification points:
In your script, '1XKcnyJkTyq15AlvhAs3V_2wnP8vgwY3mWXAijyiINVs/edit#gid=0 is used as the Spreadsheet ID. In this case, such error occurs. I think that this might be the reason of your issue. So please modify it to '1XKcnyJkTyq15AlvhAs3V_2wnP8vgwY3mWXAijyiINVs'.
Modified script:
When your script is modified, it becomes as follows.
From:
doc = new GoogleSpreadsheet('1XKcnyJkTyq15AlvhAs3V_2wnP8vgwY3mWXAijyiINVs/edit#gid=0');
To:
doc = new GoogleSpreadsheet('1XKcnyJkTyq15AlvhAs3V_2wnP8vgwY3mWXAijyiINVs');
Note:
When the Google Spreadsheet of 1XKcnyJkTyq15AlvhAs3V_2wnP8vgwY3mWXAijyiINVs is not shared with the email of the service account, the service account cannot use the Spreadsheet. Please be careful this.
Reference:
google-spreadsheet

Related

Using Node to access FTP in another server

I need to access FTP in another server (Ubuntu).
My Node.js API receive an image from user, and then needs to upload it to another server using FTP connection. However, if user folder doesn't exist, I need to create folder before sending the image.
How can i do this?
I'm using express-upload to get files:
const express = require('express');
const upload = require('express-fileupload');
const app = express();
app.use(upload());
app.use('/upload', async (req, res, next) => {
console.log(req.files.image);
})
You can use Basic FTP, an FTP client module, and use its ensureDir() method to implement the requirement "if user folder doesn't exists, I need to create folder before sending image".
According to its document:
...we make sure a remote path exists, creating all directories as necessary.
await client.ensureDir("my/remote/directory")
Then, you can send the image using its upload() method.

What is the best way to keep the sitemap.xml updated

We have a job portal website built with MEAN Stack with over 100,000 active jobs and 1,000 active company profile pages.
This data is completely dynamic. Every day tens of job postings and companies are registered.
The problem is that we should keep the sitemap.xml file(s) always updated with the latest active links.
Does anybody know the best practice to keep the sitemap.xml always updated in such a dynamic website?
In your express app you can add a sitemap.xml route like so
const xml = require('xml');
... // other routes
app.get('/sitemap.xml', function (req, res) {
// get routes from database or others
response.set('Content-Type', 'text/xml');
response.send(xml(jobs));
})
Your jobs could contain last edited date and the url to your jobs so it could be very accurate.
Or there are packages like express-sitemap-xml you can use that uses a great example to get routes from a database and generates a sitemap.xml
const express = require('express')
const expressSitemapXml = require('express-sitemap-xml')
const app = express()
app.use(expressSitemapXml(getUrls, 'https://bitmidi.com'))
async function getUrls () {
return await getUrlsFromDatabase() // this function would be to get your database jobs into an object
}

Making and changing APIs when online in Nodejs

So were trying to develop an application (or Service) with Node.js that provides each user a custom API that can be called from {theirUserName}.ourwebsite.com. Users will be able to change/edit/remote the endpoints of the API within the application through our editor. They can add params to the endpoints, add auth, etc.
Now my question is, how can we make the API online at first, then how can we change the endpoints online without stopping the API application and running again?
P.S: APIs configuration will be saved into a JSON that will be saved to the DB and once the configuration change an event will be raised that tells us the endpoints have changed.
Using Express, you can add routes after the server is listening, so it's not a problem. Beware of precedence as it will be added at the bottom of the stack.
I would advise to have a db storing routes, and when running the node app (before listening) load all the routes in db and add them to the router. In order to be able to scale your app as well as being able to restart it safely.
Then start listening, and have a route for adding routes, deleting routes, updating routes etc.
Here is a simple example of adding a route after listening :
const app = require('express')();
const bodyParser = require('body-parser');
app.use(bodyParser.json());
const someGenericHandler = function(req, res) {
return res.json({ message: 'foobar' });
};
// it creates a route
app.post('/routes', function(req, res) {
try {
const route = req.body;
app[route.method](route.path, someGenericHandler);
return res.json({ message: `route '${route.method}${route.path}' added` });
} catch(err) {
return res.status(500).json({ message: err.message || 'an error occured while adding the route' });
}
});
app.listen(process.env.PORT);
You can try this code, paste it in a file, let say index.js.
Run npm i express body-parser, then PORT=8080 node index.js, then send a POST request to http:/localhost:8080/routes with a json payload (and the proper content-type header, use postman)
like this: { method: 'get', path:'/' } and then try your brand new route with a GET request # http://localhost:8080/'
Note that if you expect to have hundreds of users and thousands of requests per minute, I would strongly advise to have a single app per user and a main app for user registering and maybe spawn a small VPS per app with some automation scripts when a user register, or have some sort of request limit per user.
Hope this helps

Azure Easy API - can't find documentation for getTable('tableName').insert

I'm using Azure Easy API on my app service. I'm experimenting a little bit and I can't find proper documentation for this stuff.
When I made a new Easy API, the comments at the top said
// Use "request.service" to access features of your mobile service, e.g.:
// var tables = request.service.tables;
So I went from there to finding out I can add to any of my tables using request.service.tables.getTable('tableName').insert({columnName: value})
I expected .insert() to return a promise, but it doesn't. In fact, it doesn't seem to return anything at all. But I'd imagine it's asynchronous.
And since it doesn't return a promise, my next bet was that it takes a callback, but when I tried .insert({columnName: value}, function(r){response.send(r.toString()}), the entire api just failed to work at all.
How am I supposed to use this .insert function?
And where can I find the documentation to learn this information on my own? Googling is getting me nowhere.
Here is a code sample you can use in your Easy API for inserting a record into the table.
module.exports = {
"get": function (req, res, next) {
req.azureMobile.tables('tableName')
.insert({columnName: 'value'})
.then(() => res.status(201).send('Success!'))
.catch(next);
}
}
The app.js file would have the following content.
// ----------------------------------------------------------------------------
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
// This is a base-level Azure Mobile App SDK.
var express = require('express'),
azureMobileApps = require('azure-mobile-apps');
// Set up a standard Express app
var app = express();
// If you are producing a combined Web + Mobile app, then you should handle
// anything like logging, registering middleware, etc. here
// Configuration of the Azure Mobile Apps can be done via an object, the
// environment or an auxiliary file. For more information, see
// http://azure.github.io/azure-mobile-apps-node/global.html#configuration
var mobileApp = azureMobileApps({
// Explicitly enable the Azure Mobile Apps home page
homePage: true,
// Explicitly enable swagger support. UI support is enabled by
// installing the swagger-ui npm module.
swagger: true
});
// Import the files from the tables directory to configure the /tables endpoint
mobileApp.tables.import('./tables');
// Import the files from the api directory to configure the /api endpoint
mobileApp.api.import('./api');
// Initialize the database before listening for incoming requests
// The tables.initialize() method does the initialization asynchronously
// and returns a Promise.
mobileApp.tables.initialize()
.then(function () {
app.use(mobileApp); // Register the Azure Mobile Apps middleware
app.listen(process.env.PORT || 3000); // Listen for requests
});

configure NodeJS process on two different machine

I have two different nodejs web app running on two different machine.
But I need to have one endpoint to user api1.abc.com/v1 to go one process and api2.abc.com/v2 go to another process.
how can i do this kind of request with the single endpoint to user (abc.com). need a nginx setup guide ?
I need this setup because internally I need to call user authenticated api from one server to another.
On one server you need to receive the data (using express & router):
router.get('/v1', function(req, res) {
// TODO
res.render('something');
});
and on the other you need to fetch:
var express = require('express');
var router = express.Router();
var app = express()
app.use('api1.abc.com', router);
router.post('/v1', function(req, res) {
// process res
});
You can write code at version two apis. In request you can pass version on which you need to call.
Call all api's on version 2. If it required to call on second server. Write code on version one to identify the call from version 2. So that it can by pass the basic authentication.
Thanks,

Resources