Axios post with firebase cloud functions - javascript

I have a basic firebase cloud function. I want to post a request with Axios (send Slack message). But the server returns "Error: could not handle the request (500)". Where is the problem? I use cors.
const cors = require('cors')
const functions = require('firebase-functions')
const Axios = require('axios')
exports.sendMessage = functions.https.onRequest((request, response) => {
return cors()(request, response, () => {
return Axios.post(
`https://hooks.slack.com/services/*XXXXXXXXXXXXX*`,
{
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: 'hello',
},
},
],
}
)
})
})

It seems like you're using cors incorrectly. Also you should return any value using provided response. Check below for detail.
const cors = require('cors')({origin: true});
exports.sendMessage = functions.https.onRequest((request, response) => {
return cors(request, response, async () => {
try {
const res = await Axios.post(
`https://hooks.slack.com/services/*XXXXXXXXXXXXX*`,
{
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: 'hello',
},
},
],
},
);
response.status(res.status).json(res.data);
} catch (error) {
response.status(400).json(error);
}
});
});

The way to accomplish this is to add the header "Content-Type": "application/x-www-form-urlencoded" to the post. You would do it like this with the code you provided:
const cors = require('cors')
const functions = require('firebase-functions')
const Axios = require('axios')
exports.sendMessage = functions.https.onRequest((request, response) => {
return cors()(request, response, () => {
return Axios.post(
`https://hooks.slack.com/services/*XXXXXXXXXXXXX*`,
{
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: 'hello',
},
},
],
},
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
}
)
})
})
Slack API doesn't seem to play nice with regular JSON, which is the default of Axios, so that is why it needs to be changed.
Hope this fixes it for you!

Related

How to catch the message button click event on Slack, and get the input value

I am trying to make a small NodeJS project to connect to Slack, post an interactive message, and receive feedback.
My code to post the message:
require("dotenv").config();
const { App } = require("#slack/bolt");
const express = require('express')
const app = express()
const axios = require('axios');
const APP_PORT = 3001
const LISTEN_PORT = 3002
const { createMessageAdapter } = require('#slack/interactive-messages');
const slackSigningSecret = process.env.SLACK_SIGNING_SECRET;
const slackInteractions = createMessageAdapter(slackSigningSecret);
app.use('/listen', slackInteractions.requestListener());
(async () => {
const server = await slackInteractions.start(LISTEN_PORT );
console.log(`Listening for events on ${server.address().port}`);
})();
app.listen(APP_PORT, () => {
console.log(`App running on port ${APP_PORT}.`)
})
app.get('/survey', async function sendmessage(){
const url = 'https://slack.com/api/chat.postMessage';
const res = await axios.post(url, {
channel: '#test',
blocks: JSON.stringify([
{
type: "section",
text: {
type: "mrkdwn",
text: "Survey"
}
},
{
type: 'input',
block_id: 'txt_input',
label: {
type: 'plain_text',
text: 'Response'
},
element: {
type: 'plain_text_input',
action_id: 'text_input',
placeholder: {
type: 'plain_text',
text: 'Your response'
},
multiline: true
}
},
{
type: "actions",
block_id: "btn_submit",
elements: [
{
type: "button",
text: {
type: "plain_text",
emoji: true,
text: "Submit"
},
style: "primary",
value: "1"
}
]
}
])
}, { headers: { authorization: `Bearer ${process.env.SLACK_BOT_TOKEN}`}});
});
The above code successfully post an interactive message on Slack channel. When user input the value and click button Submit, I would like to catch it and process.
I have read the Slack guide from Slack Interactive Messages for Node for how to listen to the event, but unable to success in any of it.
I add the below code to listen to the button event, but unable to catch anything.
slackInteractions.action({ type: 'button' }, (payload, respond) => {
// Logs the contents of the action to the console
console.log('payload', payload);
});
slackInteractions.action({ type: 'message_action' }, (payload, respond) => {
// Logs the contents of the action to the console
console.log('payload', payload);
});
What did I do wrong?
I think you need to add the slackInteractions middleware to your Bolt app:
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,
receiver: slackInteractions.receiver
});

Axios instance/function not receiving argument?

I have a next.js App which has a working axios call, which I am trying to refactor. I have it mostly working, but I can't get my new function to receive arguments.
This problem has two components to it, my next.js page, and the external custom module where I am writing my functions to use axios to call the YouTube API to retrieve info.
My next.js getStaticProps call looks like this. I know this is working. Note the function where I am trying to pass in the video ID. (The 'const = video' line)
export async function getStaticProps(context: any) {
// It's important to default the slug so that it doesn't return "undefined"
const { slug = "" } = context.params;
const film = await client.fetch(query, { slug });
const video = await youtube.grabVideoInfo(film.VideoID);
return {
props: {
film,
video,
},
revalidate: 10,
};
}
I have tried writing the axios call in two ways, trying to pass in the video ID as an argument. Neither of which work, and fail to call from the API, stating an invalid video ID, which means it isn't being passed in.
The first way:
const grabVideoInfo = async (videoId) => {
const videoGrab = axios.create({
baseURL: "https://www.googleapis.com/youtube/v3/videos?",
params: {
headers: { "Access-Control-Allow-Origin": "*" },
part: "snippet",
id: videoId,
key: KEY,
},
});
const query = await videoGrab.get().then(
(response) => {
return response.data.items[0];
},
(error) => {
return error.toJSON();
}
);
return query;
};
The second way:
const grabVideoInfo = async (videoId) => {
const videoGrab = axios.create({
baseURL: "https://www.googleapis.com/youtube/v3/videos?",
params: {
headers: { "Access-Control-Allow-Origin": "*" },
part: "snippet",
key: KEY,
},
});
const query = await videoGrab.get({ params: { id: videoId } }).then(
(response) => {
return response.data.items[0];
},
(error) => {
return error.toJSON();
}
);
return query;
};
And this is the fully working version that I am trying to rewrite, which is live on the app currently. This demonstrates that the getStaticProps client call is working.
export async function getStaticProps(context: any) {
// It's important to default the slug so that it doesn't return "undefined"
const { slug = "" } = context.params;
const film = await client.fetch(query, { slug });
const KEY = process.env.YOUTUBE_API_KEY;
const conn = axios.create({
baseURL: "https://www.googleapis.com/youtube/v3/",
params: {
headers: { "Access-Control-Allow-Origin": "*" },
part: "snippet",
id: film.videoID,
key: KEY,
},
});
const video = await (await conn.get("videos?")).data.items[0];
return {
props: {
film,
video,
},
revalidate: 10,
};
}
Any help is greatly appreciated. I'm really scratching my head with this one.
Ok so your refactor is accessing film.VideoId where the original uses film.videoId.

URQL WSS connection with GraphQL-WS says error 4500

import {
createClient,
defaultExchanges,dedupExchange, cacheExchange, fetchExchange,
subscriptionExchange,
gql
} from "#urql/core";
import { createClient as createWSClient } from "graphql-ws";
import { pipe, subscribe } from "wonka";
import { getToken, setToken } from "./helper";
const wsClient = createWSClient({
url: 'wss://**********/subscriptions',
reconnect: true,
});
const client = createClient({
url: "https://***********/",
fetchOptions: () => {
const token = getToken()
return token ? { headers: { authorization: `Bearer "${token}"` } } : {}
},
// the default:
exchanges: [
...defaultExchanges,
subscriptionExchange({
forwardSubscription(operation) {
return {
subscribe: (sink) => {
const dispose = wsClient.subscribe(operation, sink);
return {
unsubscribe: dispose,
};
},
};
},
}),
]
});
SUB_TO_MESSAGES = async () => {
console.log('sub')
const token = getToken();
console.log(String(token))
const { unsubscribe } = pipe(
await client.subscription(messageAdded,{ jwt: token }),
subscribe((result) => {
console.log(result)
})
)
};
I dont get the same issue with try and catch using GraphQL-WS but I still dont get any data from the server. The assignment is a vanillaJS project using GraphQL.I didndt post the url, jwt token,or the GET, POST, REgG as they work as intended. The rendering is done with a proxy. The error message is:
Connection Closed: 4500 Cannot read properties of undefined (reading 'Authorization')
Even playground doesnt work. Something wrong with the endpoint. It worked 2 weeks ago but admin says it still work yet I can find the problem. It used to work for me.
Here is the try and catch version:
import { createClient} from "graphql-ws";
import pStore from "./handler.js";
import { getToken } from "./helper";
const client = createClient({
url: "wss://******/subscriptions",
reconnect: true,
connectionParams:{
headers: {
"Authorization":`Bearer ${getToken()}`
}
},
})
async SUB_MESSAGE() {
try {
console.log('called Gql server')
const onNext = (res) => {
let obj = res.data.messageAdded
console.log(obj)
pStore[obj.id] = obj
pStore.render(obj)
};
let unsubscribe = () => {
/* complete the subscription */
};
new Promise((resolve, reject) => {
client.subscribe({
query: `subscription{messageAdded(jwt:"${getToken()}"){id text fromAgent createdAt updatedAt}}`,
},
{
next: (data)=> onNext(data),
error: reject,
complete: () => resolve(true),
})
})
}catch(error){
console.error('There has been a problem with your ws operation:', error);
}
}
Either way I think its a ad character, scope issue but I dont know where.

Jest custom axios interceptor

i am trying to use jest with nextJS to test API. I am using a custom interceptor for all http request to have authorization token on header. Here is my interceptor code
Api.ts
import axios from 'axios';
import config from '../config/index';
const Api = () => {
const defaultOptions = {
baseURL: config.APIENDPOINT,
method: 'get',
headers: {
'Content-Type': 'application/json',
},
};
// Create instance
let instance = axios.create(defaultOptions);
// Set the AUTH token for any request
instance.interceptors.request.use((config) => {
const token = localStorage.getItem('token');
//#ts-ignore
config.headers.Authorization = token ? `${token}` : '';
return config;
});
instance.interceptors.response.use((res) => {
return res
});
return instance;
};
export default Api();
Here is the code to call the API
export const loadMerchants = async (id: any) => {
const data = await Api.get(config.APIENDPOINT + "/merchants/company/" + id)
console.log("data" ,data);
return (data)
}
And here is my test code
const axios = require('axios');
jest.mock('axios', () => {
return {
get: jest.fn(),
create: jest.fn(() => ({
interceptors: {
request: { use: jest.fn(() => Promise.resolve({ data: { foo: 'bar' } })) },
response: { use: jest.fn(() => Promise.resolve({ data: { foo: 'bar' } })) },
}
}))
}
})
it('Merchant API call', async () => {
axios.get.mockResolvedValue({
data: [
{
userId: 1,
id: 1,
title: 'My First Album'
},
{
userId: 1,
id: 2,
title: 'Album: The Sequel'
}
]
});
const merchants = await loadMerchants("1")
console.log(merchants) //always undefined
// expect(merchants).toEqual('some data');
});
on my API call if use axios.get instead of Api.get i get the correct results. I have looked into google and haven`t found any solutions.
Any help would be appreciated. Thank you.

Getting ERR_SSL_PROTOCOL Error when trying to send a post request to my Node.js Server in ReactJs

I am creating a DHL API for checking shipment rates. I have uploaded my Node.js Server using putty and it is running correctly when I enter my IP address and port number.
In development, there are no erros or issues and I get back the response and get the rates back from the form I have set up for my users.
but in Production, when I upload my website to Hostinger I get this error " Failed to load resource: net::ERR_SSL_PROTOCOL_ERROR"
In production, it sends my post request with HTTPS instead of HTTP. And even when I change the HTTPS to HTTP in the browser I get another error saying "Cannot GET /api/dhl"
Here are some images to help make it more clear:
The Errors.
When my website submits the post request with HTTPS instead of HTTP.
When I manually change the URL from HTTPS to HTTP
What am I doing wrong? Why is this happening and how can I fix it?
Here is my code:
const express = require('express');
const port = 3001
app.post('/api/dhl', (req, res) => {
const accountNum = req.body.accountNum
const fromCountriesCode = req.body.fromCountriesCode
const fromCountriesCapital = req.body.fromCountriesCapital
const fromCity = req.body.fromCity
const fromPostalCode = req.body.fromPostalCode
const toCountriesCode = req.body.toCountriesCode
const toCountriesCapital = req.body.toCountriesCapital
const toCity = req.body.toCity
const toPostalCode = req.body.toPostalCode
const weight = parseInt(req.body.weight)
const plannedShippingDate = req.body.date
const len = "5"
const width = "5"
const height = "5"
const isCustomsDeclarable = 'false'
const unitOfMeasurement = 'metric'
console.log(weight)
console.log(fromCountriesCode)
console.log(toCountriesCode)
console.log(fromCity)
console.log(toCity)
var options = { method: 'POST',
url: 'https://express.api.dhl.com/mydhlapi/rates',
headers:
{ 'postman-token': '',
'cache-control': 'no-cache',
authorization: 'Basic myauthkey',
'content-type': 'application/json' },
body:
{ customerDetails:
{ shipperDetails:
{ postalCode: fromPostalCode,
cityName: fromCity,
countryCode: fromCountriesCode,
addressLine1: '0' },
receiverDetails:
{ postalCode: toPostalCode,
cityName: toCity,
addressLine1: '0',
countryCode: toCountriesCode }
},
accounts: [ { typeCode: 'shipper', number: 'my account number' } ],
plannedShippingDateAndTime: '2021-08-25T13:00:00GMT+00:00',//Might need to change later
unitOfMeasurement: 'metric',
isCustomsDeclarable: true,
monetaryAmount: [ { typeCode: 'declaredValue', value: 10, currency: 'BHD' } ],
requestAllValueAddedServices: false,
returnStandardProductsOnly: false,
nextBusinessDay: false,
packages: [ { weight: weight, dimensions: { length: 5, width: 5, height: 5 } } ] },
json: true };
request(options, function (error, response, body) {
if (error) throw new Error(error);
res.send(body)
console.log(body);
});
});
//Start the Server
app.listen(port, () => {
console.log(`Server running at :${port}/`);
});
My Check-Rates File:
const getRateEstimate = () => {
axios.post('http://MY_IP:3001/api/dhl', {
fromCity,
fromCountriesCapital,
fromCountriesCode,
fromPostalCode,
toCountriesCapital,
toCountriesCode,
toPostalCode,
toCity,
weight,
}).then(response => {
console.log(response)
setData(response.data);
}).catch(e => {
console.log(e)
});
}

Categories

Resources