Dart - sending GET parameters that are lists - http

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

Related

salesforce: Absolute path in the request URI

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

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("&");
}

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.

Retrofit Post Request with URL encoded body and user authentication

I am trying to create a request using retrofit with a key-value (& separated) payload and simple user authentication, as it can be done in the following curl command:
curl -X POST -d "grant_type=refresh_token&refresh_token=<refresh_token>" -u"<client_id>:<client_secret>" http://localhost:8000/o/token/
How can I create a request in retrofit that supplies the above data? I need both the interface method and the creation of RequestBody if it used.
UPDATE:
I used the following code
interface method definition:
#POST("/o/token/")
Observable<ServerToken> refreshAccessToken(#Header("Authorization") String auth, #Body RequestBody tokens);
calling the implementation:
RequestBody body = new FormEncodingBuilder()
.add("grant_type", "refresh_token")
.add("refresh_token", serverToken.refresh_token)
.build();
String auth = Credentials.basic("<client_id>", "<client_secret>");
mTokenApi.refreshAccessToken(auth, body)
But I am getting a Content-Type: application/json in the request and an empty request body.
How can I fix this?
The correct way to do it is:
interface method definition:
#FormUrlEncoded
#POST("/o/token/")
Observable<ServerToken> refreshAccessToken(#Header("Authorization") String auth,
#Field("grant_type") String grantType,
#Field("refresh_token") String refreshToken);
calling the implementation:
String auth = Credentials.basic(clientID, clientSecret);
mTokenApi.refreshAccessToken(auth, "refresh_token", serverToken.refresh_token)

modify HTTP request URI and HTTP request method with a CXF interceptor

I want to modify HTTP request URI and HTTP request method using a CXF interceptor in a HTTP client.
I have developed something like this:
public class MyInterceptor extends AbstractPhaseInterceptor<Message> {
public MyInterceptor() {
super(Phase.PRE_PROTOCOL);
}
public void handleMessage(Message message) {
// this returns me correct path and method
// String path = (String) message.getExchange().getOutMessage().get(Message.REQUEST_URI);
// String method = (String) message.getExchange().getOutMessage().get(Message.HTTP_REQUEST_METHOD);
// this does not work as expected
String path = (String) message.get(Message.REQUEST_URI);
String method = (String) message.get(Message.HTTP_REQUEST_METHOD);
// do things here
}
}
Why do need I to use exchange/OutMessage to obtain data about current message and I can not use message directly?
How can I edit both values? I tried using message.put(<key>, <value>) and the same with exchange/OutMessage, but nothing is modified.
Coming to the path, you'd always get that value as null, I believe.
You can try following code, to get the actual value of your uri:
String requestURI = (String) message.get(Message.class.getName() + ".REQUEST_URI");

Resources