I am marshaling objects in Grails to JSON using the JSON.registerObjectMarshaller() method, which is invoked in the BootStrap class.
My object graph has a number of nested objects e.g. User -> Address -> Phone and I have a marshaller for each object.
I have a scenario where I want to be able to either return a "shallow" or "deep" version of the top level object. In the case of a shallow request, in place of the address I want to return the field. In the case of the a deep version, the other object marshalers can do delegated to as usual.
I want to do a deep versus shallow based on the value of a parameter passed in the request, however I do not know how to access request parameters when in the registerObjectMarshaller() method from the BootStrap class.
Once I have a way to access these parameters I can tailor it as needed.
Any pointers would be greatly appreciated.
I once tried the object marshaller approach for XML and sadly it didn't work out.
Similar to you, I don't have one way to represent objects. I have a lot more than two, but I think Object Marshallers are a way to go only if you want to do something trivial. If you need more, just forget about them.
It may be much easier for you, to simply create a service or a class with static methods which will generate the JSON for you based on the values you pass.
You can use JsonGroovyBuilder to achieve that, and then just convert it to string and wrap it in a nice http header or whatever you need.
In my case it looks like this [mind you, this is for XML, so you have to use JsonGroovyBuilder, or other - whichever suits you - and you will probably not need to use the StringWriter as I do]:
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
def retData = someService.doSomething()
def xmlGen = new XmlResponseGenerator(xml, retData)
render(contentType: 'text/xml', encoding: "UTF-8", text: writer.toString())
Related
I have a Typescript app. I use the localstorage for development purpose to store my objects and I have the problem at the deserialization.
I have an object meeting of type MeetingModel:
export interface MeetingModel {
date: moment.Moment; // from the library momentjs
}
I store this object in the localStorage using JSON.stringify(meeting).
I suppose that stringify call moment.toJson(), that returns an iso string, hence the value stored is: {"date":"2016-12-26T15:03:54.586Z"}.
When I retrieve this object, I do:
const stored = window.localStorage.getItem("meeting");
const meeting: MeetingModel = JSON.parse(stored);
The problem is: meeting.date contains a string instead of a moment !
So, first I'm wondering why TypeScript let this happen ? Why can I assign a string value instead of a Moment and the compiler agree ?
Second, how can I restore my objects from plain JSON objects (aka strings) into Typescript types ?
I can create a factory of course, but when my object database will grow up it will be a pain in the *** to do all this work.
Maybe there is a solution for better storing in the local storage in the first place?
Thank you
1) TypeScript is optionally typed. That means there are ways around the strictness of the type system. The any type allows you to do dynamic typing. This can come in very handy if you know what you are doing, but of course you can also shoot yourself in the foot.
This code will compile:
var x: string = <any> 1;
What is happening here is that the number 1 is casted to any, which to TypeScript means it will just assume you as a developer know what it is and how you to use it. Since the any type is then assigned to a string TypeScript is absolutely fine with it, even though you are likely to get errors during run-time, just like when you make a mistake when coding JavaScript.
Of course this is by design. TypeScript types only exist during compile time. What kind of string you put in JSON.parse is unknowable to TypeScript, because the input string only exists during run-time and can be anything. Hence the any type. TypeScript does offer so-called type guards. Type guards are bits of code that are understood during compile-time as well as run-time, but that is beyond the scope of your question (Google it if you're interested).
2) Serializing and deserializing data is usually not as simple as calling JSON.stringify and JSON.parse. Most type information is lost to JSON and typically the way you want to store objects (in memory) during run-time is very different from the way you want to store them for transfer or storage (in memory, on disk, or any other medium). For instance, during run-time you might need lookup tables, user/session state, private fields, library specific properties, while in storage you might want version numbers, timestamps, metadata, different types of normalization, etc. You can JSON.stringify anything you want in JavaScript land, but that does necessarily mean it is a good idea. You might want to design how you actually store data. For example, an iso string looks pretty, but takes a lot of bytes. If you have just a few that does not matter, but when you are transferring millions a second you might want to consider another format.
My advise to you would be to define interfaces for the objects you want to save and like moment create a .toJson method on your model object, which will return the DTO (Data Transfer Object) that you can simply serialize with JSON.stringify. Then on the way back you cast the any output of JSON.parse to your DTO and then convert it back to your model with a factory function or constructor of your creation. That might seem like a lot of boilerplate, but in my experience it is totally worth it, because now you are in control of what gets stored and that gives you a lot of flexility to change your model without getting deserialization problems.
Good luck!
You could use the reviver feature of JSON.parse to convert the string back to a moment:
JSON.parse(input, (key, value) => {
if (key == "date") {
return parseStringAsMoment(value);
} else {
return value;
});
Check browser support for reviver, though, as it's not the same as basic JSON.parse
I've built a RESTful API using Spray.io.
It contains a number of endpoints, each of which returns JSON.
I use the Spray JSON marshaller to marshal my internal objects to JSON which are returned to the user. So I have something similar to...
respondWithMediaType(`application/json`) {
complete(MyResponse(username, password))
}
Where MyResponse is a case class...
case class MyResponse(username:String, password:String)
However, I want to pick the fields that are returned in the response. So in this case I want to remove the "password" field before it is returned.
Whats the best way to do this with Spray?
Thanks
Posting an answer to close question. Went with Yuvals suggestion above (he didn't add as answer)...
"Why not create PasswordLessResponse case class, instead of jumping hooks to deserialize MyResponse in different ways"
and just created the relevant case classes and marshallers, populated and returned where needed.
Thanks Yuval!
I have a situation where people consuming our API will need to do a partial update in my resource. I understand that the HTTP clearly specifies that this is a PATCH operation, even though people on our side are used to send a PUT request for this and that's how the legacy code is built.
For exemplification, imagine the simple following struct:
type Person struct {
Name string
Age int
Address string
}
On a POST request, I will provide a payload with all three values (Name, Age, Address) and validate them accordingly on my Golang backend. Simple.
On a PUT/PATCH request though, we know that, for instance, a name never changes. But say I would like to change the age, then I would simply send a JSON payload containing the new age:
PUT /person/1 {age:30}
Now to my real question:
What is the best practice to prevent name from being used/updated intentionally or unintentionally modified in case a consumer of our API send a JSON payload containing the name field?
Example:
PUT /person/1 {name:"New Name", age:35}
Possible solutions I thought of, but I don't actually like them, are:
On my validator method, I would either forcibly remove the unwanted field name OR respond with an error message saying that name is not allowed.
Create a DTO object/struct that would be pretty much an extension of my Person struct and then unmarshall my JSON payload into it, for instance
type PersonPut struct {
Age int
Address string
}
In my opinion this would add needless extra code and logic to abstract the problem, however I don't see any other elegant solution.
I honestly don't like those two approaches and I would like to know if you guys faced the same problem and how you solved it.
Thanks!
The first solution your brought is a good one. Some well known frameworks use to implement similar logic.
As an example, latests Rails versions come with a built in solution to prevent users to add extra data in the request, causing the server to update wrong fields in database. It is a kind of whitelist implemented by ActionController::Parameters class.
Let's suppose we have a controller class as bellow. For purpose of this explanation, it contains two update actions. But you won't see it in real code.
class PeopleController < ActionController::Base
# 1st version - Unsafe, it will rise an exception. Don't do it
def update
person = current_account.people.find(params[:id])
person.update!(params[:person])
redirect_to person
end
# 2nd version - Updates only permitted parameters
def update
person = current_account.people.find(params[:id])
person.update!(person_params) # call to person_params method
redirect_to person
end
private
def person_params
params.require(:person).permit(:name, :age)
end
end
Since the second version allows only permitted values, it'll block the user to change the payload and send a JSON containing a new password value:
{ name: "acme", age: 25, password: 'account-hacked' }
For more details, see Rails docs: Action Controller Overview and ActionController::Parameters
If the name cannot be written it is not valid to provide it for any update request. I would reject the request if the name was present. If I wanted to be more lenient, I might consider only rejecting the request if name is different from the current name.
I would not silently ignore a name which was different from the current name.
This can be solved by decoding the JSON body into a map[string]json.RawMessage first. The json.RawMessage type is useful for delaying the actual decoding. Afterwards, a whitelist can be applied on the map[string]json.RawMessage map, ignoring unwanted properties and only decoding the json.RawMessages of the properties we want to keep.
The process of decoding the whitelisted JSON body into a struct can be automated using the reflect package; an example implementation can be found here.
I am not proficient on Golang but I believe a good strategy would be converting your name field to be a read-only field.
For instance, in a strictly object-oriented language as Java/.NET/C++ you can just provide a Getter but not a Setter.
Maybe there is some accessor configuration for Golang just like Ruby has....
If it is read-only then it shouldn't bother with receiving a spare value, it should just ignore it. But again, not sure if Golang supports it.
I think the clean way is to put this logic inside the PATCH handler. There should be some logic that would update only the fields that you want. Is easier if you unpack into a map[string]string and only iterate over the fields that you want to update. Additionally you could decode the json into a map, delete all the fields that you don't want to be updated, re-encode in json and then decode into your struct.
I'm trying to parse a grails parameter map to a Json String, and then back to a parameter map. (For saving html form entries with constraint-violations)
Everything is fine as long as there is no hasMany relationship in the parameter-map.
I'm using
fc.parameter = params as JSON
to save the params as JSON String.
Later I'm trying to rebuild the parameter map and create a new Domain-Object with it:
new Foo(JSON.parse(fc.parameter))
Everything is fine using only 1:1 relationships (states).
[states:2, listSize:50, name:TestFilter]
But when I try to rebuild a params-map with multi-select values (states)
[states:[1,2], listSize:50, name:TestFilter]
I'm getting this IllegalStateException:
Failed to convert property value of type org.codehaus.groovy.grails.web.json.JSONArray to required type java.util.Set for property states; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [de.gotosec.approve.State] for property states[0]: no matching editors or conversion strategy found
I tried to use this, but without success:
JSON.use("deep") {
new Foo(JSON.parse(fc.parameter))
}
You can use JsonSlurper instead of the converters.JSON of grails, it maps JSON objects to Groovy Maps. I think this link also might help you.
Edit: Now, if the problem is binding the params map to your domain, you should try using bindData() method, like:
bindData(foo, params)
Note that this straightforward use is only if you're calling bindData inside a controller.
What seems to be happening in your case is that Grails is trying to bind a concrete type of List (ArrayList in the case of JsonSlurper and JSONArray in the case of converters.JSON) into a Set of properties (which is the default data structure for one-to-many associations). I would have to take a look at your code to confirm that. But, as you did substitute states: [1,2] for a method of your app, try another test to confirm this hypothesis. Change:
states:[1,2]
for
states:[1,2] as Set
If this is really the problem and not even bindData() works, take a look at this for a harder way to make it work using object marshalling and converters.JSON. I don't know if it's practical for you to use it in your project, but it sure works nicely ;)
I have a controller that access a WCF service which returns a Json object (collection). All rows are of same type, but at different calls the row stricture is different (the return object comes from a user-built sql query, executed with executeReader and serialized as Json
So I don't know the row structure upfront.
What I need is an easy way to pass this Json string to something which will generate a view of type list on the fly for it. Doesn't matter formatting, etc, just should be output easily as a table.
Does anyone knows how can I accomplish this?
Another option might be to have something that generate the view on the fly for a IEnumerable of anonymous objects (since using this I could convert the json to a list of anonymous)
EDIT
I found something that does pretty much what I need, except it display metadata about passed object.
It is preetyPrint.js, and I integrated it in my page as below:
In my controller I set the result json object to ViewBag.Result, and in the view I used this code:
<script src="#Url.Content("~/Scripts/prettyprint.js")" type="text/javascript"> </script>
<div id="resultGrid"></div>
<script>
var resultObject = #Html.Raw(ViewBag.Result);
var ppTable = prettyPrint(resultObject);
document.getElementById('resultGrid').appendChild(ppTable);
</script>
Does anyone knows such script that actually "dump" the data instead of metadata?
Thanks.
You should create a class to deserialize to if you know the properties of the row. Then use the JavaScriptSerializer class to deserialize to a list of your new class you created. Then you can take a look at the WebGrid class to output the HTML, or just manually iterate over the property metadata in your view.
Creating a custom class will provide you the ability to use metadata to control formatting or other display attributes of the output.
If you cannot create a custom class, you can always use Json.NET or the JavaScriptSerializer to deserialize to a list of dictionary objects or ExpandoObject / Dynamic's or something. Then you would have to manually write something to iterate the keys I think. The ModelMetadataProvider in MVC may be able to handle these allowing you to just iterate the properties in your view code.