I'm writing an integration test for an API in grails. This API under test takes a JSON request and returns a JSON response only. Lets say the request JSON is :
{ "param1":value1,"param2":value2}
In this request, value1 and value2 depends on some other variables. So how can i put them in request JSON
A code snippet :
void testMethod(){
def controller = new DummyController()
Long param1Value = getValue(10)
Long param2Value = getValue(20)
controller.request.content = '{"param1":<param1Value>,"param2":<param2Value>}'
controller.methodUnderTest()
def response = controller.response.json
}
In this how can i specify param1value and param2value for param1 and param2 parameters respectively. Please help!
You can use JsonBuilder as below.
void testMethod(){
def controller = new DummyController()
def reqJson = new groovy.json.JsonBuilder()
reqJson {
params1 getValue(10)
params2 getValue(20)
}
controller.request.content = reqJson.toString()
controller.methodUnderTest()
def response = controller.response.json
}
or use """ or slashy string for the json string as:
controller.request.content = """{"param1":"$param1Value","param2":"$param2Value"}"""
controller.request.content = /{"param1":"$param1Value","param2":"$param2Value"}/
Related
How to add JSON String in the POST request using kotlin and ktor?
Printing it out the Json string read from file or even constructed string with Kotlin in the client, the content looks like JSON.
Still, the server cannot recognize the string as JSON, and when I print it in the server, each double quota is back slashed.
The client obviously adds the back slashes, thus the request is not formatted as it should.
Client Kotlin - Ktor code:
import com.google.gson.*
import io.ktor.client.*
import io.ktor.http.*
...
val client = HttpClient(OkHttp) {
install(JsonFeature) {
serializer = GsonSerializer()
}
}
val fileContent = MyClass::class.java.getResource("myfile").readText()
println("fileContent string = $fileContent")
val out = client.post<String> {
url(url)
contentType(ContentType.Application.Json)
body = fileContent
}
the print out looks like this :
{ "name": "myname", "value": "myvalue" }
but the server (I use hookbin by the way to really print out the data without Jackson conversions) prints out:
{ \"name\": \"myname\", \"value\": \"myvalue\" }
The solution is to pass to the HTTP POST request a JSON object not a String object. They look the same when you print them, but of course they are not equally interpreted by the JVM. So, we have just to parse the string. I use the GSON library.
Add the JsonParser -> parseString method and use its object in the client:
import com.google.gson.JsonParser
val fileContent = MyClass::class.java.getResource("myfile").readText()
println("fileContent string = $fileContent")
var bodyAsJsonObject = JsonParser.parseString(fileContent).asJsonObject
println("bodyAsJsonObject = $bodyAsJsonObject")
val out = client.post<String> {
url(url)
contentType(ContentType.Application.Json)
body = bodyAsJsonObject
}
I'm updating groovy scripts from httpbuilder to httpbuilder-ng. These scripts interact with various webservices to get messages. I'm looking to parse the responses preferably using Jackson into objects. However, I can't seem to get the raw json response like I could in httpbuilder as httpbuilder-ng auto parses into a lazymap in all cases.
The old implementation using httpbuilder allowed you to use the body.text method to get the raw json string without it being parsed into a lazymap. This could then be used with ObjectMapper in Jackson to create my POJO's. However, httpbuilder-ng doesn't seem to support this.
I have already tried the method here for getting the raw json, but the body.text method does not seem to work in version 1.03 that I'm using http://coffeaelectronica.com/blog/2016/httpbuilder-ng-demo.html.
I have also tried to add my own custom encoders to override Groovy's default creation of JSON objects without any success. It is supposedly possible as detailed in the wiki https://http-builder-ng.github.io/http-builder-ng/asciidoc/html5/. If anyone has a code snippet of how to do this it would be appreciated!
Old httpbuilder code:
def http = new HTTPBuilder("http://${proxy}.domain.ie")
http.request(GET, TEXT) {
uri.path = "/blah/plugins/blah/queues"
headers.Accept = 'application/json'
headers.'Cookie' = "token=${token}"
response.success = { resp, json ->
assert resp.status < 300
LOGGER.info("GET queues request succeeded, HTTP " + resp.status)
ObjectMapper objectMapper = new ObjectMapper()
queues = objectMapper.readValue(json, Queue[].class)
}
response.failure = { resp ->
assert resp.status >= 300
LOGGER.info("GET queues request failed, HTTP " + resp.status)
return null
}
}
new http-builder-ng code:
def http = configure {
request.uri = "http://${proxy}.domain.ie"
request.headers["Accept"] = "application/json"
request.headers["Cookie"] = "token=${token}"
request.contentType = TEXT
}
return http.get {
request.uri.path = "/blah/plugins/blah/queues"
response.success { FromServer fs, Object body ->
return body.text // doesn't work
}
response.failure {
return null
}
}
Update
Found the solution. It was to add a custom parser and a closure using the FromServer.inputstream.text method.
def text = httpBuilder.get {
request.uri.path = '/blah/plugins/blah/queues'
response.parser('application/json') { ChainedHttpConfig cfg, FromServer fs ->
String text = fs.inputStream.text
}
}
The following is what GitHub returns from a REST GET method. How to parse it using JSON?
response.success = { resp, reader ->
result = reader.text
}
[{"login":"ghost","id":1,"avatar_url": ....},{"login":"github-enterprise","id":2,"avatar_url": ....}]
You can use awesome tool for working with json - json slurper:
def slurper = new JsonSlurper()
def result = slurper.parseText(result)
def firstLogin = result[0].login
def secondId = result[1].id
I have the following Groovy script (not a Grails app) that is returning a JSON-like, but it is not strictly valid JSON.
String baseURL = 'https://test.com'
File userFile = new File("./user.json")
def client = new HTTPBuilder(baseUrl)
client.headers['Content-Type'] = 'application/json'
client.request(GET, JSON) { req ->
requestContentType = JSON
headers.Accept = 'application/json'
response.success = { resp, json ->
userFile.append json.toString()
println JsonOutput.toJson(json.toString())
}
}
I am trying to create a JSON output file. I have tried using JsonOutput.prettyPrint and I looked at JsonBuilder, but that looks like I would have to build the JSON structure manually when Groovy should support the output. This is what I am getting back.
{AssetNumber=AssetNumber1, DeviceFriendlyName=FriendlyName1, PhoneNumber=17035551231, SerialNumber=SerialNumber1, Udid=Udid1, UserEmailAddress=user1#email.com, UserId=userId1, UserName=userName1}
As I said, this is JSON-like, but not strictly valid. I was expecting something like:
{"AssetNumber": "AssetNumber1", "DeviceFriendlyName": "FriendlyName1"....}
Any ideas?
It works perfectly fine (groovy v 2.3.6):
import groovy.json.*
def pretty = JsonOutput.prettyPrint(JsonOutput.toJson([1:2]))
assert pretty == """{
"1": 2
}"""
In this closure:
response.success = { resp, json ->
userFile.append json.toString()
println JsonOutput.toJson(json.toString())
}
You're getting an instance of Map under json variable. You do not need to turn it into a string. Instead use:
userFile.append JsonOutput.toJson(json)
println JsonOutput.toJson(json)
I'm converting a list of Foo objects to a JSON string. I need to parse the JSON string back into a list of Foos. However in the following example, parsing gives me a list of JSONObjects instead of Foos.
Example
List list = [new Foo("first"), new Foo("second")]
def jsonString = (list as JSON).toString()
List parsedList = JSON.parse(jsonString) as List
println parsedList[0].getClass() // org.codehaus.groovy.grails.web.json.JSONObject
How can I parse it into Foos instead?
Thanks in advance.
I had a look at the API docs for JSON and there doesn't appear to be any way to parse to a JSON string to a specific type of object.
So you'll just have to write the code yourself to convert each JSONObject to a Foo. Something like this should work:
import grails.converters.JSON
import org.codehaus.groovy.grails.web.json.*
class Foo {
def name
Foo(name) {
this.name = name
}
String toString() {
name
}
}
List list = [new Foo("first"), new Foo("second")]
def jsonString = (list as JSON).toString()
List parsedList = JSON.parse(jsonString)
// Convert from a list of JSONObject to a list of Foo
def foos = parsedList.collect {JSONObject jsonObject ->
new Foo(name: jsonObject.get("name"))
}
A more general solution would be to add a new static parse method such as the following to the JSON metaClass, that tries to parse the JSON string to a List of objects of a particular type:
import grails.converters.JSON
import org.codehaus.groovy.grails.web.json.*
class Foo {
def name
Foo(name) {
this.name = name
}
String toString() {
name
}
}
List list = [new Foo("first"), new Foo("second")]
def jsonString = (list as JSON).toString()
List parsedList = JSON.parse(jsonString)
// Define the new method
JSON.metaClass.static.parse = {String json, Class clazz ->
List jsonObjs = JSON.parse(json)
jsonObjs.collect {JSONObject jsonObj ->
// If the user hasn't provided a targetClass read the 'class' proprerty in the JSON to figure out which type to convert to
def targetClass = clazz ?: jsonObj.get('class') as Class
def targetInstance = targetClass.newInstance()
// Set the properties of targetInstance
jsonObj.entrySet().each {entry ->
if (entry.key != "class") {
targetInstance."$entry.key" = entry.value
}
}
targetInstance
}
}
// Try the new parse method
List<Foo> foos = JSON.parse(jsonString, Foo)
// Confirm it worked
assert foos.every {Foo foo -> foo.class == Foo && foo.name in ['first', 'second'] }
You can try out the code above in the groovy console. A few warnings
I have only performed very limited testing on the code above
There are two JSON classes in the latest Grails release, I'm assuming you're using the one that is not deprecated
If you are doing this in a Grails controller, and Foo IS indeed a domain object, don't forget that armed with your JSON map, you can also do:
List list = [new Foo("first"), new Foo("second")]
def jsonString = (list as JSON).toString()
List parsedList = JSON.parse(jsonString) as List
Foo foo = new Foo()
bindData(foo, parsedList[0]);
I've taken this code and extended it to work with nested structures. It relies on a 'class' attribute existing in the JSON. If there's a better way by now in Grails please let me know.
// The default JSON parser just creates generic JSON objects. If there are nested
// JSON arrays they are not converted to theirs types but are left as JSON objects
// This converts nested JSON structures into their types.
// IT RELIES ON A PROPERTY 'class' that must exist in the JSON tags
JSON.metaClass.static.parseJSONToTyped = {def jsonObjects ->
def typedObjects = jsonObjects.collect {JSONObject jsonObject ->
if(!jsonObject.has("class")){
throw new Exception("JSON parsing failed due to the 'class' attribute missing: " + jsonObject)
}
def targetClass = grailsApplication.classLoader.loadClass(jsonObject.get("class"))
def targetInstance = targetClass.newInstance()
// Set the properties of targetInstance
jsonObject.entrySet().each {entry ->
// If the entry is an array then recurse
if(entry.value instanceof org.codehaus.groovy.grails.web.json.JSONArray){
def typedSubObjects = parseJSONToTyped(entry.value)
targetInstance."$entry.key" = typedSubObjects
}
else if (entry.key != "class") {
targetInstance."$entry.key" = entry.value
}
}
targetInstance
}
return typedObjects
}
As of Grails 2.5, this is possible:
Period test = new Period()
test.periodText = 'test'
String j = test as JSON
def p = JSON.parse(j)
test = p.asType(Period)
println(test.periodText)
Output:
test
I am unsure of when it became an option.