So I am practising some nodejs and this time I am playing around with steam api and json objects. But I am having some problems.
So, from the Steam api,
http://steamcommunity.com/profiles/<steamid>/inventory/json/730/2
I got the json from this code,
var request = require('request');
var url = "http://steamcommunity.com/profiles/<steamid>/inventory/json/730/2"
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
var json = JSON.parse(body);
console.log(body)
}
});
And the json looks lite this, json-link
From the json I want to take out the classid and instanceid from each of the items, but there comes the problem. I don't know how. I know I need to parse it but nothing more unfortunately.
Would be very helpful if someone could explain how, or link a guide/tutorial so I can learn.
Thanks!
EDIT:
var request = require('request');
var _ = require('lodash');
var url = "http://steamcommunity.com/profiles/76561198007691048/inventory/json/730/2";
request({
url: url,
json: true
}, function jsonParse(error, response, data) {
console.log(data.rgDescriptions);
var item = getItems(data.rgDescriptions);
console.log(item);
}
);
function getItems(data){
var item = data;
if(!item){
return "error";
}
return _(item).keys().map(function(id){
return _.pick([id], "name");}).value();
Console give me this; [ {}, {}, {}, {}, {}, {}, {}, {},
{},.... ]
JSON look like this;
'1293508920_0':
{ appid: '730',
classid: '1293508920',
instanceid: '0',
icon_url: '-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXU5A1PIYQNqhpOSV-fRPasw8rsUFJ5KBFZv668FF4u1qubIW4Su4mzxYHbzqGtZ-KGlz8EuJcg3rnE9NiijVe3_UY-Zzr2JJjVLFEEeiQRtg',
icon_drag_url: '',
name: 'Shadow Case',
market_hash_name: 'Shadow Case',
market_name: 'Shadow Case',
name_color: 'D2D2D2',
background_color: '',
type: 'Base Grade Container',
tradable: 1,
marketable: 1,
commodity: 1,
market_tradable_restriction: '7',
},
'1644880589_236997301':
{ appid: '730',
classid: '1644880589',
instanceid: '236997301',
icon_url: '-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXU5A1PIYQNqhpOSV-fRPasw8rsUFJ4MAlVo6n3e1Y27OPafjBN09izq42ChfbzNvXTlGkD6p0lj7_FpNjx0VDj_UBoZ272cNfBdg48MAyB-VS3xum61Me_ot2XnqkB5QYc',
icon_drag_url: '',
name: 'MLG Columbus 2016 Mirage Souvenir Package',
market_hash_name: 'MLG Columbus 2016 Mirage Souvenir Package',
market_name: 'MLG Columbus 2016 Mirage Souvenir Package',
name_color: 'D2D2D2',
background_color: '',
type: 'Base Grade Container',
tradable: 1,
marketable: 1,
commodity: 0,
market_tradable_restriction: '7',
},
To work with complex objects or collections you can use lodash library.
So, you have json with the following format:
{
"success":true,
"rgInventory": {
"5719625206": {"id":"5719625206","classid":"1651313004","instanceid":"188530139","amount":"1","pos":1},
"5719034454": {"id":"5719034454","classid":"1649582636","instanceid":"188530139","amount":"1","pos":2},
"5718628709": {"id":"5718628709","classid":"1649582636","instanceid":"188530139","amount":"1","pos":3},
...
}
}
To extract array of required items, first of all install lodash library in your project: npm i -S, after that add this code into your file:
var _ = require('lodash');
function extractItems(data) {
var rgInventory = _.get(data, 'rgInventory');
if (!rgInventory) {
return [];
}
return _(rgInventory)
.keys()
.map(function(id) {
return _.pick(rgInventory[id], ['classid', 'instanceid']);
})
.value();
}
Related
Here with javascript we do an API POST using a external JSON file. Then we have 2 files order.json and app.js
my server:
ubuntu 22.04
node v19.2.0
npm 8.19.3
The script get data from the file order.js using readFile.
app.js
var myHeaders = new Headers();
myHeaders.append("api-key", "123");
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Cookie", "session_id=123");
// get order.json file
var fs = require('fs')
fs.readFile('order.json', 'utf8', (err, data) => {
if (err) throw err
let orders = JSON.parse(data)
let order_line = orders.map(o => ([0, 0, {
product_id: +o.product_id,
product_uom_qty: +o.product_uom_qty,
price_unit: +o.price_unit
}]));
let body = {
partner_id: 150,
user_id: 6,
workflow_id: 1,
order_line
}
let raw = JSON.stringify(body);
console.log(raw);
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
}
fetch("https://mysite/api/sale.order/create?api_key=123", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error))
})
the file is located on the path ./ and contain the common order sales from your store.
order.json
[
{
"sku": "123",
"product_id": "6",
"price_unit": "9.7",
"product_uom_qty": "1.0000"
},
{
"sku": "456",
"product_id": "7",
"price_unit": "9.8",
"product_uom_qty": "1.0000"
}
]
Don't create JSON yourself, but use an existing well working serialization method (like the builtin JSON.stringify)
let orders = [
{
sku: 123,
product_id: 6,
price_unit: 9.7,
product_uom_qty: 1.0,
},
{
sku: 456,
product_id: 7,
price_unit: 9.8,
product_uom_qty: 1.0,
},
];
let order_line = orders.map(o => ([0,0, {
product_id: o.product_id,
product_uom_qty: o.product_uom_qty,
price_unit: o.price_unit
}]));
let body = {
partner_id: 150,
user_id: 6,
workflow_id: 1,
order_line
}
let raw = JSON.stringify(body);
console.log(raw);
Mind that I initialized orders from an array instead of reading it from the disk, but that doesn't really matter, assuming that orders.json contains valid JSON data. But I noticed, the datatypes in your orders.json differs from the datatypes in the data posted through postman. Ie for instance price_unit is a string in your JSON, but a number in your posted data. You will need to fix that. I fixed this in the orders array in my snippet.
If you can't influence the structure of your json, you can also convert between string and number while creating your object like this (notice the + in front of the property access, which converts the string from your order object into a number)
let order_line = orders.map(o => ([0,0, {
product_id: +o.product_id,
product_uom_qty: +o.product_uom_qty,
price_unit: +o.price_unit
}]));
I also used Array.map instead of the for loop ...
This will create a valid JSON string that can be correctly parsed at the server.
This SO answer correctly explains that since the require Node/JS library is not supported by Google Apps Script, the following code changes must be made to get Stripe to work properly in a GAS project:
from
const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
(async () => {
const product = await stripe.products.create({
name: 'My SaaS Platform',
type: 'service',
});
})();
to
function myFunction() {
var url = "https://api.stripe.com/v1/products";
var params = {
method: "post",
headers: {Authorization: "Basic " + Utilities.base64Encode("sk_test_4eC39HqLyjWDarjtT1zdp7dc:")},
payload: {name: "My SaaS Platform", type: "service"}
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res.getContentText())
}
Now, I want to convert the following code into the Google Apps Script friendly version.
from https://stripe.com/docs/payments/checkout/accept-a-payment#create-checkout-session
const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card', 'ideal'],
line_items: [{
price_data: {
currency: 'eur',
product_data: {
name: 'T-shirt',
},
unit_amount: 2000,
},
quantity: 1,
}],
mode: 'payment',
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cancel',
});
So, I'm trying the following.
to
function myFunction() {
var url = "https://api.stripe.com/v1/checkout/sessions";
var params = {
method: "post",
headers: {
Authorization:
"Basic " + Utilities.base64Encode("sk_test_4eC39HqLyjWDarjtT1zdp7dc:"),
},
payload: {
payment_method_types: ["card", "ideal"],
line_items: [
{
price_data: {
currency: "eur",
product_data: {
name: "T-shirt",
},
unit_amount: 2000,
},
quantity: 1,
},
],
mode: "payment",
success_url:
"https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
cancel_url: "https://example.com/cancel",
},
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res.getContentText());
}
However, instead of getting the expected response object returned, I get the following error:
Exception: Request failed for https://api.stripe.com returned code 400. Truncated server response:
Log.error
{
error: {
message: "Invalid array",
param: "line_items",
type: "invalid_request_error",
},
}
What am I doing wrong? And how can I generalize the first example? What is the specific documentation I need that I'm not seeing?
Edit:
After stringifying the payload per the suggestion from the comments, now I get the following error:
Exception: Request failed for https://api.stripe.com returned code 400. Truncated server response:
Log.error
{
"error": {
"code": "parameter_unknown",
"doc_url": "https://stripe.com/docs/error-codes/parameter-unknown",
"message": "Received unknown parameter: {\"payment_method_types\":. Did you mean payment_method_types?",
"param": "{\"payment_method_types\":",
"type": "invalid_request_error"
}
}
I modified the script mentioned in the comments and now have a one that works for this purpose.
// [ BEGIN ] utilities library
/**
* Returns encoded form suitable for HTTP POST: x-www-urlformencoded
* #see code: https://gist.github.com/lastguest/1fd181a9c9db0550a847
* #see context: https://stackoverflow.com/a/63024022
* #param { Object } element a data object needing to be encoded
* #param { String } key not necessary for initial call, but used for recursive call
* #param { Object } result recursively populated return object
* #returns { Object } a stringified object
* #example
* `{
"cancel_url": "https://example.com/cancel",
"line_items[0][price_data][currency]": "eur",
"line_items[0][price_data][product_data][name]": "T-shirt",
"line_items[0][price_data][unit_amount]": "2000",
"line_items[0][quantity]": "1",
"mode": "payment",
"payment_method_types[0]": "card",
"payment_method_types[1]": "ideal",
"success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}"
}`
*/
const json2urlEncoded = ( element, key, result={}, ) => {
const OBJECT = 'object';
const typeOfElement = typeof( element );
if( typeOfElement === OBJECT ){
for ( const index in element ) {
const elementParam = element[ index ];
const keyParam = key ? `${ key }[${ index }]` : index;
json2urlEncoded( elementParam, keyParam, result, );
}
} else {
result[ key ] = element.toString();
}
return result;
}
// // test
// const json2urlEncoded_test = () => {
// const data = {
// time : +new Date,
// users : [
// { id: 100 , name: 'Alice' , } ,
// { id: 200 , name: 'Bob' , } ,
// { id: 300 , name: 'Charlie' , } ,
// ],
// };
// const test = json2urlEncoded( data, );
// // Logger.log( 'test\n%s', test, );
// return test;
// // Output:
// // users[0][id]=100&users[0][name]=Stefano&users[1][id]=200&users[1][name]=Lucia&users[2][id]=300&users[2][name]=Franco&time=1405014230183
// }
// // quokka
// const test = json2urlEncoded_test();
// const typeOfTest = typeof test;
// typeOfTest
// test
// [ END ] utilities library
From this question and this sample script, I thought that in this case, the values are required to be sent as the form data. So how about the following modification?
Modified script:
function myFunction() {
var url = "https://httpbin.org/anything";
var params = {
method: "post",
headers: {Authorization: "Basic " + Utilities.base64Encode("sk_test_4eC39HqLyjWDarjtT1zdp7dc:")},
payload: {
"cancel_url": "https://example.com/cancel",
"line_items[0][price_data][currency]": "eur",
"line_items[0][price_data][product_data][name]": "T-shirt",
"line_items[0][price_data][unit_amount]": "2000",
"line_items[0][quantity]": "1",
"mode": "payment",
"payment_method_types[0]": "card",
"payment_method_types[1]": "ideal",
"success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}"
}
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res.getContentText()); // or console.log(res.getContentText())
}
I think that point might be payment_method_types: ["card", "ideal"] is required to be sent as "payment_method_types[0]": "card" and "payment_method_types[1]": "ideal".
References:
Create a Session of official document
How to integrate Stripe payments with Google Apps Script
I'm currently building a Twitter-like page as coding practice. I'm able to fetch the JSON data and load it to the page, but when it comes to posting a new tweet, the console throws a few error messages, like POST http://localhost:8080/api/feed/post 404 (Not Found), and Backend API: SyntaxError: Unexpected token < in JSON at position 0.
I googled by myself and learned that a "404 error" occurs when the requested page doesn't exist, and one of the common errors when Backend API: SyntaxError: Unexpected token < in JSON at position 0 is displayed is that the "JSON" is actually HTML ect.
But I'm not sure if those alone will be helpful enough to fix my problem, so I'm posting a new one here.
One of the things that I find odd is why the JSON file is not properly processed while it does work when I just load it.
Any idea how this is happening?
Here is some parts of my code.
[feed.json]
[
{
"avatar": "/avatar/avatar-ivomagi.jpg",
"username": "Ivo Mägi",
"handle": "#ivomagi",
"timestamp": 1543319880000,
"content": "This is your 1500ms latency in real life situations -",
"media": {
"type": "video",
"url": "https://video.twimg.com/tweet_video/DtCeK1zXcAAgQQV.mp4"
},
"actions": {
"replies": 35,
"rekweets": 2700,
"likes": 5700
}
},
{
"avatar": "/avatar/avatar-mralancooper.jpg",
"username": "Alan Cooper",
"handle": "#MrAlanCooper",
"timestamp": 1542542280000,
"content": "We have thousands of incredibly shitty programs and apps that were shipped on time. Deadlines don’t make things better.",
"actions": {
"replies": 17,
"rekweets": 393,
"likes": 1100
}
},
.........
]
[App.vue]
<template>
<form class = "userContainer">
<div class = "user-avatar">
<img src="avatar/avatar-loggedin.jpg">
</div>
<textarea rows = "10" cols = "80" v-model="kweetInput"> </textarea>
<p><button class = "kwitterBtn" type = "submit" #click.prevent="newKweet()">Kwitter</button></p>
</form>
<button class = "JsonEx" #click="loadPage()" v-if="!pageLoaded">Show previous kweets</button>
<button #click="hideKweets()" v-else>Hide previous kweets</button>
<br><br>
<div v-if="pageLoaded">
<show-previous-kweets v-bind:allJsonData="allJsonData"></show-previous-kweets>
</div>
</template>
<script>
import ShowPreviousKweets from './components/ShowPreviousKweets';
export default {
components: {
'show-previous-kweets': ShowPreviousKweets
},
data(){
return {
allJsonData: [],
pageLoaded: false,
kweetInput: '',
userJSON: {
avatar: 'avatar/avatar-loggedin.jpg',
username: 'Johan Westling',
handle: '#johanwestling',
timestamp: '',
content: this.kweetInput,
media: {
type: '',
url: ''
},
actions: {
replies: 0,
rekweets: 0,
likes: 0
}
}
}
},
created() {
this.loadPage();
},
methods: {
loadPage(){
var self = this;
fetch('/feed.json').then(function(response){ // "/feed.json" // /api/feed/get
return response.json();
}).then(function(response){
var tempArray = [];
for(var i = 0; i < response.length; i++){
tempArray.push(response[i]);
}
self.allJsonData = tempArray;
self.setAllJsonData(self.allJsonData);
});
self.pageLoaded = true;
},
setAllJsonData(json){
this.allJsonData = json;
},
hideKweets(){
this.pageLoaded = false;
},
newKweet(){
var self = this;
alert(self.kweetInput);
fetch('/api/feed/post', {
method: 'POST',
body: JSON.stringify(self.userJSON),
headers: {
'Content-Type': 'application/json'
}
})
.then(function(backendResponse){
console.log('backendResponse: ' + backendResponse);
return backendResponse.json();
}) .then((backendData) => {
console.log('Backend API:', backendData); })
.catch((backendResponse) => {
console.warn('Backend API:', backendResponse);
});
self.kweetInput = '';
console.log('The end of newKweet() method');
}
}
}
</script>
[api.js]
const fs = require('fs');
const path = require('path');
const express = require('express');
const api = express();
const apiUrl = process.env.URL || 'http://localhost';
//const apiPort = parseInt((process.env.PORT || 3001));
const apiPort = 8080;
api.use(express.json());
api.get('/api/feed/get' , (req, res) => {
//let feedFile = path.resolve(__dirname, '../employees.json'); // just an experiment with a simpler file
let feedFile = path.resolve(__dirname, '../feed.json');
res.type('json');
res.sendFile(feedFile);
});
api.post('/api/feed/post' , (req, res) => {
//let feedFile = path.resolve(__dirname, '../employees.json'); // just an experiment with a simpler file
let feedFile = path.resolve(__dirname, '../feed.json');
let feedContent = JSON.parse(fs.readFileSync(feedFile));
let feedPosted = req.body;
let feedJson = '';
console.log('/api/feed/post:', feedPosted);
feedContent.push(feedPosted);
feedJson = JSON.stringify(feedContent);
fs.writeFileSync(feedFile, feedJson);
res.type('json');
res.sendFile(feedFile);
});
api.listen(apiPort, () => {
console.log(`API server running at ${apiUrl}:${apiPort}`);
});
I'm running the program with a localhost port number 8080, so I changed the value of const apiPort to 8080, but it had no effect.
Another thing I found out is that when I replace /feed.json of the loadPage() method in App.vue with /api/feed/get, it stops working as well, spitting the same error message, Backend API: SyntaxError: Unexpected token < in JSON at position 0.
I guess it's something wrong with api.js?
[UPDATE]
[All the folders and files within the working directory]
slutuppgift/
|-- public/ Static files
|-- |-- index.html HTML-code
|-- |-- feed.json the API JSON-data
|-- src/
|-- |-- main.js JavaScript-code to initialize Vue & app.vue
|-- |-- app.vue Vue-code for the application
|-- |-- components/ Vue-code for components
|-- |-- views/ Vue-code for pages/templates (Vue-router).
|-- |-- router.js JavaScript-code for Vue-router (URL-structure)
|-- |-- api.js JavaScript-kod for Express.js (the API)
[main.js]
import Vue from 'vue';
import VueRouter from './router';
import App from './App.vue';
Vue.config.productionTip = false
new Vue({
router: VueRouter,
render: h => h(App)
}).$mount('#app')
I am receiving below response from a service
[ { recipient_id: 'default',
text: 'Hello, how can I help?' } ]
I need to retrieve the text portion of the response. I can do that with python like below
json_response = response.json()
reply = json_response[0]['text']
But I need to retrieve the text portion in NodeJS now for a different project. So I have tried below code but it outputs undefined
var obj = JSON.parse(response)
console.log(obj[0]['text'])
Can anyone please suggest?
EDIT:
The POST request is made like
request.post(
'http://path-to-service',
{ json: { 'query': msg} },
function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body)
var obj = JSON.parse(body)
console.log(obj[0]['text'])
}
The problem is the service returns response as an array of python dictionary. So response[0] is essentially a python dictionary
{ recipient_id: 'default',
text: 'Hello, how can I help?' }
So the question is, how do I retrieve the value of the key text from this dictionary.
I think your response is already coming as JSON object so don't need to parse again.
var obj = [ { recipient_id: 'default',
text: 'Hello, how can I help?' } ];
console.log(obj[0].text);
try code
var body = {'query': 'msg', 'name': 'my name is nodejs'}
var obj = JSON.parse(body);
console.log(obj.query);
console.log(obj.name);
printf
msg
my name is nodejs
I am trying to covert json data into Xlsx file and save it in a folder.
I have been trying to use icg-json-to-xlsx module but till now I have been unable to use it.
My code looks like this:
jsonXlsx = require('icg-json-to-xlsx');
filename = path.join('./files', "output.xlsx");
outputFile = jsonXlsx(filename, result) //result contains json data
console.log(outputFile);
but I got this error
outputFile = jsonXlsx(filename, result)
^
TypeError: Property 'jsonXlsx' of object # is not a function
Getting data from mongodb:
in routes:
router.get('/', function(req, res, next) {
fileController.getAll(function(err, result){
if(err){
res.send(500,err);
}
// res.json(result);
var data = result;
in controller:
FileController.prototype.getAll = function(callback){
File.find( {}, {_id: false, id: true, name: true, status: true}, function(err, file){
if(err) {
return callback(err);
} else {
if (!file) {
return callback('file not found');
}
}
callback(null, file);
}
)};
Try this
outputFile = jsonXlsx.writeFile(filename, result);
jsonXlsx is object, which contains methods like writeFile, writeBuffer, so you can't call jsonXlsx as function... or you need add reference to function like this
jsonXlsxWriteFile = require('icg-json-to-xlsx').writeFile;
outputFile = jsonXlsxWriteFile(filename, result)
Example
var jsonXlsx = require('icg-json-to-xlsx');
var path = require('path');
var filename = path.join('./files', "output.xlsx");
var result = [
{ id: '1', name: 'test', status: '123' },
{ id: '2', name: 'david', status: '323'},
{ id: '3', name: 'ram', status: '2323' }
];
var outputFile = jsonXlsx.writeFile(filename, JSON.stringify(result));
console.log(outputFile);
Update:
File
.find({ })
.select({
_id: false, id: true, name: true, status: true
})
.lean()
.exec(function(err, file) {
//
});
In your case, query returns MongooseDocuments, but jsonXlsx needs plain JavaScript objects, so that's why you should use lean()
You can try Alasql JavaScript SQL library. It includes a module to work with JSON and XLSX files (with support of js-xlsx.js library).
Install these two libraries into your project.
npm install alasql
npm install xlsx
Then call alasql function:
var alasql = require(alasql);
alasql('SELECT * INTO XLSX("mydata.xlsx",{headers:true}) \
FROM JSON("mydata.json")');
var cities = [{City:'London',Population:2500000},{City:"Paris",Population:2000000}];
alasql("SELECT * INTO XLSX("mydata.xlsx",{headers:true}) FROM ?",[cities]);
See more examples in this demo file.
There are a lot of modules that can do it. But if you want to control the formatting of xlsx file, then I suggest you use this below code. Rows contain data in the form of JSON array.
var excel = require('node-excel-export');
var styles = {
headerDark: {
fill: {
fgColor: {
rgb: 'FF000000'
}
},
font: {
color: {
rgb: 'FFFFFFFF'
},
sz: 14,
bold: true,
underline: true
}
},
cellPink: {
fill: {
fgColor: {
rgb: 'FFFFCCFF'
}
}
},
cellGreen: {
fill: {
fgColor: {
rgb: 'FF00FF00'
}
}
}
};
var specification = {
"Col1": {
"displayName": 'Col1Name',
"headerStyle": styles.headerDark,
"width": 250
},
"Col2": {
"displayName": 'Col2Name',
"headerStyle": styles.headerDark,
"width": 215
},
"Col3": {
displayName: 'Col3Name',
headerStyle: styles.headerDark,
width: 150
}
}
var report = excel.buildExport(
[{
name: 'Report.xlsx',
specification: specification,
data: rows
}]
);