I am at my wits end! I am trying to create a customer via the stripe api. Using their example with curl i have no problems.
Here is their example:
curl https://api.stripe.com/v1/customers \
-u sk_test_apikey: \
-d description="Customer for zoey.brown#example.com" \
-d source=tok_visa
It is when i try to do this with axios that i get an error "invalid_request_error" because it isn't properly parsing my data. Here's what i've got:
export const registerNewUser = async (firstName, lastName, email, password) => {
let config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Bearer ${stripeTestApiKey}`
}
}
let data = {
email: `${email}`,
description: `Customer account for ${email}`
}
await axios.post(stripeCustomerUri, data, config)
.then(res => {
console.log("DEBUG-axios.post--res: ", res)
})
.catch(err => {
console.log(JSON.stringify(err, null, 2))
})
}
and in my console i see that stripe isn't receiving my data in the correct manner. Here's the (useful part of my) response json:
"response": {
"data": {
"error": {
"type": "invalid_request_error",
"message": "Received unknown parameter: {\"email\":\"joe#blow.com\",\"description\":\"Customer account for joe#blow.com\"}", "param": "{\"email\":\"joe#blow.com\",\"description\":\"Customer account for joe#blow.com\"}" } },
Judging by all of my other attempts and this example error, I am not passing my data in the correct format... However, when i pass -d to my curl command everything works as expected... If I send an empty string as data it works as well...
does anyone have an idea why / how this is? How is the "data" object via curl differ from my javascript data object?
The problem was that axios uses application/json content type by default and the stripe api requires form-url-encoded... this requires parsing the data object with a library like querystring before passing through to the stripe api... hope this helps someone!
Related
I have used Postman to explore an API for Samsung's SmartThings. I have that working as expected. But when I take that information and try to implement it in node with Axios the data returned looks like it is compressed or some other blob. Here is the code I am trying to use to get the response:
const axios = require("axios");
function main() {
const st_api = axios.create();
st_api
.get("https://api.smartthings.com/v1/locations/", {
headers: {
get: {
Accept: "application/vnd.smartthings+json",
},
Authorization: process.env.my_home_token,
},
responseType: "json",
responseEncoding: "utf8",
decompress: true,
})
.then(function (res) {
console.log("Status: ", res.status);
console.log("Data: ", res.data);
})
.catch(function (err) {
console.log("Error: ", err);
});
}
main();
And the console log returned is:
Status: 200
Data: �$ͱ�0��W1wn��-H�����d���6KK��»[�v�/���������BC���BXn���%�ek3��j��&�� m�x�M��i�i1 ��פ��8�`�����4�r_����d�ޤ�A�Z��K�K��UV�rk²�<\�_㿻���wA��
I have tried inserting gzip to decompress it or other header information but nothing changes. I am expecting some json returned (or at least something human readable would be a start). I believe I distilled my simple (I hope) api call to a brief test and nothing I try has changed the data being returned.
This is a bug in Axios. Downgrade your Axios version to 1.1.3 or lower, and don't upgrade until 1.3.0 is released. Ref: https://github.com/axios/axios/pull/5300, https://github.com/axios/axios/pull/5306
My react native code:
const signin =
(dispatch) =>
async ({ username, password }) => {
try {
console.log(username, password);
const response = await tracker.post(
"/login",
(data = { username, password }),
(headers = {
"content-type": "application/x-www-form-urlencoded",
})
);
await AsyncStorage.setItem("token", response.data.token);
dispatch({ type: "signin", payload: response.data.token });
console.log(response.data.token);
} catch (err) {
console.log(err);
dispatch({
type: "error",
payload: "This is an error, start debugging",
});
}
};
Curl request to FastAPI backend:
curl -X 'POST' \ 'https://fastest.herokuapp.com/login/' \ -H 'accept: application/json' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=&username={email}&password={password}&scope=&client_id=&client_secret=
whenever I try to create a new user or sign in with an existing user I keep getting following error:
[AxiosError: Request failed with status code 422]
Is there a better way to send a POST request with curl to signup or login using axios?
Now, I know this is a well documented error on internet, but, somehow, I am unable to find the error and debug it. Any feedback as to what I am doing wrong?
Edit:
FastAPI endpoint code:
#router.post("/",response_model=schemas.Token)
def getLogin(user_Credentials:OAuth2PasswordRequestForm=Depends(),db: Session=Depends(database.get_db)):
user = db.query(models.User).filter(models.User.email == user_Credentials.username).first()
if not user:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=f"wrong credentials")
if not utils.verify(user_Credentials.password,user.password):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=f"wrong credentials")
access_token = oauth2.create_access_token(data={"user_id": user.id})
return {"access_token":access_token, "token_type":"bearer"}
For full code:
Backend FastAPI: here
Frontend react native: here
Error Changed
After adding qs.stringify() according to https://axios-http.com/docs/urlencoded and updating the code as follows:
const signin =
(dispatch) =>
async ({ username, password }) => {
try {
console.log(username, password);
const response = await tracker({
method: "post",
url: "/login",
data: qs.stringify({
username: username,
password: password,
}),
headers: {
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
});
console.log(response.data.token);
await AsyncStorage.setItem("token", response.data.token);
dispatch({ type: "signin", payload: response.data.token });
} catch (err) {
console.log(err);
dispatch({
type: "error",
payload: "Start debuggin",
});
}
};
the problem arises now is that token is undefined, but the when I enter same credentials on /docs I get the token.
Final update: got the endpoint wrong for token access
As per Javascript documentation:
A variable that has not been assigned a value is of type undefined.
A method or statement also returns undefined if the variable that is
being evaluated does not have an assigned value. A function returns
undefined if a value was not returned.
In your case, you attempt to retrieve an attribute, namely token, from the JSON repsonse returned by your FastAPI backend. However, such an attribute does not exist in that JSON object. Your API endpoint returns "access_token": access_token, hence, you should instead use response.data.access_token.
Also, for future reference, a response having status code 422 (unprocessable entity) will have a response body that specifies the error message, telling exactly which part of your request is missing or doesn’t match the expected format. This will guide you to fix the error in your code.
Please try to send your authentication data as FormData.
let bodyFormData = new FormData();
bodyFormData.append("username", "value");
bodyFormData.append("password", "value");
then send it as you did:
const response = await tracker.post(
"/login",
(data = bodyFormData),
(headers = {
"content-type": "application/x-www-form-urlencoded",
})
);
It should be mentioned that I didn't do much with react-native, but I guess this work for your case.
*My goal here is to get the location of bikes from a bike-sharing company's API.
I did Steps 1 and 2 using Postman. but ill try to integrate it into my code once I get the hang of it.
The first step is to verify your email and generate an Auth token. This requires only a verifiable email address. Make a POST request to https://web.spin.pm/api/v1/magic_links with the body:
{"email": "sampleemail#gmail.com"}
From there, you will need to find the token within your email. This token needs to be sent with a POST request to
https://web.spin.pm/api/v1/auth_tokens with the body:
{
"grant_type": "magic_link",
"magic_link": {
"email": "<email>",
"token": "<token>"
}
}
This request returns a JSON that looks like this: {"jwt":"eyJ0eXAiOiJ.....cXVLw","refreshToken":"2cb07....bab5030","existingAccount":false}
To get the position of vehicles so a GET-Request to https://web.spin.pm/api/v3/vehicles?lng=-77.0146489&lat=38.8969363&distance=&mode= User Header Authorization: Bearer to Authenticate and use the jwt-Token we got from the Auth request.
You will get something like this as return JSON {"vehicles":[{"lat":37.69247,"lng":-122.46595,"last4":"3595","vehicle_type":"bicycle","batt_percentage":null,"rebalance":null}, … ]}
Step 3 is done using (async/awit function) using fetch where I am having the problem with. I copy-pasted the jwt in my .env file and set up the proper headers.
I get a 401 response when making the call. when I tested step 3 using postman everything seems to work fine.
I have attached a screenshot of the error in this post. Hopefully its more clear, Thanks in advance.
const fetch = require("node-fetch");
require('dotenv').config();
async function getBikes()
{
const lat = '38.897574612438575';
const lng = '-77.01855164084469';
const api_url = `https://web.spin.pm/api/v3/vehicles?lng=${lng}&lat=${lat}&distance=&mode=`;
const jwt_key = process.env.BERER_KEY;
try{
const config = { method: 'GET',
headers: {json: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer'+ jwt_key
} },
rejectUnauthorized: false
};
const response = await fetch(api_url,config );
const data = await response.json(); //response.json() //headers //.jwt; //response.json()
if (response.ok)
{
console.log("STATUS CODE IS: "+response.status);
console.log('My JWT:', response);
return data;
}
else{
console.log("something went wrong ");
console.log("STATUS CODE IS: "+ response.status);
console.log( response);
}
} catch (error) {
console.log(error);
}
}
const y = getBikes();
console.log(y)
BEARER_KEY=eyJhbGciOiJIUzI1NiJ9.eyJ1c2V
I am trying to use DialogFlow v2 endpoint but for some reason I am getting not authorized message, eventhou I am able to generate access token using the following command:
Initially I am running this to authorize the service for my local machine to be able to authorize to the service: gcloud auth activate-service-account --key-file=<service-account-key-file.json> then I get access token by following command: gcloud auth print-access-token and this access token I am attaching on the following code:
fetch(configs.baseUrl + "query?v=20150910", {
body: JSON.stringify({query: text, lang: "en", sessionId: "somerandomthing"}),
headers: {
'content-type': 'application/json',
"Authorization": "Bearer " + accessToken,
},
method: 'POST',
})
.then(response => response.json())
.then(data => {
console.log(data.result.fulfillment.speech);
return data.result.fulfillment.speech;
})
.catch(error => console.error(error))
I dont know if this is the right way to achieve a communication with DialogFlow V2?
Please if you could let me know what I am doing wrong and why I it says I am not authorised since I am authorizing by the above commands and been able to get access token!
Edit:
After few changes my code finally looks like this:
fetch("https://dialogflow.googleapis.com/v2beta1/projects/xxx/agent/sessions/xxx/:detectIntent", {
body: JSON.stringify({queryInput: "Hello"}),
headers: {
'content-type': 'application/json',
"Authorization": "Bearer xxxx",
},
method: 'POST',
})
.then(response => response.json())
.then(data => {
console.log(data.result.fulfillment.speech);
return data.result.fulfillment.speech;
})
.catch(error => console.error(error))
and the new error message I get is:
{
"error": {
"code": 400,
"message": "Invalid value at 'query_input' (type.googleapis.com/google.cloud.dialogflow.v2beta1.QueryInput), \"Hello\"",
"status": "INVALID_ARGUMENT",
"details": [
{
"#type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "query_input",
"description": "Invalid value at 'query_input' (type.googleapis.com/google.cloud.dialogflow.v2beta1.QueryInput), \"Saanko yhteystiedot?\""
}
]
}
]
}
}
You don't show the baseUrl you're using, but that looks like the V1 API rather than the V2 API. You should migrate your code to V2.
Keep in mind, also, that the access token expires, so you will need to generate a new one periodically. You cannot request a "long lived" token (this is considered insecure), but should have your code call gcloud auth print-access-token (or use a library to do the same thing) before the previous one expires.
Update based on your code once you've moved it to V2:
The queryInput parameter doesn't take a string directly. It must be set to a QueryInput object. This is an enum, so can only have one of the fields specified set. It looks like you want the text field which requires a TextInput object.
So your body parameter might be setup something like this:
var body = {
queryInput: {
text: {
text: "Hello",
language: "en-US"
}
}
};
var bodyStr = JSON.stringify(body);
and then set in your request() options.
Because you have put wrong URL in your project.
Open below image and see which URL use for posturl in your project
https://i.stack.imgur.com/3ym9n.png
I'm having a hard time trying to make a basic zomato api request work, in reactjs.
The api documentation looks so simple. I'm doing a basic GET request to categories: https://developers.zomato.com/documentation#!/common/categories
And here's how my ReactJS function looks like:
componentDidMount() {
// A previous request for london restaurants
// axios.get('https://developers.zomato.com/api/v2.1/geocode?
lat=51.5138&lon=0.0984')
axios.get('https://developers.zomato.com/api/v2.1/categories')
.then(res => {
console.log(res.data);
this.setState(
{ places: res.data});
});
}
However, I keep getting this response when I hit any api url, in the browser. Or via insomnia.
{
"code": 403,
"status": "Forbidden",
"message": "Invalid API Key"
}
I know it says invalid API. But I've gotten these URLs after loggin in and applying any API key in Zomato's developer portal. Can't find any intructions to figure where I've gone wrong...
Thanks,
Reena.
i got it, the answer was this:
const config = { headers: {'user-key': 'MY KEY HERE'} };
enter code here
axios.get('developers.zomato.com/api/v2.1/…;, config) .then(res => {
console.log(res.data.collections); this.setState( { places:
res.data.collections }); });
thank you all.
Pass the API_Key from Headers you'll get the response data.
axios({
method: "GET",
url: "https://developers.zomato.com/api/v2.1/search",
headers: {
"user-key": "b8cc3b8b0a85afed047f030fb52dc15f",
"content-type": "application/json"
}
})
.then(response => {
console.log(response.data.restaurants[0].restaurant.name);
})
.catch(error => {
console.log(error);
});
You need to set this key this in the request header.
X-Zomato-API-Key:
Sample request:
curl -X GET --header "Accept: application/json" --header "X-Zomato-API-Key: <YOUR_API_KEY>" "https://developers.zomato.com/api/v2.1/categories"
Hope this will help you.
Seems you are missing user-key parameter and its value. For example, the URL should be something like:
https://developers.zomato.com/api/v2.1/categories?user-key=<your API key>