salesforce: Absolute path in the request URI - http

Trying to apply abs_path from RFC2616 (https://www.rfc-editor.org/rfc/rfc2616#section-5.1.2) but receiving callout exception 'System.CalloutException: no protocol: /animals'.
End point url trying in following example : http://th-apex-http-callout.herokuapp.com/animals
eg.
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setHeader('Host','th-apex-http-callout.herokuapp.com');
request.setEndpoint('/animals');
request.setMethod('GET');
HttpResponse response = http.send(request);
// If the request is successful, parse the JSON response.
if (response.getStatusCode() == 200) {
// Deserializes the JSON string into collections of primitive data types.
Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
// Cast the values in the 'animals' key as a list
List<Object> animals = (List<Object>) results.get('animals');
System.debug('Received the following animals:');
for (Object animal: animals) {
System.debug(animal);
}
}
expected output :
Received the following animals:
majestic badger
fluffy bunny
etc...

I've never tried sending Host as a header but this works just fine
request.setEndpoint('http://th-apex-http-callout.herokuapp.com/animals');

Related

http package can not convert map to query URL in flutter

I am trying make an http post request with the method below. when I run the method I keep getting the message that an exeption has occured and am being pointed to this utils.dart file. From what am seeing my best guess is that there is a problem converting the map data I have provided in the url into the query string. Icant seem to find what am doing wrong tho.How may I solve this.
Request Method
Future<List>getdata()async{
print("Loading ....");
String theUrl ="https://http://127.0.0.1/codeishweb/notifiedUser.php";
var res = await http.post(Uri.encodeFull(theUrl),headers: {"Accept":"application/json"},body: {"notID":2},);
var responseBody = json.decode(res.body);
print("results ::$responseBody");
//print("the response at position something::::\nHeading\n${responseBody[0][7]['post_head']}\nBody\n${responseBody[0][7]['post_body']}");
return responseBody;
}
Error message in utils.dart
/// Converts a [Map] from parameter names to values to a URL query string.
///
/// mapToQuery({"foo": "bar", "baz": "bang"});
/// //=> "foo=bar&baz=bang"
String mapToQuery(Map<String, String> map, {Encoding encoding}) {
var pairs = <List<String>>[];
map.forEach((key, value) => pairs.add([
Uri.encodeQueryComponent(key, encoding: encoding),
Uri.encodeQueryComponent(value, encoding: encoding)
]));
return pairs.map((pair) => "${pair[0]}=${pair[1]}").join("&");
}

Dart - sending GET parameters that are lists

I want to send parameters with an http GET request in dart. The first answer here demonstrates it well: How do you add query parameters to a Dart http request?
var uri =
Uri.https('www.myurl.com', '/api/query', queryParameters);
However, a major problem is that queryParameters only accepts:
Map<String, String>
This doesn't allow me to pass in lists/arrays.
If i change my get request to a post request, I am easily able to send a
body (as a json encoded String) as outlined by the flutter docs: https://pub.dev/documentation/http/latest/http/post.html
post(url, {Map<String, String> headers, body, Encoding encoding})
However, the get request has no such equivalent argument for query parameters: https://pub.dev/documentation/http/latest/http/get.html
get(url, {Map<String, String> headers})
I have also tried adding query parameters directly to the url like so:
get('www.myurl.com/api/query/?array[]=value1&array[]=value2&array[]=value3)
but the square brackets [] always get transformed into %5B%5D when I receive it in the server.
Any help is appreciated.
Thanks
In fact, queryParameter takes Map<String, dynamic>. Check the source code:
factory Uri(
{String scheme,
String userInfo,
String host,
int port,
String path,
Iterable<String> pathSegments,
String query,
Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
String fragment}) = _Uri;
The dynamic can be either a String or an Iterable<String>. So,
var uri = Uri(
scheme: 'http',
host: 'www.myurl.com',
path: '/api/query/',
queryParameters: {
'array': ['value1', 'value2', 'value3'],
},
);
print(uri);
prints:
http://www.myurl.com/api/query/?array=value1&array=value2&array=value3

Http.put does not accept any but a String

Simple is, that I am trying to make a PUT request to my API but I get the type error of:
_CastError (type 'List<String>' is not a subtype of type 'String' in type cast)
My API accepts an Array of strings (string[]), which I know work because I am currently consuming it on the sibling web platform. So I am trying to replicate that on the Flutter app with the below code. At the moment it is just static code.
I know, that the http module is only accept string but is there a way to get around this? As it does not make sense, as what happens if we want to post an int, bool or <List<String>>. I know you can obviously convert using .toString() but my API has certain validation and is rigid on what it can accept.
Code below:
When I use this payload it works because it follows the rigid types of the Http module (<String, String>)
Map<String, String> payloadThatWorks = {"first_name": "First Name"};
Now when I want to give the payload of the type Map<String, List<String>> with the code below:
Map<String, List<String>> payload = {
"personal_settings": ["allow-notification-discussion-mentions"]
};
It throws the error of _CastError (type 'List<String>' is not a subtype of type 'String' in type cast)
in the http.put function below:
Main API Helper function
static Future<http.Response> queryPut(String apiPath, {dynamic body}) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String accessToken = prefs.getString('access_token');
var response = await http.put(
Uri.encodeFull(_urlBase + '$apiPath'),
body: body,
headers: {
HttpHeaders.authorizationHeader: "Bearer $accessToken",
'Accept': 'application/json'
},
);
return response;
}
However, when helper function is called in my Widget...
http.Response response =
await ApiService.queryPut('/api/users/$username', body: payload);
So i'm in a spot where the http module does not accept anything put <String> but the API does not accept anything but an Array or <List<String>>
How can I get round this or understand why the http put method is so rigid?
Thank you in advance :)
Sam
You can import dart:convert and use its jsonEncode to convert your map or array of map into a string
So basically you will have to do the following
String payloadStr = jsonEncode(payload)
and use this payloadStr to pass in the http methods. Similarly you can use JsonDecoder to convert json string to Map or Array of map.

False positive in consumer tests for valid and invalid reques(matching multiple contracts)

We have the case where we have two different outcomes on the producer side depending on a request one is for success and on which trows error message.
A simplified sample with two contracts:
1)Contract.make {
request {
method PUT()
urlPath("/sample")
headers {
contentType('application/json')
}
body("{\"acc\": \"1234A\" ,\"case\":\"abc23\",\"re\":2018/12/12}")
}
response {
status BAD_REQUEST()
}
}
2)
Contract.make {
request {
method PUT()
urlPath("/sample")
headers {
contentType('application/json')
}
body("{\"acc\": \"1234\" ,\"case\":\"abc23\",\"re\":2018/12/12}")
}
response {
status 200
}
}
On the consumer side it is able to match both request where as , when i run the invalid request test case it is throwing org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request
But the for both scenarios i can able to see request and coresponding response, i can able to see in the logs
Can any body help me in this?
Thanks
These are my consumer test cases
1) its sucess request scenauro its working fine it is getting 200
enter code here
#Test
public void should_update_case_sucess() throws Exception {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Type", "application/json");
ResponseEntity<String> response = restTemplate.exchange(
"http://localhost:8083//sample",
HttpMethod.PUT,
new HttpEntity<>("{\"acc\":\"1234\",\"case\":\"abc23\",\"re\":\"20181212\"}", httpHeaders), String.class);
BDDAssertions.then(response.getStatusCodeValue()).isEqualTo(200);
}
2)
This is the failure scenario which not getting 400 respose instead it is trowing httpclient error,it is not able to invoke target
enter code here
#Test
public void should_update_case_error() throws Exception {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Type", "application/json");
ResponseEntity<String> response = restTemplate.exchange(
"http://localhost:8083//sample",
HttpMethod.PUT,
new HttpEntity<>("{\"acc\":\"1234A\",\"caseNumber\":\"abc23\",\"representmentStartDate\":\"20181212\"}", httpHeaders), String.class);
BDDAssertions.then(response.getStatusCodeValue()).isEqualTo(400);
}
Could you help me in this
This will not work cause wiremock has two same requests and two different responses so the first one wins.
What you have to do is to alert the request a little bit to differentiate between the two and that way you'll find the proper response.

Asp.net web api sometimes returning content type as text/plain

I am working with ASP.NET web api. I understand response depends on the content-type header. I am asking this question assuming client will always send content-type as application/json. As suggested in this SO post, I am using following line to return JSON as the default response.
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html") );
Until now all my controllers were returning dynamic response & data was returned as JSON.
[Route("employee/division")]
[HttpPost]
public dynamic GetEmployeeData(FilterModel filter)
{
//getData returns a POCO
var data = getData();
//This will return valid json response to client
return data;
}
Recently, I added another endpoint which is returning HttpResponseMessage.
[HttpGet]
[Route("employee/update")]
public HttpResponseMessage Update()
{
...........
//return the response
var msg = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("Info updated !!")
};
return msg;
}
The problem is, in this case response is returned as string. Content-Type in the response header looks like this. "content-type": "text/plain; charset=utf-8",
I have following questions:
Why am I getting different type of response when I follow different approachs?
Is the approach no. 1 which is working, is that the right way to return JSON response.
Since I wanted to set different response code, I have decided to use approach no two. Is there any downside to this approach? How can I return JSON using this approach?

Resources