I have some code that fetches data from an API and writes it to a file, the API returns tokenIdMetadata that has a bunch of information in it that I do not want so I made it into a new JSON object tokenMetadata and save that to a file as seen below.
const tokenIdMetadata = await Moralis.Web3API.token.getTokenIdMetadata(options);
const tokenMetadata = {};
tokenMetadata.token_id = tokenIdMetadata.token_id;
tokenMetadata.metadata = tokenIdMetadata.metadata;
fs.writeFileSync(folderName.concat('/', collectionSlug, '_', tokenID, '.json'), JSON.stringify(tokenMetadata, null, 4));
The problem is the code returns a string in the JSON file that is not formatted properly
"token_id": "4",
"metadata": "{\"name\":\"Arcade Land Mega #4\",\"image\":\"ipfs://QmaJyxmwWkH17P7cpzRDFqcQwh7HYZ53VS9pJN3rtWKVPh\",\"description\":\"Arcade Lands are digital properties in an interoperable metaverse that serves as your web3 home for all your NFTs. Land owners will get additional benefits within the Arcadeverse.\",\"attributes\":[{\"trait_type\":\"Size\",\"value\":\"Mega\"},{\"trait_type\":\"Area\",\"value\":\"Frozen\"},{\"trait_type\":\"Underground\",\"value\":\"Weird Rocks\"}]}"
This is how it should be formatted
"token_id" : "4",
"metadata" : {
name: 'Arcade Land Mega #4',
image: 'ipfs://QmXYYbVEFqVPRELzPN3fgCw9v3wr2iQqixbVaGS1JTH6mS',
description: 'Arcade Lands are digital properties in an interoperable metaverse that serves as your web3 home for all your NFTs. Land owners will get additional benefits within the Arcadeverse.',
attributes: [
{ trait_type: 'Size', value: 'Mega' },
{ trait_type: 'Area', value: 'Frozen' },
{ trait_type: 'Underground', value: 'Weird Rocks' }
]
}
I was wondering how I would go about fixing this.
I have checked example result of this API call in the documentation https://docs.moralis.io/moralis-dapp/web3-api/token#gettokenidmetadata . It looks like this is about failing to decode incoming JSON.
I think replacing tokenIdMetadata.metadata by JSON.parse(tokenIdMetadata.metadata) should fix that.
The final code should look like the following:
const tokenIdMetadata = await Moralis.Web3API.token.getTokenIdMetadata(options);
const tokenMetadata = {};
tokenMetadata.token_id = tokenIdMetadata.token_id;
tokenMetadata.metadata = JSON.parse(tokenIdMetadata.metadata);
fs.writeFileSync(folderName.concat('/', collectionSlug, '_', tokenID, '.json'), JSON.stringify(tokenMetadata, null, 4));
Related
The topic of this post is: my solution is too slow for a large query return.
I have a Web Api serving REST results like below from a call to localhost:9090/api/invetories?id=1:
[
{
"inventory_id": "1",
"film_id": "1",
"store_id": "1",
"last_update": "2/15/2006 5:09:17 AM"
},
{
"inventory_id": "2",
"film_id": "1",
"store_id": "1",
"last_update": "2/15/2006 5:09:17 AM"
}
]
Since my WebAPI did not provide a root key for my JSON response, I made a RESTSerializer like following.
export default DS.RESTSerializer.extend({
extract:function(store,primaryType,payload,id,requestType){
var typeName = primaryType.typeKey;
var data = {};
data[typeName] = payload; // creating root
payload = data;
return this._super(store,primaryType,payload,id,requestType)
}
});
When this gets run, I get the following error message: Assetion failed: You must include an 'id' for inventory in an object passed to 'push'
As you can see, these objects do not have the attribute id, so I found that the default behaviour of Ember RESTSerializer forces me to write my own.
Okay, so here's where I'm not sure my solution is right. inventory_id from my return is unique, therefore I choose to use that as an id, okay I'm thinking to my self, I'll just add it manually. The function looks like this now:
export default DS.RESTSerializer.extend({
extract:function(store,primaryType,payload,id,requestType){
var typeName = primaryType.typeKey;
for(var i=0;i<payload.length;i++){
payload[i].id = payload[i].inventoryId;
}
var data = {};
data[typeName] = payload; // creating root
payload = data;
return this._super(store,primaryType,payload,id,requestType)
}
});
By just manually duplicating an attribute, I feel like I'm cheating my way over this error message. In addition, I sometimes return a large payload array (over 150k rows). Looping O(n) just doesn't seem a right price to pay for just a simple mapping.
Is there some other way to set either my WebAPI or serializer up so I avoid the for loop in assigning the id that ember so desperately wants.
I think this should fix your problem:
export default DS.RESTSerializer.extend({
primaryKey: 'inventory_id'
});
With this parameter Ember Data will map inventory_id to it's id parameter.
I've got a node application that uses express, socket.io 1.0 and passport. When a user auths through passport-twitter I store their information in a session store using the below code;
var passportSocketIo = require("passport.socketio");
var MemoryStore = express.session.MemoryStore
,sessionStore = new MemoryStore();
io.set('authorization', passportSocketIo.authorize({
cookieParser: express.cookieParser,
key: 'express.sid',
secret: 'secret',
store: sessionStore
}));
I then use the following for my socket.io connection handler;
io.on("connection", function(client){
console.log(sessionStore.sessions[client.request.sessionID]);
});
This returns all the session data for the client with that ID in this format;
{
"cookie": {
"originalMaxAge": null,
"expires": null,
"httpOnly": true,
"path": "/"
},
"passport": {
"user": {
"id": "XXXXXXXXXX",
[...],
[...]
}
}
}
The issue is that if I tried to access "passport" from the structure, the result is always undefined. I tried the following (both with and without the . before "passport");
sessionStore.sessions[client.request.sessionID].[passport]
sessionStore.sessions[client.request.sessionID].["passport"]
sessionStore.sessions[client.request.sessionID].passport
sessionStore.sessions[client.request.sessionID]."passport"
Unfortunately these return as undefined. I'm really just trying to get the passport.user.id field value out of that structure so I can perform some DB lookup (e.g. user group, user privacy settings, etc) and so I can ensure I emit the correct DB data back to the client.
Any ideas?
After looking into it further, it appears that passing it through JSON.parse() was the correct method to use;
var jsobj = JSON.parse(sessionStore.sessions[client.request.sessionID]);
console.log(jsobj.passport.user.id);
or for a single line solution;
console.log(JSON.parse(sessionStore.sessions[client.request.sessionID]).passport.user.id);
I have an ember application which has two routes, user and subject. I'm (trying) to use the RESTAdapter to get data from an api, but the api does not return the data in the necessary format, ie instead of returning:
{
"user": {
id: "1",
name: "John Doe"
}
}
my api returns:
{
id: "1",
name: "John Doe"
}
I've been reading through a lot of related questions and have surmised that I need to use some kind of serializer within my adapter to customize it for my JSON. So far I have come up with this, based on answers and examples:
App.Adapter = DS.RESTAdapter.extend({
host: 'http://example.com',
serializer: DS.RESTSerializer.extend({
extractMany: function(loader, json, type, records) {
var root = this.rootForType(type);
var roots = this.pluralize(root);
formattedJson = {};
formattedJson[roots] = json.entries;
delete formattedJson.pagination;
this._super(loader, formattedJson, type, records);
}
})
});
But it doesn't seem to be having any effect. I'm also wondering if I need to write a different adapter for each model as I don't think the above can handle creating both users and a subjects roots. Can anyone point me in the right direction?
Per type serializers are super easy in ED as of 1.0, see documentation below, and this example should work for your user model.
https://github.com/emberjs/data/blob/master/TRANSITION.md
App.UserSerializer = DS.RESTSerializer.extend({
extractSingle: function(store, type, payload, id, requestType) {
payload = {user:payload};
return this._super(store, type, payload, id, requestType);
}
}
We have an internal API that was specifically built to be used with a new piece of software I'm building that runs on Backbone. The API has a single URL and takes JSON as input to determine what it needs to return. It essentially allows me to build custom queries with JSON that return exactly what I'm looking for.
Thing is this JSON can get pretty verbose and is often 3–4 levels deep, but sometimes may just be a few lines and just 1 level deep.
First question first: How do I send a string of JSON along with the ID when I do a fetch()? Do I have to set these parameters as the model or collection's defaults?
Here is an example of a really simple string to get a specific user's info
{
"which" : "object",
"object" : {
"type" : "customer",
"place" : "store",
"customerID" : "14"
}
}
As others have suggested it will likely be challenging to work with SOAP, but it shouldn't be impossible. Backbone models and collections communicate with the server through the sync operation; you should be able to customize that. I think something along these lines might get the ball rolling (for models):
Backbone.SoapyModel = Backbone.Model.extend({
sync: function(method, model, options) {
// force POST for all SOAP calls
method = 'create';
options = _.extend(options, {
// Setting the data property will send the model's state
// to the server. Add whatever complexity is needed here:
data: JSON.stringify({
"which" : "object",
"object" : model.toJSON()
}),
// Set the request's content type
contentType: 'application/json'
});
// Defer the rest to Backbone
return Backbone.sync.apply(this, [method, model, options]);
}
});
var SoapyModelImpl = Backbone.SoapyModel.extend({
url: '/test'
});
var soapTest = new SoapyModelImpl({
id: 42,
name: 'bob',
address: '12345 W Street Dr',
phone: '867 5304'
});
soapTest.fetch();
I am working on an iOS app using the MonoTouch framework. I am using Visual Studio 2010 Professional SP1 with the Xamarin.iOS (v1.3.250) extension. I have been able to open a valid FacebookConnect.FBSession by using the FacebookConnect.FBLoginView with no issues but when I try to make a Graph API request using FacebookConnect.FBRequest I recieve a non-standard JSON style string. When I run following request through the Graph API Explorer:
me?fields=albums.fields(id,name,cover_photo)
I receive the following response:
{
"id": "111111111111111111",
"albums": {
"data": [
{
"id": "111111111111111111",
"name": "Some Album (#1)",
"cover_photo": "111111111111111111",
"created_time": "000-00-00T00:00:00+0000"
},
{
"id": "111111111111111111",
"name": "Some Album (#2)",
"cover_photo": "111111111111111111",
"created_time": "000-00-00T00:00:00+0000"
},
],
"paging": {
"cursors": {
"after": "xxxxxxxx=",
"before": "xxxxxxxx="
}
}
}
}
Now all of this is just fine and is what I expect to receive but when I make the same Graph API request from my app like this:
public static void GetPhotoAlbums(string _userID)
{
// _userID = "me"
mFBRequest = new FBRequest(FBSession.ActiveSession, _userID + "?fields=albums.fields(id,name,cover_photo)");
FBRequestConnection fbRequestConnection = new FBRequestConnection();
fbRequestConnection.AddRequest(mFBRequest, OnPhotoAlbumsReceived);
fbRequestConnection.Start();
}
static void OnPhotoAlbumsReceived(FBRequestConnection _connection, NSObject _result, NSError _error)
{
if (_error == null)
{
Console.WriteLine("FacebookManager.OnPhotoAlbumsReceived() - JSON: " + _result.Description);
object o = JsonConvert.DeserializeObject(_result.Description);
// ...
}
}
I receive this JSON 'like' response:
{
albums = {
data = (
{
"cover_photo" = 111111111111111111;
"created_time" = "000-00-00T00:00:00+0000";
id = 111111111111111111;
name = "Some Album (#1)";
},
{
"cover_photo" = 111111111111111111;
"created_time" = "000-00-00T00:00:00+0000";
id = 111111111111111111;
name = "Some Album (#2)";
},
);
paging = {
cursors = {
after = "xxxxxxxx=";
before = "xxxxxxxx=";
};
};
};
"id": "111111111111111111";
}
I'm not really sure how/why I'm getting a response formatted in a non-standard way but needless to say, I get Newtonsoft.Json.JsonReaderException when attempting to deserialize the data because it does not follow the standard formatting rules (ie, = instead of : to separate key/value pairs, ; instead of , to separate elements of a container, some keys having quotes while others do not, etc...)
I'm pretty new to Facebook and JSON stuff in general and am really at a loss for what is happening to the response string I receive. Any help, feedback, ideas are greatly appreciated. Thanks.
* Solution *
After a bunch of digging around it seems to be that the Graph API response is indeed JSON but it gets converted to an FBGraphObject which holds a NSMutableArray as it the data makes its way through the MonoTouch->.NET bindings so when I pulled _result.Description (equivalent to _result.ToString() it returned me the string representation of that object which happens to look a lot like JSON but is not. After finding all this out (and a lot of runtime experimentation), I was finally able to extract the data into a usable state by doing this:
static void OnPhotoAlbumsReceived(FBRequestConnection _connection, NSObject _result, NSError _error)
{
if (_error == null)
{
NSArray fieldData = (NSArray) _result.ValueForKeyPath(new NSString("albums.data.name"))
string[] names = NSArray.StringArrayFromHandle(fieldData.Handle);
// ...
}
}
Although this works for me, I have a feeling that there is a better or more robust way to get the data I requested, so if any developers out there can offer any additional tips for improving this solution, I would love to hear them.
As stated in Facebook SDK documentation Graph API:
When a request returns a non-JSON response (such as a "true" literal),
that response will be wrapped into a dictionary using this const as
the key. This only applies for very few Graph API prior to v2.1.
So you can check first if result is an NSDictionary, otherwise you can deserialize the JSON data as usual.
Below some obj-c code you can translate into C#/MonoTouch (I don't know the framework, I hope it is helpful).
NSDictionary *dict;
if ([graphResult isKindOfClass:[NSDictionary class]]) {
dict = (NSDictionary *)graphResult;
} else {
NSError *JSONError;
dict = [NSJSONSerialization JSONObjectWithData:graphResult options:NSJSONReadingAllowFragments error:&JSONError];
if (JSONError) {
NSLog(#"Facebook: JSON parse error: %#", JSONError);
// Handle error
}
}