I'm currently building my own website that is hosted on GitHub Pages.
The app is built with react.js and what is shown here is a contact form.
The problem I'm encountering is that I cannot send a POST request to a google cloud platform with the cloud function service through the form on the GitHub pages.
Am sure the node.js code on GCP is working since i've used Postman to send a request.
With the GCP log, the function is able to parse the POST:
GCP Success with Postman
GCP Failure from website
// react code
submitForm(event) {
const {name, email, subject, message} = this.state;
console.log("sending email...");
console.log(JSON.stringify({name: name, email: email, subject: subject, msg: message}));
fetch('GCP_API_HTTP', {
method: 'POST',
headers: { 'content-type': 'application/json', },
body: JSON.stringify({ name: name, email: email, subject: subject, msg: message })
}).then((response) => {
if (response.status === 200) {
return response.text();
} else {
this.setState({emailError: true});
return response.text();
}
})
}
Here's what's on GCP:
// GCP
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey('API_KEY');
exports.contactMe = (req, res)=> {
let jsonBody;
switch (req.get('Content-Type')) {
// '{"name":"John"}'
case 'application/json':
jsonBody = req.body;
break;
// 'John'
case 'text/plain':
jsonBody = req.body;
break;
// 'name=John' in the body of a POST request (not the URL)
case 'application/x-www-form-urlencoded':
jsonBody = req.body;
break;
}
let msg = {
to: 'example#gmail.com',
from: { email: jsonBody.email, name: jsonBody.name },
subject: jsonBody.subject,
text: jsonBody.msg
};
sgMail.send(msg);
res.send("received!");
res.end();
};
It is quite critical to understand that GitHub Pages publishes any static files that you push to your repository. And it's also keen to note that...
GitHub Pages does not support server-side languages e.g. nodejs, python etc.
Since POST requests require server-side communication, you'll need to get an actual server host. Here's a good read about Static sites by GitHub Pages
Related
I am having trouble adding a contact to ActiveCampaign. I read a post in here: How to add a contact to a list in ActiveCampaign API v3 and am using v1 of the API. I used their contact_sync documentation to the best of my availability.
I'm developing using Gatsby/React --> GitHub --> Netlify, using a lamda function for the POST request.
Here is my axios POST:
{
method: 'post',
url: 'https://ACCOUNT.api-us1.com/admin/api.php?api_key=xxxxxxxxxxxx&api_action=contact_sync&api_output=json',
headers: { 'Content-Type': 'Content-Type: application/x-www-form-urlencoded' },
body: {
email: 'email#email.com',
first_name: 'John'
}
}
And received the following response:
{
result_code: 0,
result_message: 'Could not add contact; missing email address',
result_output: 'json'
}
I'm talking to their endpoint. I just can't figure out how to feed the endpoint the email address?
Does anyone have a working example they would be kind enough to share? Guidance of any kind would be greatly appreciated!
I wanted to make sure to close this and share my answer.
Thanks so much to #reza jafari for his comment in this post where he brought to my attention the code window on the right margin of Postman where you can choose the language/server from a dropdown and it provides the correctly formatted response.
(I don't have enough reputation to upvote #reza's response so wanted to acknowledge it here.)
I was able to get my post working in Postman, and this little trick squared me away. I'll go ahead and post my solution to close this post.
const axios = require("axios")
const qs = require("qs")
exports.handler = async function (event) {
const { email, first_name } = JSON.parse(event.body)
const data = qs.stringify({
email: email,
first_name: first_name,
tags: '"api"',
"p[1]": "1",
})
const config = {
method: "post",
url: "https://ACCOUNT.api-us1.com/admin/api.php?api_key=xxxxxxxxx&api_action=contact_sync&api_output=json",
headers: {
"Api-Token":
"xxxxxxxxx",
"Content-Type": "application/x-www-form-urlencoded",
},
data: data,
}
try {
const response = await axios(config)
return {
statusCode: 200,
body: JSON.stringify(response.data),
}
} catch (err) {
return {
statusCode: 500,
body: JSON.stringify(err),
}
}
}
This is my first question here, although I always come to this great community for guidelines. I am learning how to use GraphQL watched a few videos on how to set it up and work with it as a project.
I am cloning my GitHub repositories with Node.js for server interactions. My query works perfectly in the GraphQL playground, so I moved on to get the same data in my local editor; using Axios, I set up my server like below.
const { default: Axios } = require("axios");
// const fetch = require("node-fetch");
const username = "myGithubUsername"
const token = "myGithubPersonalAccessToken"
const body = {
query:`
query {
user(login: ${username}){
name,
login,
bioHTML,
avatarUrl,
repositories(last: 10){
nodes{
name,
id,
forkCount
}
}
}
}`
}
const baseUrl = "https://api.github.com/graphql/";
const headers ={
"Content-Type": "application/json",
Authorization: `Bearer ${token}`
}
Axios.post(baseUrl,
{body: JSON.stringify(body)},
{headers: headers}).then((response) =>{
console.log('response', response.data)
}).catch((error) => {
console.log('error', error.response)})
Each time I serve it, I get Error: Status 404 Not Found.
I tried in PostMan using my Token, and it works perfectly too. Please let me know what I am doing wrong.
I'm trying to setup a Google-OAuth flow using serverless and AWS-Lambdas. To start, I have a button that kicks off the process by hitting a lambda endpoint. However, the page never actually redirects to the authentication page. Instead I get an error on the FE:
Request failed with status code 302
Frontend logic:
const redirectToGoogleOAuth = async (user) => {
try {
const endpoint = process.env.GOOGLE_PATH_ENDPOINT;
const response = await axios.get(endpoint, {
responseType: 'text',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${user}`,
},
});
// Expect redirect at this point
return response.data.data;
} catch (err) {
throw new Error(err.message);
}
};
Lambda Endpoint:
module.exports = async (event, context) => {
const responseType = 'code'
const googleAuthorizeURL = 'https://accounts.google.com/o/oauth2/v2/auth'
const scope = 'openid email https://www.googleapis.com/auth/contacts.readonly'
const accessType = 'offline'
try {
const params = [
`response_type=${responseType}`,
`client_id=${googleClientId}`,
`redirect_uri=${baseURL}`,
`scope=${scope}`,
`state="state"`,
`access_type=${accessType}`
]
const googleOAuthEndPath = `${googleAuthorizeURL}?${params.join('&')}`
const response = {
statusCode: 302,
body: '',
headers: {
location: googleOAuthEndPath
}
}
return response
} catch (err) {
return response(400, err.message)
}
}
In the lambda-response, I've added a header for location with the google-path. However, the frontend does not seem to consume the response correctly. The frontend interprets the 302 as in error instead of redirecting to the specific page. Any ideas on how I may resolve this so it actually redirects?
Axios uses XHR, which always follows redirects by itself and therefore Axios can't do anything about it (unless you rely on hacks, discussed in the same link).
You might have to use something other than Axios for this part, such as the Fetch API, which supports manual redirects.
GitHub user parties suggested the fetch() equivalent in the same Axios issue linked above:
fetch("/api/user", {
redirect: "manual"
}).then((res) => {
if (res.type === "opaqueredirect") {
window.location.href = res.url;
} else {
return res;
}
}).catch(handleFetchError);
I can log in and see posts, but I can't seem to comment on these posts pragmatically, and have 0 clue on how to read Direct Messages. Here is my code for logging in and getting media id.
// import axios from 'axios';
// import cheerio from 'cheerio';
const request = require('request-promise');
const cheerio = require('cheerio');
class Instagram {
async commentOnPost({ mediaURL, comment }) {
console.log("here commentPost");
let mediaId = await this.getMediaKey({ mediaURL });
// post comment
const url = `https://www.instagram.com/web/comments/${mediaId}/add/`;
const data = {
'comment_text': comment
}
let commentData;
try {
commentData = await this.session({
method: "POST",
url,
form: data,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Referer': "https://www.instagram.com/" + mediaURL
},
json: true
});
} catch (err) {
console.log(err);
}
console.log(commentData);
}
async function testCase() {
let i = new Instagram();
await i.login({ username: "username", password: "password" });
await i.getMediaKey({ mediaURL: "/p/B7PGlAKl5vx/" });
await i.commentOnPost({ mediaURL: "/p/B7PGlAKl5vx/", comment: "pogchamp!" });
}
};
According to the logs, the code is submitting everything correctly, but I get a 403 error when I send a request to comment on a post. Anyone have experience with this? I have seen libraries like https://github.com/dilame/instagram-private-api but I am not sure how they work, nor how to replicate it in my code.
I've been reading tutorials and seeing examples for 2 days already, with no success.
I want to send an email using Google Apps Gmail account in NodeJS environment, however, i get 400 response from Google API:
{[Error: Bad Request]
code: 400,
errors:
[{
domain: 'global',
reason: 'failedPrecondition',
message: 'Bad Request'
}]
}
Here's what I've done so far:
Created a project in Google Cloud Platform
Created a service account
Enabled Domain Wide Delegation for the service account
Downloaded the key for the service account in JSON format
API Manager > Credentials i have created OAuth 2.0 client ID
Enabled Gmail API for the project
In Google Apps Admin console:
In Security > Advanced Settings > Manage API client access i have added the Client ID from step 4 above
I have added all possible scopes for the Client ID
Here's the code that tries to send an email:
const google = require('googleapis');
const googleKey = require('./google-services.json');
const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], null);
jwtClient.authorize((err, tokens) => {
if (err) {
console.err(err);
return;
}
console.log('Google auth success')
var gmail = google.gmail({version: 'v1', auth: jwtClient})
var raw = <build base64 string according to RFC 2822 specification>
var sendMessage = gmail.users.messages.send({
auth: jwtClient,
userId: 'user#domain.com',
message: {
raw: raw
}
}, (err, res) => {
if (err) {
console.error(err);
} else {
console.log(res);
}
});
I can see the Google auth success message and the request is sent with properly initialized token:
headers:
{ Authorization: 'Bearer ya29.CjLjAtVjGNJ8fcBnMSS8AEXAvIm4TbyNTc6g_S99HTxRVmzKpWrAv9ioTI4BsLKXW7uojQ',
'User-Agent': 'google-api-nodejs-client/0.9.8',
host: 'www.googleapis.com',
accept: 'application/json',
'content-type': 'application/json',
'content-length': 2 }
But still, the response is 400
So I was half-step close to the solution, the problem was that while creating const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], null); i did not mention the account to be impersonated.
The correct initialization should be:
const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], 'user#domain.com');
To summarize, the correct steps are:
Created a project in Google Cloud Platform
Created a service account
Enabled Domain Wide Delegation for the service account
Downloaded the key for the service account in JSON format
API Manager > Credentials i have created OAuth 2.0 Client ID
Enabled Gmail API for the project
In Google Apps Admin console:
In Security > Advanced Settings > Manage API client access i have added the Client ID from step 4 above
I have added all possible scopes for the Client ID
This is the code that sends mails:
const google = require('googleapis');
const googleKey = require('./google-services.json');
const jwtClient = new google.auth.JWT(googleKey.client_email, null, googleKey.private_key, ['https://www.googleapis.com/auth/gmail.send'], '<user to impersonate>');
jwtClient.authorize((err, tokens) => {
if (err) {
console.err(err);
return;
}
console.log('Google auth success')
var gmail = google.gmail({version: 'v1'})
var raw = <build base64 string according to RFC 2822 specification>
var sendMessage = gmail.users.messages.send({
auth: jwtClient,
userId: '<user to impersonate>',
resource: {
raw: raw
}
}, (err, res) => {
if (err) {
console.error(err);
} else {
console.log(res);
}
});
Hope that would be helpful for others
Thanks very much #agoldis. Both the summary steps and the code were very helpful.
It helped me pick up on a few things I needed to fix on both the GoogleWorkspace and the ApplicationCode end of the communication path. Below is my c# implementation for anyone who needs it.
private static void Try4()
{
try {
//file included in project with properties: CopyToOutputDirectory = CopyAlways
var credential = GoogleCredential.FromFile("MyPrj-MyServiceAccount-Credentials.json")
.CreateScoped(new[] { GmailService.Scope.GmailSend })
.CreateWithUser("WhoIAmImpersonating#bla.com")
.UnderlyingCredential as ServiceAccountCredential;
var service = new GmailService(new BaseClientService.Initializer() { HttpClientInitializer = credential });
var nl = Environment.NewLine;
string plainText = "From: WhoIAmImpersonating#bla.com"
+ nl + "To: myfriend#gmail.com,"
+ nl + "Subject: This is the Subject"
+ nl + "Content-Type: text/html; charset=us-ascii"
+ nl
+ nl + "This is the message text.";
var newMsg = new Message() { Raw = Base64UrlEncode(plainText) };
service.Users.Messages.Send(newMsg, "WhoIAmImpersonating#bla.com").Execute();
Console.WriteLine("Message Sent OK");
}
catch (Exception ex) {
Console.WriteLine("Message failed");
}
}
private static string Base64UrlEncode(string input)
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
return Convert.ToBase64String(inputBytes)
.Replace('+', '-')
.Replace('/', '_')
.Replace("=", "" );
}