I'm creating a React app with Firebase for basic backend functionality.
I'm trying to use the Yelp API but am always getting a MISSING_PARAMETER and CORS errors.
Here is my code:
import OAuth from 'oauth-1.0a';
const oauth = OAuth({
consumer: {
public: 'public',
secret: 'secret'
},
signature_method: 'HMAC-SHA1'
});
const url = "https://api.yelp.com/v2/";
const token = {
public: 'public',
secret: 'secret'
};
class YelpWrapper {
static prepareSearch(term, category) {
const requestData = {
url: url + "search/?term=" + term + "&category_filter=" + category + encodeURIComponent("&location=Los Angeles, CA"),
method: "POST"
};
return {
requestData: requestData,
headers: oauth.toHeader(oauth.authorize(requestData, token))
};
}
}
export default YelpWrapper;
and this is called in
static addMemory(memory) {
const { id, category, text, name } = memory;
newMemoryRef(id).set(memory);
const search = YelpWrapper.prepareSearch(name, category);
const { url, method } = search.requestData;
const { headers } = search;
request({
url: url,
method: method,
headers: headers
}, (error, response, body) => {
console.log(error);
console.log(response);
console.log(body);
});
}
Here is the missing parameter error I'm getting
{"error": {"text": "One or more parameters are missing in request", "id": "MISSING_PARAMETER", "field": "oauth_consumer_key"}}
Although when I print the headers I can see all the required headers defined in there, for some reason they don't appear in the Request Headers of Chrome Dev Tools. I think that's the reason, but I can't figure out why that is.
Related
So i been trying to get access to the reddit api.
I registered to reddit. verified my mail. opened an app and got my credentials.
Followed this official documentation and also came across to this tutorial
All my efforts have failed and don't get any respond.
I am using nodejs. but also tried in postman and failed.
Tried 2 options using fetch and using axios:
const axios = require('axios');
const fetch = require('node-fetch')
const { URLSearchParams } = require('url')
class RedditApi {
clientId2 = "get ur own credentials by opening an app here https://www.reddit.com/prefs/apps";
clientSecret2 = "get ur own credentials by opening an app here https://www.reddit.com/prefs/apps";
authenticationUrl = `https://www.reddit.com/api/v1/access_token`;
BASE_URL = 'https://www.reddit.com/';
tokenAuth = null;
tokenExpirationTime = null;
currencyObj = null;
constructor(currencyObj) {
this.currencyObj = currencyObj;
console.log("constructor service")
}
async getAuthToken() {
const bodyParams = new URLSearchParams({
grant_type: "https://oauth.reddit.com/grants/installed_client",
device_id: "DO_NOT_TRACK_THIS_DEVICE"
});
console.log(this.clientId2, 'this.clientId');
debugger;
const headersObj = {
'Authorization': `Basic ${Buffer.from(`${this.clientId2}:`).toString('base64')}`,
'Content-Type': 'application/x-www-form-urlencoded',
};
let response = null;
try {
response = await axios.post(this.authenticationUrl,
bodyParams,
{
headers: headersObj
});
debugger;
} catch (error) {
debugger;
console.error(error);
console.log(error.stack);
return null;
}
}
async getAuthToken2() {
try {
// Creating Body for the POST request which are URL encoded
const params = new URLSearchParams()
params.append('grant_type', 'https://www.reddit.com/api/v1/access_token')
params.append('device_id', 'DO_NOT_TRACK_THIS_DEVICE')
// Trigger POST to get the access token
const tokenData = await fetch('https://oauth.reddit.com/grants/installed_client', {
method: 'POST',
body: params,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${Buffer.from(`${this.clientId2}:`).toString('base64')}` // Put password as empty
}
}).then(res => {
debugger;
return res.text()
})
debugger;
if (!tokenData.error) {
debugger;
res.send(trendingResult)
}
res.status(tokenData.error).send(tokenData.message)
} catch (error) {
debugger;
console.log(error)
}
}
}
module.exports = RedditApi;
when using axios i get this respond: "Request failed with status code 401"
When using fetch i get this respond: "'403 Forbidden\nRequest forbidden by administrative rules.\n\n'"
Anybody knows what is the problem and how can i fix it?
Many thanks!
I am using GraphQL Code Generator with React Query, this is my codegen.yml:
overwrite: true
schema: http://localhost:4000/graphql
generates:
src/lib/__generated__/graphql.ts:
documents:
- "**/graphql/**/*.graphql"
- "!mysqldata/**"
plugins:
- add:
content: &comment "/* DO NOT EDIT! this file was generated by graphql-codegen */\n/* eslint-disable */"
- add:
placement: append
content: "export { fetcher }"
- typescript
- typescript-operations
- typescript-react-query
config:
fetcher:
endpoint: "`${process.env.NEXT_PUBLIC_API_URL}/graphql`"
fetchParams:
credentials: include
headers:
Content-Type: application/json
This generates the following fetcher:
function fetcher<TData, TVariables>(query: string, variables?: TVariables) {
return async (): Promise<TData> => {
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/graphql` as string, {
method: "POST",
credentials: "include",
headers: {"Content-Type":"application/json"},
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (json.errors) {
const { message } = json.errors[0];
throw new Error(message);
}
return json.data;
}
}
NEXT_PUBLIC_API_URL refers to an external GraphQL API.
In my Next.js application I tried to make use of nextjs-auth0 and auth0-react.
nextjs-auth0 allows me to access Auth0's ID token from Next.js API routes:
export default (req: NextApiRequest, res: NextApiResponse) => {
const session = getSession(req, res)
const idToken = session?.idToken
while auth0-react allows me to get the token client side:
const claims = await auth0.getIdTokenClaims();
const idToken = claims.__raw;
The problem is that because of these abstractions, I cannot figure out a way to include this token in requests to my GraphQL endpoint like:
headers: {
authorization: `Bearer ${session?.idToken}`,
},
After I posted a feature request to include the ID token inside a cookie, I figured the "appSession" cookie that's set by nextjs-auth0 is an encrypted token which includes the ID token, I implemented custom server logic using the nextjs-auth0 source code as reference:
type DecodedToken = Record<"idToken" | "token_type", string>
const API_BASE_URL = "https://example.com"
const BYTE_LENGTH = 32
const ENCRYPTION_INFO = "JWE CEK"
const HASH = "SHA-256"
const alg = "dir"
const enc = "A256GCM"
/**
* Derives appropriate sized keys from provided secret random string/passphrase using
* HKDF (HMAC-based Extract-and-Expand Key Derivation Function) defined in RFC 8569
* #see https://tools.ietf.org/html/rfc5869
*/
function deriveKey(secret: string) {
return hkdf(secret, BYTE_LENGTH, { info: ENCRYPTION_INFO, hash: HASH })
}
export const meQueryField = queryField("me", {
type: "User",
async resolve(_, __, ctx) {
const jwe = ctx.request.cookies["appSession"]
if (!jwe) {
return null
}
// eslint-disable-next-line #typescript-eslint/no-non-null-assertion
const octKey = JWK.asKey(deriveKey(process.env["AUTH0_SECRET"]!))
const { cleartext } = JWE.decrypt(jwe, octKey, {
complete: true,
contentEncryptionAlgorithms: [alg],
keyManagementAlgorithms: [enc],
})
const { idToken, token_type: tokenType } = JSON.parse(
cleartext.toString()
) as DecodedToken
const response = await fetch(`${API_BASE_URL}/users/me`, {
headers: {
Authorization: `${tokenType} ${idToken}`,
},
})
const user = (await response.json()) as Response
return {
id: user.data.id,
...
}
},
})
It's not pretty but it works. AUTH0_SECRET is the same secret that's used to encrypt the token in nextjs-auth0
this is my code :
Express Routes:
router.route('/block')
.post(controller.ticketBlocking);
Express Controller:
const axios = require('axios');
const OAuth = require('oauth-1.0a');
const crypto = require('crypto');
const ticketBlocking = (req, res) => {
const data = JSON.stringify({
source = req.body.source
});
const oauth = OAuth({
consumer: {
key: '....', //Hided the key
secret: '....', //Hided the secret
},
signature_method: 'HMAC-SHA1',
hash_function(base_string, key) {
return crypto.createHmac('sha1', key).update(base_string).digest('base64');
}
});
const request_data = {
url: 'http://link.vvv/blockTicket',
method: 'post',
};
axios({
method: request_data.method,
url: request_data.url,
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
...oauth.oauth.toHeader(oauth.oauth.authorize(request_data)),
},
data : data
})
.then((response) => {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
console.log(error.config);
});
};
the npm package which am using is - "oauth-1.0a"
The problem am facing is, when i use GET method with different end point, i get an output but when ever i use POST method am getting an empty error with status code 500
I dont know where is the mistake, am using oauth1.0a for authorization, please help !
I'm trying to retrieve, then POST a JPEG image to Foursquare's https://api.foursquare.com/v2/photos/add endpoint using Axios in Node. I've tried a few methods with Axios (and Postman) but always receive the same error response of Missing file upload:
{
"meta": {
"code": 400,
"errorType": "other",
"errorDetail": "Missing file upload",
"requestId": "NNNNNNNNNNNNNNNNNNNNN" // not the true requestId
},
"notifications": [
{
"type": "notificationTray",
"item": {
"unreadCount": 0
}
}
],
"response": {}
}
The image is created using the Google Static Map API and retrieved with an Axios GET request:
const image = await axios.get(imageURL, {
responseType: "arraybuffer"
});
which is wrapped in an async function and successfully returns a buffer. The data is read into a Buffer and converted to a string:
const imageData = new Buffer(image, "binary").toString();
Here's an example imageData string. I've also tried converting the string to base64.
This string is then POSTed to the Foursquare endpoint:
const postPhoto = await axios.post(
"https://developer.foursquare.com/docs/api/photos/add?
checkinId=1234&
oauth_token=[TOKEN]&
v=YYYYMMDD",
imageData,
{
headers: { "Content-Type": "image/jpeg" }
}
);
where the checkinId, oauth_token and v params are all valid.
I've tried different Content-Type values, base64 encoding the imageData and several other solutions found in forums and here on SO (most are several years old), but nothing works. The response errorDetail always says Missing file upload.
The issue could be in how the POST request is structured, but I could also be requesting/handling the image data incorrectly. A 2nd (or 3rd, or 4th) set of eyes to check I'm putting this together would be super helpful.
Whew, I have finally solved this.
I was eventually able to get it working thru Postman which provided some hints. Here's the Postman code snippet using request:
var fs = require("fs");
var request = require("request");
var options = { method: 'POST',
url: 'https://api.foursquare.com/v2/photos/add',
qs:
{ checkinId: [MY CHECKING ID],
public: '1',
oauth_token: [MY OAUTH TOKEN],
v: [MY VERSION] },
headers:
{ 'postman-token': '8ce14473-b457-7f1a-eae2-ba384e99b983',
'cache-control': 'no-cache',
'content-type': 'multipart/form-data; boundary=---- WebKitFormBoundary7MA4YWxkTrZu0gW' },
formData:
{ file:
{ value: 'fs.createReadStream("testimage.jpg")',
options: {
filename: 'testimage.jpg',
contentType: null
}
}
}
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
The key part of this was fs.createReadStream(). The part I was missing before was to pass the image as a stream to the request.
Using this I was able to figure out the Axios request:
const axios = require("axios");
const querystring = require("qs");
const FormData = require("form-data");
const getImageStream = async function(url) {
return await axios
.get(url, {
responseType: "stream"
})
.then(response => response.data);
};
let form = new FormData();
form.append("file", getImageStream([IMAGE URL]));
const requestURL = "https://api.foursquare.com/v2/photos/add";
const requestParams = {
checkinId: [MY CHECKIN ID],
public: 1,
oauth_token: [MY OAUTH TOKEN],
v: [MY VERSION]
};
const requestConfig = {
headers: form.getHeaders()
};
try {
const postPhoto = await axios.post(
requestURL + "?" + querystring.stringify(requestParams),
form,
requestConfig
);
return postPhoto;
} catch (e) {
console.error(e.response);
}
And voila, the request succeeds and the image is posted to the Foursquare checkin.
I am confused about http requests and how it works when requesting links.
So I know a GET requests adds parameters to urls like ?username=ABC123&password=TTT and POST just sends data to the server but thats all I get when reading tutorials out there. How would I for example send a request and download a file from a rapidgator link after authenticating? (I am a premium user).
Link to their api doc:
https://support.rapidgator.net/index.php?/Knowledgebase/Article/View/89/9/do-you-have-api
The first response gives back a response object like this which gives the session id which is where I got the session id from:
{
"response": {
"expire_date":1351526400,
"traffic_left":0,
"reset_in":11695
},
"response_status":200,
"response_details":null
}
This is my code:
const rp = require('request-promise');
const url = 'http://rapidgator.net/api/user/login';
const opts = {
uri: url,
qs: {
username: '**censored**',
password: '**censored**',
},
headers: {
'User-Agent': 'Request-Promise'
},
json: true
}
rp(opts)
.then(( resp ) => {
const sessionId = resp.session_id;
const postOpts = {
uri: 'http://rapidgator.net/api/user/info?sid=knf3pqpg3ldm05qnol0sn16326',
method: 'POST',
body: {
session_id: sessionId
},
json: true
}
rp(postOpts)
.then(res => {
console.log(cyan(JSON.stringify(res, null, 2)));
})
})
.catch(( err ) => {
throw Error(err);
});
Am I approaching this the wrong way? How do I proceed to download links from rapidgator?