Netflify lambda function working locally but not in production - javascript

I'm trying to use netlify and its lambda function feature to run a node function . Based on https://css-tricks.com/using-netlify-forms-and-netlify-functions-to-build-an-email-sign-up-widget/ , I have in my functions/submission-created.js:
const https = require("https");
exports.handler = async event => {
const email = JSON.parse(event.body).payload.data.EMAIL
const asking = JSON.parse(event.body).payload.data.ASKING
var formData = {
'email': email,
'first_name': '',
'last_name': asking,
'lists[]': 'NUM'
};
var encoded = Object.entries(formData).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&");
var endpoint = 'https://api.sendfox.com/contacts/?' + encoded;
const data = JSON.stringify(formData);
const options = {
method: 'POST',
connection: 'keep-alive',
headers: {
'Authorization': 'Bearer hhhhh',
'Content-Type': 'application/json',
},
'content-length': data.length,
};
console.log(email);
const req = https.request(endpoint, options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (d) => {
console.log(d);
});
});
req.on('error', (e) => {
console.error(e);
});
req.write(data);
req.end();
return {
statusCode: 200,
body: data
};
}
This works as expected when I run it locally with netlify dev, but when pushed to the github repo used by netlify to build the site, it does not work in production. How can I fix this?
The package structure looks like the screenshot:
EDIT:
the netlify.toml :
[build]
functions = "./functions
No errors. The output on sites function tab is:
8:57:43 PM: 2020-12-08T01:57:43.384Z undefined INFO to here
8:57:43 PM: 2020-12-08T01:57:43.390Z 8ca26edc-1f20-4c20-b038-
79ecdf206d92 INFO yt#ghj.org
8:57:43 PM: 2020-12-08T01:57:43.390Z 8ca26edc-1f20-4c20-b038-
79ecdf206d92 INFO 999
8:57:43 PM: 2020-12-08T01:57:43.390Z 8ca26edc-1f20-4c20-b038-
79ecdf206d92 INFO yt#ghj.org
8:57:43 PM: Duration: 39.71 ms Memory Usage: 69 MB Init Duration:
176.22 ms

As noted, the information you give are insufficient regarding what has gone wrong. However, I will try to answer based on what I have.
In the tutorial, I noticed the usage of dotenv package.
The package is used in order to setup different configuration in different environments.
It utilizes different production files related to the environments, allowing you for example to setup a .env file for local development, and a different one (e.g.,.env.production) for your production.
Based on the setup, variables setup in the respective .env file utilized on each environment, are loaded in the process.env object.
Now, on your tutorial, I noticed that you have the loading of crucial variables being loaded from .env such as EMAIL_TOKEN. I suspect that your setup expects a separate dotenv file for production - and by not finding it, it loads the parameters required as empty, silently. Please revise what environment it loads and what your configuration is at your environments, respectively.
Also, consider the following tutorial for working with dotenv vars.

This could be because of incorrect settings on the API Gateway. Check what all traffic is allowed. Sometimes you may have just allowed TCP traffic. Change it to all traffic.
I could also be that you have a malformed lambda response. Check this AWS documentation
Resolve malformed 502 Api gateway

Related

axios request to docker daemon

Description:
In graphql gateway i would like to know the services available in docker so that i can stitch the schema from other graphql services. All the applications are running in a docker. docker compose file is used to start all the applications.
Docker engine does provide a REST api to list all the services.
Inside docker compose we should also mount volume
volume
- /var/run/docker.sock:/var/run/docker.sock
Problem:
I used npm library http and i was able to get the result
const result = http.request(
{
socketPath: "/var/run/docker.sock",
path: "/containers/json",
},
(response) => {
res.setEncoding("utf8");
res.on("data", (data) => console.log(data));
res.on("error", (data) => console.error(data));
}
);
result.end();
I am not able to get all the docker services using axios. I also find that even-though axios has socketPath attribute it do not have a path attribute along with it.
I used the following code will using axios:
const axiosResult = await axios({
socketPath: "/var/run/docker.sock",
url: "/containers/json",
method: "GET",
});
I tried most using a different url: http://unix:/var/run/docker.sock/v1.30/containers/json
When using Axios the code has to modified as such to get the result
const { data } = await axios.get("http://unix:/containers/json", {
socketPath: "/var/run/docker.sock",
});
console.log(data);

documentPath is not a valid resource path when deployed to Google App Engine with javascript

Description:
I have a frontend React client that is hosted on Firebase Hosting and a NodeJS Express API that is hosted on Google App Engine. The client needs to send a POST request to a NodeJS Express route, the request need to contain a variable called formid that holds the name of a firebase document. When both the server and client is run locally the formid variable gets sent to the API and it is not empty or undefined. But when the API is deployed and the request is sent to GAE instead I get this error:
UnhandledPromiseRejectionWarning: Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.
The error appears in the Google Cloud Platform Console. In left hand menu I go to; Operations > Logging > Logs Viewer. But I can also tail the logs to my local console with the command "gcloud app logs tail -s default".
Question: Why does the error appear only when the request is sent to GAE and not when I run them locally?
request.headers.form_id contains the name of the document stored in a collection (which is an autoID) in Google Firestore.
async function postFormQuestionHandler(request, response) {
let form_ref = db.collection("forms").doc(request.headers.form_id);
... other code
Express router that recieves the request, forwards it to postFormQuestionHandler function.
router.post("/question", (req, res) => {
postFormQuestionHandler(req, res);
});
Here is where the request firstly is being sent:
async addQuestionsToFormDb(idToken, fomrid, questionids) {
let result = await questionids.map(async (questionid) => {
let data = {
idToken: idToken,
form_id: formid,
question_id: questionid,
};
return await fetch(`${process.env.REACT_APP_API}/form/question`, {
method: 'POST',
mode: 'cors',
headers: data
});
}
From above code I have also tried using the Axios library but it also produces the same error on when the API is deployed to GAE. I have tried reading the documentation of both Axios (Github Axios Documentation) and Fetch (Firefox MDN web docs) but it have not helped me, am I missunderstanding something? Below is what I tried with Axios:
return await axios.post(`${process.env.REACT_APP_API}/form/question`, {}, {
headers: data,
}
);
Other information
Im using Express v4.17.1 and Node v10.19.0, I am also developing this with WSL 2 on Windows 10 2004.
your request.headers.form_id is either empty string or contain invalid character. I guess it contains slash /. Here is more info https://firebase.google.com/docs/firestore/quotas#collections_documents_and_fields

Read/Write and store data internelly in a Local App (no server) with JavaScript

So I am making a local App using Javascript , React and Electron and I want it to be able to work just fine without internet.
I can't use 'localStorage' because the data might get deleted if the user deletes the cache.
I tried reading/writing using differant Modules, none of them worked mostly because of CROS. Using XMLHTTPrequests and Ajax doesn't work either and am running out of time.
When I use them on the test server, they return the index.html for the mainpage (They can at least access that ... and still they can't read the data) but when I try it on the build I get CORS the error.
My Idea for now is to enable CORS on my webpage since I have no worries about security : The App will run ONLY offline so there is no danger.
But After many hours...I didn't find a solution to do it on the client side.
If anyone has an idea or suggestion I would be grateful.
I tried : fs,FileReader,FileSaver, $.ajax,XMLHTTPrequests
//using $ajax
var test = $.ajax({
crossDomain:true,
type: 'GET',
url:'../data/DefaultCategorie.txt',
contentType: 'text/plain',
success: function(data){
console.log(data);
},
error: function(){
alert('failed');
},
})
//using fs
fs.readFile('../data/DefaultCategorie.txt', 'utf8', (err, data) => {
if (err) {
console.log("Failed");
throw err
}
console.log(data);
fs.close(data, (err) => {
if (err) throw err;
});
});
This article covers the 3 most common ways to store user data: How to store user data in Electron
The Electron API for appDatadoes what you want. It is very easy to use.
From the above article:
const userDataPath = (electron.app || electron.remote.app).getPath('userData');
this.path = path.join(userDataPath, opts.configName + '.json')
this.data = parseDataFile(this.path, opts.defaults);
function parseDataFile(filePath, defaults) {
try {
return JSON.parse(fs.readFileSync(filePath));
} catch(error) {
// if there was some kind of error, return the passed in defaults instead.
return defaults;
}
}
Docs
app.getPath(name)
name String
Returns String - A path to a special directory or file associated with
name. On failure, an Error is thrown.
You can request the following paths by the name:
appData - Per-user application data directory, which by default points to:
%APPDATA% on Windows
$XDG_CONFIG_HOME or ~/.config on Linux
~/Library/Application Support on macOS
userData - The directory for storing your app's configuration files,
which by default it is the appData directory appended with your app's
name.

React Native - Unable to Upload Image Via Axios Post (Android)

I'm unable to upload an image from my React Native application in Android (iOS works fine). On attempting to upload, I'm receiving the following error:
Error: Network Error
at createError (buildURL.js:33)
at XMLHttpRequest.handleError (xhr.js:144)
at XMLHttpRequest.dispatchEvent (event-target.js:172)
at XMLHttpRequest.setReadyState (XMLHttpRequest.js:576)
at XMLHttpRequest.__didCompleteResponse (XMLHttpRequest.js:392)
at XMLHttpRequest.js:505
at RCTDeviceEventEmitter.emit (EventEmitter.js:190)
at MessageQueue.__callFunction (MessageQueue.js:344)
at MessageQueue.js:107
at MessageQueue.__guard (MessageQueue.js:291)
All other requests work, connection is configured to my local static IP address, as I'm testing on a physical device, rather than in a simulator.
I've looked at a number of solutions already:
https://github.com/facebook/react-native/issues/9506
Suggests to add a type filed to data, which I had already (detailed below)
https://github.com/facebook/react-native/issues/10404
Suggests to use IP instead of localhost, which I have been doing since the start
Here is the code that handles this:
ProfileImage.js (wrapper for react-native-image-picker):
async onHandleResizedImageUri(image) {
var data = new FormData();
data.append("profile_image", {
uri: image.path,
name: image.name,
type: "image/jpeg"
});
let imageUploadSuccess = await global.api.callPostImage("/api/profile-image", data);
Api.js
async callPostImage(url, data) {
try {
const settings = {
baseURL: config.api_host,
timeout: 1000,
headers: {
"content-type": "multipart/form-data"
}
};
const response = await this.axios.post(url, data, settings);
return response;
} catch (error) {
console.log(error);
}
}
Also, this issue is happening in both debug and release mode, and for multiple servers (local, staging and production). All other network requests work fine, but this one will not complete. Anyone have any suggestions?
Device information:
Samsung Galaxy A5 (2017)
Model SMA520W
Version 8.0.0

Relative URL as hostname in Nock

I need to mock client side HTTP requests. I'm using isomorphic-fetch in the client side and I'm using mocha and nock for testing and mocking. All my client requests are based on relative path. Due to this I'm unable to provide host name for the nock. Is there a work around.
Client side:
fetch('/foo') //hostname: http://localhost:8080
.then(res => res.json())
.then(data => console.log(data))
.catch(e => console.log(e))
Test suite
nock('/')
.get('/foo')
.reply(200, {data: "hello"})
This is failing as I'm not giving the proper hostname for the nock. Am I doing something wrong?
For anyone interested: In my react/webpack project I solved this by prepending the fetch url with 'http://localhost' when NODE_ENV is set to 'test'.
example:
const testing = process.env.NODE_ENV === 'test';
const apiUrl = `${testing ? 'http://localhost' : ''}/api`;
function getStuffFromApi() {
return fetch(apiUrl, ...)
}
This way, in my test I can always use nock like so:
nock('http://localhost')
.get('/api')
.reply(200, {data: 'hello'})
NOTE: When running my tests, NODE_ENV gets set to 'test'
Found a workaround for this. Have a _ajax-setup.js in your test folder
import $ from 'jquery'
$(document).ajaxSend((event, jqxhr, settings) => {
settings.url = 'http://0.0.0.0' + settings.url;
})
The thing to note is that this file has to run First and Only Once. Having it as a file runs only once and _ before it makes it alphabetically first.
Later you can test your code with
nock('http://0.0.0.0')
.get('/foo')
.reply(200, {data: "hello"})
I just asked a similar question on Nock's repository. Apparently this is not supported: https://github.com/pgte/nock/issues/431
For axios I added following to my test file. This helped overcome this limitation.
axios.defaults.baseURL='http://localhost:4000/';
Please note that this is a global variable.
With this the actual code can live with relative URL and there is no need to check testing flag in it.
kudresov's reply to liorbauer's issue describes a Jest-specific workaround.
Put this into __mocks__/isomorphic-fetch.js:
const fetch = require.requireActual('isomorphic-fetch');
module.exports = (url, config) => {
return fetch('https://localhost' + url, config);
};
Jest then automatically replaces all requires (or imports) for this node module.
In other test frameworks you could use something like rewire

Categories

Resources