Sending complex JSON with fetch, save, and delete on a model or collection - json

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();

Related

Monaco editor default json uri schema

I'm using monaco editor to edit JSON and I would like to set a custom diagnostic option.
I'm trying that https://microsoft.github.io/monaco-editor/playground.html#extending-language-services-configure-json-defaults
// Configures two JSON schemas, with references.
var jsonCode = [
'{',
' "p1": "v3",',
' "p2": false',
"}"
].join('\n');
var modelUri = monaco.Uri.parse("a://b/foo.json"); // a made up unique URI for our model
var model = monaco.editor.createModel(jsonCode, "json", modelUri);
// configure the JSON language support with schemas and schema associations
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
validate: true,
schemas: [{
uri: "http://myserver/foo-schema.json", // id of the first schema
fileMatch: [modelUri.toString()], // associate with our model
schema: {
type: "object",
properties: {
p1: {
enum: ["v1", "v2"]
},
p2: {
$ref: "http://myserver/bar-schema.json" // reference the second schema
}
}
}
}, {
uri: "http://myserver/bar-schema.json", // id of the second schema
schema: {
type: "object",
properties: {
q1: {
enum: ["x1", "x2"]
}
}
}
}]
});
monaco.editor.create(document.getElementById("container"), {
model: model
});
Where does uri: "http://myserver/foo-schema.json" come from ? I just want to use default JSON schema. Not my own.
Setting uri like this works :
uri: "http://localhost:4200/assets/monaco-editor/min/vs/language/json/jsonMode.js",
But is there a clean way to set this value ? Maybe uri value for JSON is available somewhere ? I searched through monaco.languages.json.jsonDefaults but I did not find anything.
"http://myserver/foo-schema.json" is an arbitrary value-- you can make it anything you want. It only matters if you are also using enableSchemaRequest-- in which case it should point to the location that you want the schema to be fetched from-- but you're not doing that, so that doesn't matter. In fact, everything related to this URI is irrelevant to what you are trying to do, if I'm understanding your intent correctly.
When you say "I just want to use default JSON Schema, Not my own", I think what you mean to say is that you just want to ensure that it is valid JSON, right? Because, there is no such thing as "default JSON Schema"-- by definition, it is defined by you-- but there is such a thing as a formal definition of what JSON is (JSON Schema, on the other hand, assumes that you are already starting with valid JSON, and allows you to then define a schema that your (valid) JSON must conform to).
Assuming you just want to ensure it is valid JSON (but you don't care that the json conform to some custom schema), setting the language to 'json' is all you need to do and your code can be as simple as:
var myBadJSONText = '{this is not : "JSON"}'
monaco.editor.create(document.getElementById('container'), {
language: 'json',
value: myBadJSONText
});
which running in the Monaco playground gives you:

TypeScript / Angular 2 creating a dynamic object deserializer

So I am coming from a background of C# where I can do things in a dynamic and reflective way and I am trying to apply that to a TypeScript class I am working on writing.
Some background, I am converting an application to a web app and the backend developer doesn't want to change the backend at all to accommodate Json very well. So he is going to be sending me back Json that looks like so:
{
Columns: [
{
"ColumnName": "ClientPK",
"Label": "Client",
"DataType": "int",
"Length": 0,
"AllowNull": true,
"Format": "",
"IsReadOnly": true,
"IsDateOnly": null
}
],
Rows:[
0
]
}
I am looking to write an Angular class that extends Response that will have a special method called JsonMinimal which will understand this data and return an object for me.
import { Response } from "#angular/http";
export class ServerSource
{
SourceName: string;
MoreItems: boolean;
Error: string;
ExtendedProperties: ExtendedProperty[];
Columns: Column[];
}
export class ServerSourceResponse extends Response
{
JsonMinimal() : any
{
return null; //Something that will be a blank any type that when returned I can perform `object as FinalObject` syntax
}
}
I know StackOverflow isn't for asking for complete solutions to problems so I am only asking what is one example taking this example data and creating a dynamic response that TypeScript isn't going to yell at me for. I don't know what to do here, this developer has thousands of server-side methods and all of them return strings, in the form of a JSON or XML output. I am basically looking for a way to take his column data and combine it with the proper row data and then have a bigger object that holds a bunch of these combined object.
A usage case here after that data has been mapped to a basic object would be something like this.
Example:
var data = result.JsonMinimal() as LoginResponse; <-- Which will map to this object correctly if all the data is there in a base object.
var pk = data.ClientPK.Value;
I'm not exactly sure I understand, but you may want to try a simple approach first. Angular's http get method returns an observable that can automatically map the response to an object or an array of objects. It is also powerful enough to perform some custom mapping/transformation. You may want to look at that first.
Here is an example:
getProducts(): Observable<IProduct[]> {
return this._http.get(this._productUrl)
.map((response: Response) => <IProduct[]> response.json())
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError);
}
Here I'm mapping a json response to an array of Product objects I've defined with an IProduct interface. Since this is just a "lambda" type function, I could add any amount of code here to transform data.

parse urls in Backbone.js

I am new to Backbones.js, and I was trying to get my JSON urls and parse them correctly.
This is my code:
window.Post = Backbone.Model.extend({
initialize: function(options) {
this.id = options.id;
},
url: function() {
return 'api/get_post/?post_type=movies&id=' + this.id;
},
parse : function(response) {
return response.posts;
},
});
window.Posts = Backbone.Collection.extend({
model: Post,
defaults: {
model: Post,
},
url: "api/get_recent_posts/?post_type=movies",
parse : function(response) {
return response.posts;
},
});
It seems that parsing for both overrides each other or something. when I remove the parse option from the Post class, I get a full response from the collection, but not from the model.
Are there any clear examples on how to set parsing for different son hierarchies? my JSON result have a status ok before it dives into the actual data.
I've never used bones.js but maybe these examples will help.
I think what you want to do is get rid of the parse() function in your collection. This assumes that since it is a Post collection, your data will come in as an array of Post JSON objects [{id:'1', 'sub':{data}},{id:'2', 'sub':{data}},{id:'3', 'sub':{data}}] or something like that.
If your Post model has sub-models or collections, your model parse() will then take the sub-object property name and do something with it.
// In Post Model definition
parse:function(response) {
if (response.sub) {
// create some model or collection etc.
}
}
You might have to pass an option parse:true when you do your collection fetch.
I posted something along these lines which might help you see how sub-models can be instantiated on fetch calls.
Backbone.js: Load multiple collections with one request
Cast/initialize submodels of a Backbone Model
I hope this helps.

Sencha Touch - Accessing Associated-Model Store JSON via Nested Looping

I've been lurking on Stack Overflow for quite some time now, and have found quite a number of very helpful answers. Many thanks to the community! I hope to be able to contribute my own helpful answers before too long.
In the meantime, I have another issue I can't figure out. I am using Sencha Touch to create a Web-based phone app and I'm having trouble using a nested loop to iterate through some JSON. I can grab the first level of data, but not the items nested within that first level. There is a somewhat related ExtJS thread, but I decided to create my own since ExtJS and Touch diverge in subtle yet important ways. Anyway, here is some code to show where I am:
JSON (truncated - the JSON is PHP/MYSQL-generated, and there are currently actually three sub levels with "title", all of which I can access. It's the sub level "items" through which I can't iterate):
{
"lists": [
{
"title": "Groceries",
"id": "1",
"items": [
{
"text": "contact solution - COUPON",
"listId": "1",
"id": "4",
"leaf": "true"
},
{
"text": "Falafel (bulk)",
"listId": "1",
"id": "161",
"leaf": "true"
},
{
"text": "brita filters",
"listId": "1",
"id": "166",
"leaf": "true"
}
]
}
]
}
Store:
var storeItms = new Ext.data.Store({
model: 'Lists',
proxy: {
type: 'ajax',
method: 'post',
url : LIST_SRC,
extraParams: {action: 'gtLstItms'},
reader: {
type: 'json',
root: 'lists'
}
}
});
Working Loop:
storeItms.on('load', function(){
var lstArr = new Array();
storeItms.each(function(i) {
var title = i.data.title;
lstArr.push(i.data.title);
});
console.log(lstArr);
});
Non-working Nested Loop:
storeItms.on('load', function(){
var lstArr = new Array();
storeItms.each(function(i) {
var title = i.data.title;
var id = i.data.id;
title.items.each(function(l) {
lstArr.push(l.data.text);
});
});
console.log(lstArr);
});
The non-working nested loop gives me the error "Cannot call method 'each' of undefined", in reference to 'title.items.each...'
I suspect this is because I've not set title to be a key to set up a key:value pair, so it just sees a list of strings...but I'm kind of at a loss.
I should mention that the store is populated via two Models that have been associated with one another. I know that the Store can access everything because I am able to do nested iterating via an XTemplate.
Any help will be much appreciated and hopefully returned to the community in kind before too long!'
-Eric
Eric, why the loop?
If your models are associated in the same way that the JSON is nested, then you should just be able to set autoLoad:true on the store, sit back and enjoy.
Anyway, on the assumption that you are needing these arrays for some other unrelated reason, the problem is that you are trying .each on
i.data.title.items
Surely you should be iterating through
i.data.items
Also, if the object is a model, you can use .get() instead of the data object:
var title = i.get('title);
Using new sencha touch 2 framework, you can create associations within the models exactly the same way how your json is returned.
Check Sencha Touch 2 Model Document which tells you the various config options on Model.
You may refer to this example of ST2 Nested List .
Hope this helps.
"title" is not a enumerable object, its a string. To iterate a string you'll need to split it to convert it into an array.
Also, instead of using Ext.each try a simple for (var x in obj) {} or for (var xc in obj.prop) {} If that works then the ext.each method should work as well but if ext cannot iterate the object it will just quietly fail.

Extjs store reader fully qualified json property names

Using Extjs 3+ and server side is sending back the following JSON:
{"com.klistret.cmdb.ci.pojo.QueryResponse": {"com.klistret.cmdb.ci.pojo.successful":true,"com.klistret.cmdb.ci.pojo.count":1,"com.klistret.cmdb.ci.pojo.elements":{"com.klistret.cmdb.ci.pojo.id":123,"com.klistret.cmdb.ci.pojo.name":"Mars","com.klistret.cmdb.ci.pojo.fromTimeStamp":"2010-07-08T16:38:00.478+02:00","com.klistret.cmdb.ci.pojo.createTimeStamp":"2010-07-08T16:38:00.478+02:00","com.klistret.cmdb.ci.pojo.updateTimeStamp":"2010-10-25T15:02:09.446+02:00","com.klistret.cmdb.ci.pojo.type":{"com.klistret.cmdb.ci.pojo.id":1,"com.klistret.cmdb.ci.pojo.name":"{http:\/\/www.klistret.com\/cmdb\/ci\/element\/logical\/collection}Environment","com.klistret.cmdb.ci.pojo.fromTimeStamp":"2009-08-05T11:20:12.471+02:00","com.klistret.cmdb.ci.pojo.createTimeStamp":"2009-08-05T11:20:12.471+02:00","com.klistret.cmdb.ci.pojo.updateTimeStamp":"2009-08-05T11:20:12.471+02:00"},"com.klistret.cmdb.ci.pojo.configuration":{"#www.w3.org.2001.XMLSchema-instance.type":"com.klistret.cmdb.ci.element.logical.collection:Environment","#Watermark":"past","com.klistret.cmdb.ci.commons.Name":"Mars"}}}}
The reader is setup up as follows:
var reader = new CMDB.JsonReader(
{
totalProperty : 'com.klistret.cmdb.ci.pojo.count',
successProperty : 'com.klistret.cmdb.ci.pojo.successful',
idProperty : 'com.klistret.cmdb.ci.pojo.id',
root : 'com.klistret.cmdb.ci.pojo.elements'
},
[
{name: 'Id', mapping: 'com.klistret.cmdb.ci.pojo.id'},
{name: 'Name', mapping: 'com.klistret.cmdb.ci.pojo.name'}
]
);
The store as:
var ds = new Ext.data.Store({
proxy : new Ext.data.ScriptTagProxy({
url : 'http://sadbmatrix2:55167/CMDB/resteasy/element'
}),
reader : reader
});
The reader extends the Ext.data.JsonReader as explained by http://erichauser.net/2007/11/07/more-wcf-json-and-extjs/ to remove the "com.klistret.cmdb.ci.pojo.QueryResponse" start node in the JSON returned from the server.
The extended reader never gets called. Assuming the problem is due to has fully qualified property names in the JSON object returned (ie. "com.klistret.cmdb.ci.pojo.name" rather than just "name").
Anybody use gotten around this?
We worked it out (well, mostly Matthew did) in the comments:
ScriptTagProxy needs the server to wrap the JSON data in a function call so that your local code can get access to it.
Instead of the server emitting something like:
{here:'is data}
it needs to return
somefunc("{here:'is data'}");
That way, your client-side implementaiton of somefunc() is called and can process the returned data.