Hello I have created a RESTful web services which returns the responce in below format :
[
{"empId":1,"empName":"A"},
{"empId":2,"empName":"B"},
{"empId":3,"empName":"C"},
{"empId":4,"empName":"D"},
{"empId":5,"empName":"E"}
]
I have written the simple visualforce page to call the method named 'lookup' on button click action. My Apex class is given below.
public class REST {
public PageReference lookup()
{
string resp;
// Note this version of the API is only for the US
string endpoint ='http://localhost:8080/RESTfulExample/rest/json/metallica/get';
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
Http http = new Http();
req.setMethod('GET');
req.setEndpoint(endpoint);
try {
res = http.send(req);
} catch (Exception e) {
system.debug(LoggingLevel.Error, 'Error HTTP response code = '+res.getStatusCode()+'; calling '+endpoint );
return null;
}
resp = res.getBody();
JSONParser parser = JSON.createParser(resp);
// Parsing The JSON & set the list of values to the variables 'empid' & 'empname'
return null;
}
}
Can anyone help me how I can use JSON parser to parse the JSON and to store the values to the variables.
Thank You !!!
If you would like to use JSONParser here is an example from the Salesforce documentation on JSONParser(https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_json_jsonparser.htm):
public class JSONParserUtil {
#future(callout=true)
public static void parseJSONResponse() {
Http httpProtocol = new Http();
// Create HTTP request to send.
HttpRequest request = new HttpRequest();
// Set the endpoint URL.
String endpoint = 'https://docsample.herokuapp.com/jsonSample';
request.setEndPoint(endpoint);
// Set the HTTP verb to GET.
request.setMethod('GET');
// Send the HTTP request and get the response.
// The response is in JSON format.
HttpResponse response = httpProtocol.send(request);
System.debug(response.getBody());
/* The JSON response returned is the following:
String s = '{"invoiceList":[' +
'{"totalPrice":5.5,"statementDate":"2011-10-04T16:58:54.858Z","lineItems":[' +
'{"UnitPrice":1.0,"Quantity":5.0,"ProductName":"Pencil"},' +
'{"UnitPrice":0.5,"Quantity":1.0,"ProductName":"Eraser"}],' +
'"invoiceNumber":1},' +
'{"totalPrice":11.5,"statementDate":"2011-10-04T16:58:54.858Z","lineItems":[' +
'{"UnitPrice":6.0,"Quantity":1.0,"ProductName":"Notebook"},' +
'{"UnitPrice":2.5,"Quantity":1.0,"ProductName":"Ruler"},' +
'{"UnitPrice":1.5,"Quantity":2.0,"ProductName":"Pen"}],"invoiceNumber":2}' +
']}';
*/
// Parse JSON response to get all the totalPrice field values.
JSONParser parser = JSON.createParser(response.getBody());
Double grandTotal = 0.0;
while (parser.nextToken() != null) {
if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
(parser.getText() == 'totalPrice')) {
// Get the value.
parser.nextToken();
// Compute the grand total price for all invoices.
grandTotal += parser.getDoubleValue();
}
}
system.debug('Grand total=' + grandTotal);
}
}
Although from what you say in your question I think it would be simpler to do JSON Deserialization.
Here is an example on how to do it:
Wrapper Class
public class EmployeeWrapper {
public Integer empId {get;set;}
public String empName {get;set;}
}
JSON Deserialization
String jsonContent = '[{"empId": 1,"empName": "A"}, {"empId": 2,"empName": "B"}, {"empId": 3,"empName": "C"}, {"empId": 4,"empName": "D"}, {"empId": 5,"empName": "E"}]';
List<EmployeeWrapper> employeeWrapperList = (List<EmployeeWrapper>)JSON.deserialize(jsonContent, List<EmployeeWrapper>.class);
System.debug(employeeWrapperList);
//Do actions to WrapperList
Related
We want to get the UserName from the ServiceStack session, but we find that the backslashes in the UserName are not deserialized as expected. The UserName has this format 'domainname\username' and serialized in a jwt token this looks like:
{
"typ": "JWT",
"alg": "HS256"
}.{
"iss": "ssjwt",
"iat": 1635952233,
"exp": 1635955833,
"name": "Robin Doe",
"preferred_username": "domainname\\robindoe"
}.[Signature]
After calling:
var sessionFromJwt = JwtAuthProviderReader.CreateSessionFromJwt(req);
userName = sessionFromJwt.UserName;
The userName variable contains the value 'domainname\\robindoe' instead of 'domainname\robindoe'.
After digging in the ServiceStack code, we pin this down to the PopulateFromMap() method in https://github.com/ServiceStack/ServiceStack/blob/36df74a8b1ba7bf06f85262c1155e1425c082906/src/ServiceStack/Auth/UserAuth.cs#L388.
To demonstrate this problem we have written a small program to prove the point:
class Program
{
static void Main(string[] args)
{
var jwtPayload = JsonObject.Parse(#"{
""iss"": ""ssjwt"",
""iat"": 1635952233,
""exp"": 1635955833,
""name"": ""John Doe"",
""preferred_username"": ""domainname\\username""
}");
var session = new AuthUserSession();
// The PopulateFromMap implementation does not deserialize the json values according to json standards
UserAuthExtensions.PopulateFromMap(session, jwtPayload);
// Notice that the session.UserName still has the escape character 'domainname\\username' instead of the expected 'domainname\username'
Console.WriteLine(session.UserName);
// The PopulateFromMap should deserialize also the values, like in test Can_dynamically_parse_JSON_with_escape_chars()
Can_dynamically_parse_JSON_with_escape_chars();
}
private const string JsonCentroid = #"{""place"":{ ""woeid"":12345, ""placeTypeName"":""St\\a\/te"" } }";
// Source: https://github.com/ServiceStack/ServiceStack.Text/blob/master/tests/ServiceStack.Text.Tests/JsonObjectTests.cs
public static void Can_dynamically_parse_JSON_with_escape_chars()
{
var placeTypeName = JsonObject.Parse(JsonCentroid).Object("place").Get("placeTypeName");
if (placeTypeName != "St\\a/te")
throw new InvalidCastException(placeTypeName + " != St\\a/te");
placeTypeName = JsonObject.Parse(JsonCentroid).Object("place").Get<string>("placeTypeName");
if (placeTypeName != "St\\a/te")
throw new InvalidCastException(placeTypeName + " != St\\a/te");
}
}
Why does UserAuthExtensions.PopulateFromMap(session, jwtPayload) does not deserialize json values with escape correctly in ServiceStack.Auth?
The issue is due to enumerating a JsonObject didn't return the same escaped string value as indexing it which has been resolved from this commit.
This change is available from v5.12.1+ that's now available on MyGet.
I created an ArrayList with the json values from an Rest API.
This is the code to read the Rest API:
#RestController
public class exemploclass {
#RequestMapping(value="/vectors")
//#Scheduled(fixedRate = 5000)
public ArrayList<StateVector> getStateVectors() throws Exception {
ArrayList<StateVector> vectors = new ArrayList<>();
String url = "https://opensky-network.org/api/states/all?lamin=41.1&lomin=6.1&lamax=43.1&lomax=8.1";
//String url = "https://opensky-network.org/api/states/all?lamin=45.8389&lomin=5.9962&lamax=47.8229&lomax=10.5226";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
// optional default is GET
con.setRequestMethod("GET");
//add request header
con.setRequestProperty("User-Agent", "Mozilla/5.0");
int responseCode = con.getResponseCode();
System.out.println("\nSending 'GET' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
JSONObject myResponse = new JSONObject(response.toString());
JSONArray states = myResponse.getJSONArray("states");
System.out.println("result after Reading JSON Response");
for (int i = 0; i < states.length(); i++) {
JSONArray jsonVector = states.getJSONArray(i);
String icao24 = jsonVector.optString(0);
String callsign = jsonVector.optString(1);
String origin_country = jsonVector.optString(2);
Boolean on_ground = jsonVector.optBoolean(8);
//System.out.println("icao24: " + icao24 + "| callsign: " + callsign + "| origin_country: " + origin_country + "| on_ground: " + on_ground);
//System.out.println("\n");
StateVector sv = new StateVector(icao24, callsign, origin_country, on_ground);
vectors.add(sv);
}
System.out.println("Size of data: " + vectors.size());
return vectors;
}
}
The last line " return vectors;" returns a list with the values i parsed and returns it like this:
But i want this more "pretty", i want it to be one Array in each line, how can i achieve this?
P.S. Its on the .html page, not on console
Your return value seems a valid Json Object. If you want it more pretty so you can read it clearly then pass it through an application that makes that json pretty.
If you call your API from Postman, it will give you a pretty Json Object which will be better formatted. This will be because you have annotated your controller with #RestController so it will deliver an application/json response which Postman will know and then it will try to make it prettier.
P.S. Its on the .html page, not on console
So you hit your API from a browser. Most browsers don't expect a Json object to be returned, so they will not make it pretty. You can't force that from your Service either.
Just hit your API from Postman, it will understand it and make it pretty.
I'm using asyncHTTPrequest for async request to a REST API in ESP8266.
I receive the response in JSON format but can't parse it.
This kind of parsing was working while i used to made sync call to API.
I tried to store the request->responseText() into a String variable because its return a String, but the variable never get any value.
void sendRequest() {
if (request.readyState() == 0 || request.readyState() == 4) {
request.open("GET", "http://192.168.1.103:45456/api/systems/1013/arduino");
request.send();
}
}
void requestCB(void* optParm, asyncHTTPrequest* request, int readyState) {
if (readyState == 4) {
Serial.println(request->responseText());
const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(2) + JSON_OBJECT_SIZE(2) + 2*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(8)+816;
DynamicJsonBuffer jsonBuffer(capacity);
JsonObject& root = jsonBuffer.parseObject(request->responseText());
String a = request->responseText();
Serial.println(a);
JsonObject& schState = root["dataForArduino"][0];
String beginTime = schState["start"]; // "2019-12-02T21:51:00"
}
}
void setup() {
Serial.begin(9600);
wifi.Connect();
request.onReadyStateChange(requestCB);
ticker.attach(5, sendRequest);
}
I have wrote json parsing function (__get_from_json) to get key value from json here
e.g. if you have json response like
{
"timestamp" : "2020-04-01 19:20:49"
}
and in your application you want to parse timestamp value from it then
char response[max_response_size] = "{ \"timestamp\" : \"2020-04-01 19:20:49\" }";
char key[max_key_size] = "timestamp";
char value[max_value_size] = "";
if( __get_from_json( response, key, value, max_value_size ) ){
Serial.println(value);
}
I had the same problem and added .c_str() to get the response to print.
So in your example it would be:
String a = request->responseText();
Serial.println(a.c_str());
For the JSON I also needed to add .c_str()
DynamicJsonDocument jsonDoc(2048);
DeserializeJson(jsonDoc, a.c_str());
Hi Stack Overflow community!
I'm trying to mock a microservice in some java integration tests.
To do so, I'm using MockServer version 5.5.1.
To do the rest-requests I'm using OkHttp version 3.13.1
The code in java:
final SomeDTO requestObject = new SomeDTO(someParams);
final String jsonObject = objectMapper.writeValueAsString(requestObject);
final MediaType MEDIA_TYPE_JSON = MediaType.get("application/json; charset=utf-8");
final RequestBody requestBody = RequestBody.create(MEDIA_TYPE_JSON, jsonObject);
final Request request = new Request.Builder().url("serverUrl").post(requestBody).build();
final Response response = client.newCall(request).execute();
final String responseJson = response.body().string();
final ResultDTO result = objectMapper.readValue(responseJson, ResultDTO.class);
This works fine. However, when I attach MockServer with the matcher:
final MockServerClient client = new MockServerClient("127.0.0.1", 1080);
client.when(request().withMethod("POST") //
.withPath("serverUrl") //
.withBody(json(correctJsonString, MatchType.ONLY_MATCHING_FIELDS))) //
.respond(response().withStatusCode(200) //
.withHeaders(new Header("Content-Type", "application/json; charset=utf-8"),
new Header("Cache-Control", "public, max-age=86400"))
.withBody(responseJson));
I get a request didn't match expectation because: body didn't match, where the difference between the bodies are:
Request:
"body" : {
"type" : "STRING",
"string" : "{\"id\":33611,\"prop1\":28,\"prop2\":\"value2\",\"graph\":[...]}",
"contentType" : "text/plain; charset=utf-8"
}
Request should match:
"body" : {
"type" : "JSON",
"json" : "{\"prop2\":\"value2\",\"prop1\":28,\"graph\":[...]}"
}
So my questions:
Is it correct to assume that because of the type "JSON" <-> "STRING", the body doesn't match?
Is this a wrong interpretation of MockServer or does OkHttp generate the wrong request? (The request itself does work)
Any suggestions how to fix this?
Here is a JSON Demo:
#Test
public void testRemote3() {
String host = "localhost";
int port = 1080;
String url = String.format("http://%s:%d",host,port);
MockServerClient mockServerClient = new MockServerClient(host,port);
mockServerClient.when(
request()
.withMethod("POST")
.withPath("/order/completed/notify")
.withBody(new JsonBody("{\"username\":\"foo1\", \"age\": 13}", Charset.forName("UTF-8"),MatchType.STRICT))
).respond(
response().withStatusCode(200)
.withCookie("sessionId", "2By8LOhBmaW5nZXJwcmludCIlMDAzMW")
.withHeader("Location", "https://www.mock-server.com")
.withBody("{\"username\":\"wang\", \"status\": 1}")
);
mockServerClient.when(
request()
.withMethod("POST")
.withPath("/order/completed/notify")
.withBody(new JsonBody("{\"username\":\"zhao\", \"age\": 3}", Charset.forName("UTF-8"),MatchType.STRICT))
).respond(
response().withStatusCode(200)
.withCookie("sessionId", "2By8LOhBmaW5nZXJwcmludCIlMDAzMW")
.withHeader("Location", "https://www.mock-server.com")
.withBody("{\"username\":\"wang\", \"status\": true}")
);
log.info("----------------->calling ");
Map<String,Object> userInfo = new HashMap<>();
userInfo.put("age",13);
userInfo.put("username","foo1");
String result = OkHttpUtils.postJson(url+"/order/completed/notify",userInfo);
log.info(result);
Map<String,Object> fool = new HashMap<>();
fool.put("age",3);
fool.put("username","zhao");
result = OkHttpUtils.postJson(url+"/order/completed/notify",fool);
log.info(result);
}
The Nancy documentation seems to say that Pipelines.OnError should return null - as opposed to BeforeResponse which allows both null and a Response object.
All the examples like this one and many code samples here on StackOverflow show a Response being returned in the OnError, just like in the BeforeRequest.
When I attempt to return an HTTPStatus string for the Pipelines.OnError, everything works OK!
But when I attempt to return a Response, I get a compiler error:
Operator '+=' cannot be applied to operands of type 'Nancy.ErrorPipeline' and 'lambda expression'
I'm emulating almost exactly the code in the Nancy example, except for the fact that mine is a TinyIocContainer while the example's is using a StructureMap container and a StructureMap derived bootstrapper
Here's my code:
const string errKey = "My proj error";
const string creationProblem = "Message creation (HTTP-POST)";
const string retrievalProblem = "Message retrieval (HTTP-GET)";
public void Initialize(IPipelines pipelines)
{
string jsonContentType = "application/json";
byte[] jsonFailedCreate = toJsonByteArray(creationProblem);
byte[] jsonFailedRetrieve = toJsonByteArray(retrievalProblem);
Response responseFailedCreate = new Response
{
StatusCode = HttpStatusCode.NotModified,
ContentType = jsonContentType,
Contents = (stream) =>
stream.Write(jsonFailedCreate, 0, jsonFailedCreate.Length)
};
Response responseFailedRetrieve = new Response
{
StatusCode = HttpStatusCode.NotFound,
ContentType = jsonContentType,
Contents = (stream) =>
stream.Write(jsonFailedRetrieve, 0, jsonFailedRetrieve.Length)
};
// POST - error in Create call
pipelines.OnError += (context, exception) =>
{
// POST - error during Create call
if (context.Request.Method == "POST")
return responsefailedCreate;
// GET - error during Retrieve call
else if (context.Request.Method == "GET")
return responseFailedRetrieve;
// All other cases - not supported
else
return HttpStatusCode.InternalServerError;
};
}
private byte[] toJsonByteArray(string plainString)
{
string jsonString = new JObject { { errKey, plainString } }.ToString();
byte[] result = Encoding.UTF8.GetBytes(jsonString);
return result;
}
I had the same problem and I found a nice approach to the problem: http://paulstovell.com/blog/consistent-error-handling-with-nancy.
you should override RequestStartup on the Bootstrapper, here my test code:
protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
{
pipelines.OnError.AddItemToEndOfPipeline((ctx, ex) =>
{
DefaultJsonSerializer serializer = new DefaultJsonSerializer();
Response error = new JsonResponse(ex.Message,serializer);
error.StatusCode = HttpStatusCode.InternalServerError;
return error;
});
base.RequestStartup(container, pipelines, context);
}