Get Access Token with REST API in flutter/dart - rest

I cannot take access token with this getData() function, it return "Bad Request - Invalid Hostname". How can ı fix this problem ? Am ı change Future<> method, async or http methods ?
Here is my main.dart :
Future<HttpClient> getData() async {
Map<String, String> connection = {
'grant_type': 'string',
'branchcode': 'string',
'password': 'string',
'username': 'string',
'dbname': 'string',
'dbuser': 'string',
'dbpassword': 'string',
'dbtype': 'string+'
};
var uri = Uri.http("192.168.1.44:7070","api/v2/token",connection);
http.Response r = await http.get(uri);
print(r.statusCode);
print(r.body);
}
ERROR !
I/flutter ( 9316): 400
I/flutter ( 9316): <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
I/flutter ( 9316): <HTML><HEAD><TITLE>Bad Request</TITLE>
I/flutter ( 9316): <META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
I/flutter ( 9316): <BODY><h2>Bad Request - Invalid Hostname</h2>
I/flutter ( 9316): <hr><p>HTTP Error 400. The request hostname is invalid.</p>
I/flutter ( 9316): </BODY></HTML>

If you want to get token from rest api you have to post your connection with http.post() method.In this method you can easily declare the connection string in body field.I tried and it is working.
Here is my code block:
Future<Null> getData() async {
var url = "http://192.168.1.23:7070/api/v2/token";
http.post(url, body:{
"grant_type": "string",
"branchcode": "string",
"password": "string",
"username": "string",
"dbname": "string",
"dbuser": "string",
"dbpassword": "string",
"dbtype": "string"
}).then((response){
print("Response Status: ${response.statusCode}");
print("Response Body: ${response.body}");
});
}

I have tried to get the access token using unsplash api and it worked fine. I have used two plugins. first one, url_launcher, it allows you to open the url in a browser. you should put the registration url and once the user has successfully registered, user is redirected to your app. how? using the second plugin uni_links. once the user return back you start to extract the access token.
Launch the url that allow user to register
_launchURL() async {
var registerUrl= Constants.registerUrl;
if (await canLaunch(registerUrl)) {
await launch(registerUrl);
} else {
throw 'Could not launch $loginUrl';
}
}
when the user finish the process. your app should listen for this step
#override
initState() {
super.initState();
initUniLinks();
}
Future<Null> initUniLinks() async {
getUriLinksStream().listen((Uri uri) {
if (uri != null) {
setState(() {
String code = uri.queryParameters["code"];
print("code:" + code);
if (code != null) {
_getAccessToken(Constants.clientId, Constants.clientSecret,
Constants.redirectURI, code, "authorization_code");
}
});
}
}, onError: (err) {
print("error:" + err.toString());
});
}
_getAccessToken(String client_id, String client_secret, String redirect_uri,
String code, String grant_type) async {
var url = "https://unsplash.com/oauth/token";
var query_params = {
"client_id": client_id,
"client_secret": client_secret,
"redirect_uri": redirect_uri,
"code": code,
"grant_type": grant_type
};
var response = await http.post(url, body: query_params);
Map<String, dynamic> map = json.decode(response.body);
var accessToken = AccessToken.fromJson(map);
_saveAccessTokenToPrefs(accessToken);
}

Related

Response body is empty in http call

I am calling a remote PHP file to get some data into my Flutter app.
This is the Flutter function:
Future<void> registrarUsuario() async {
var url = Constantes.adminUsuariosUrl + 'nuevo_usuario.php';
final response = await http.post(Uri.parse(url), body: {
"email": controllerEmail.text,
"password": controllerPass.text
});
print("response ${response.body}");
}
Calling the function the print output is empty.
flutter: response
But calling the PHP file using Postman gives me the following output:
[{"id":"57","correo":"modestovasco#gmail.com"}]
I would like to update the funtion registrarUsuario to get the json objects from the response.body
Encode the body content in request
Future<void> registrarUsuario() async {
var url = Constantes.adminUsuariosUrl + 'nuevo_usuario.php';
final response = await http.post(Uri.parse(url), body:json.encode({
"email": controllerEmail.text,
"password": controllerPass.text
}));
print("response ${response.body}");
}

api response body doesn't show up

So I'm trying to get the access token from the Instagram API. it shows in Postman but it doesn't show up in the response body
onPageStarted: (url) async {
print("url is " + url);
if (url
.startsWith("https://aymen-ziouche.github.io/Gaming-website/")) {
Navigator.pop(context);
var uri = Uri.parse(url);
final String? code = uri.queryParameters["code"];
print("this's the code: $code");
final response = await dio
.post('https://api.instagram.com/oauth/access_token', data: {
'client_id': Constants.igClientId,
'client_secret': Constants.igClientSecret,
'grant_type': "authorization_code",
'redirect_uri': Constants.igRedirectURL,
'code': code
});
print("token is => ${response.data}");
print("response => ${response.statusCode} ${response.data}");
}
},
here's the log:
I/flutter (21891): url is https://aymen-ziouche.github.io/Gaming-website/?code=AQDIXj5sEEPfgHv_U5dcw3A9zQbWjR9w37MTWg9f153UAJsyHcG34iNtSgxH9sswpBvHrB1CobZBgReCx4GhCIeq5HiLfIDRe8c_HNS_U_7CQ5fVdP6JdS1vLxQua4iA706q9lik08r_C9aAFLm6oT0hJeQVXcHiwTqJWLxxyXxWhtmeClBYwlIoSJKp8gcf-rft6QrVOolBcXg6LCB6Vj9W7Dr3k4QiqsDVN0vX2uvAsw#_
I/flutter (21891): this's the code: AQDIXj5sEEPfgHv_U5dcw3A9zQbWjR9w37MTWg9f153UAJsyHcG34iNtSgxH9sswpBvHrB1CobZBgReCx4GhCIeq5HiLfIDRe8c_HNS_U_7CQ5fVdP6JdS1vLxQua4iA706q9lik08r_C9aAFLm6oT0hJeQVXcHiwTqJWLxxyXxWhtmeClBYwlIoSJKp8gcf-rft6QrVOolBcXg6LCB6Vj9W7Dr3k4QiqsDVN0vX2uvAsw
I/flutter (21891): token is =>
I/flutter (21891): response => 200
I fixed it. the problem was in dio.options() I added this: Options(responseType: ResponseType.json)
Add “Content-Type”: “application/json” and “Accept”: “application/json” to the headers parameters of your dio.post() method
According to the package example, you should use response.data.toString() if you want to print it.
If you want to use it, properly decode it first.

401 on POST requests, how to set up properly http service?

I am trying to fetch data after successful login. I have cookie based auth on backend. I checked the login response and I see that the cookie is present in the headers. I am not sure why my requests are not going with cookie.
I keep getting this in my console, code for not authorized. I/flutter (21293): 401
class Session {
Map<String, String> headers = {};
Future<Map> get(String endpoint) async {
http.Response response = await http.get(Uri.parse("$baseUrl$endpoint"), headers: headers);
print(response.statusCode);
updateCookie(response);
return jsonDecode(response.body);
}
Future<http.Response> post(dynamic data, String endpoint) async {
http.Response response = await http.post(Uri.parse("$baseUrl$endpoint"), body: json.decode(data), headers: headers);
updateCookie(response);
return response;
}
void updateCookie(http.Response response) {
String? rawCookie = response.headers['set-cookie'];
if (rawCookie != null) {
int index = rawCookie.indexOf(';');
headers['cookie'] =
(index == -1) ? rawCookie : rawCookie.substring(0, index);
}
}
}
Tried to print rawCookie as well
I/flutter (21293): _api_key=SFMyNTY.g3QAAAABbQAAAAhpZGVudGl0eXQAAAAHZAAKX19zdHJ1Y3RfX2QAF0VsaXhpci5HYXRld2F5LklkZW50aXR5ZAAGYWN0aXZlZAAEdHJ1ZWQACWF2YXRhcl9pZG0AAAAkNTY4NWMwNTMtYThhMS00MDA5LWJhN2UtZmJkNTkyMjBhM2U1ZAAHY291bnRyeXQAAAAGZAAEZmxhZ20AAAAI8J-HtfCfh7FkAAppc29fbmFtZV8ybQAAAAJwbGQACmlzb19uYW1lXzNtAAAAA3BvbGQABG5hbWVtAAAABlBvbGFuZGQACG51bV9jb2RlbQAAAAM2MTZkAAVwb2ludHQAAAAEZAAKX19zdHJ1Y3RfX2QAEEVsaXhpci5HZW8uUG9pbnRkAAtjb29yZGluYXRlc2gCYRRhNGQACnByb3BlcnRpZXN0AAAAAGQABHNyaWRiAAAQ5mQAC2Rlc2NyaXB0aW9ubQAAAAF4ZAACaWRtAAAAJGM2ZTljY2Q0LTM4MmItNDEzZi04ODYyLTc2ZjM5ZTYxOGFiNGQABG5pY2ttAAAACHRlc3Rzc3Nz.80iQK3sUwPPVj1pkaZsKgMxQ4Lt8aW8-ndYbPSucGag; path=/; HttpOnly
I/flutter (21293): 200
Then I use it
class Items{
Future<Map> fetchItems() async {
final response = await Session().get("/user/items");
return response;
}
}
I had the same problem. I resolved it by using dio and cookiejar instead of HTTP.
Add these dependencies in your pubspec.yaml:
dependencies:
dio: ^4.0.4
dio_cookie_manager: ^2.0.0
cookie_jar: ^3.0.1
Here's an example to use dio:
var dio = Dio(BaseOptions(
connectTimeout: 10000, // in ms
receiveTimeout: 10000,
sendTimeout: 10000,
responseType: ResponseType.plain,
followRedirects: false,
validateStatus: (status) { return true; }
)); // some dio configurations
dio.interceptors.add(CookieManager(CookieJar()));
Response response = await dio.post(
"http://example.com/login",
data: FormData.fromMap(
{
'username': 'myUser',
'password': 'myPassword',
}
)); // cookies are automatically saved
Response nextResponse = await dio.post("http://example.com/user/items");

The getter 'length' was called on null in post request

I'm trying to make a post request to an API, and I couldn't get why this is happening.
This is my code:
print('THIS IS PRINTING');
var response = await http.post(url, body: body, headers: header);
print('This not printing (throwing error before it prints)');
This is the error that I'm getting:
I/flutter ( 2417): NoSuchMethodError: The getter 'length' was called on null.
I/flutter ( 2417): Receiver: null
I/flutter ( 2417): Tried calling: length
I'm able to make the request using PostMan, and giving the same fields and values, I get this error on dart. I'm also able to make other get requests without any issues.
Full code:
void getFavorites() async {
var url = "https://www.my-url-edited.com/favorite";
var header = {
"Content-Type": "application/x-www-form-urlencoded",
"token": "my token ---- edited",
};
var body = {
"car_id": "1",
"boat_id": null,
"habitation_id": null,
"product_id": null,
};
try {
print('print before post request --- working');
// var response = await http.post(url, body: body, headers: header);
var response = await http.post(url, body: body, headers: header);
print('This not printing (throwing error before it prints)');
print(response.body);
// var data = json.decode(response.body);
} catch (e) {
print(e);
throw Exception('Not connected to network');
}
}
you header should be ,
headers: {'Content-type': 'application/json','Accept': 'application/json'}
Try
var header = {
"Content-Type": "application/json",
"token": "my token ---- edited",
};
var body = jsonEncode({
"car_id": "1",
});

How to post x-www-form-urlencoded in Flutter

I am trying to send a POST request to an API to create an account.
The request is working well, it should look like this :
Bulk Edit Mode :
Key-Value Edit mode :
There are also 9 headers that are auto-generated, so I did not show them, but I can take another screen if you need to.
My request looks like this :
import 'dart:convert' as convert ;
import 'package:my_project/requests/utils.dart';
import 'package:http/http.dart' as http;
Future<String> createUser(String firstName, String name, String mail,
String password, String confirmPassword, String birthDate,
String phone) async {
String url = BASE_URL + "createUser" ; // Don't worry about BASE_URL, the final url is correct
Map<String, dynamic> formMap = {
"name": name,
"surname": firstName,
"mail": mail,
"password": password,
"birth": birthDate,
"phone": phone,
"confirmPassword": confirmPassword
} ;
http.Response response = await http.post(
url,
body: convert.jsonEncode(formMap),
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
encoding: convert.Encoding.getByName("utf-8"),
);
print("RESPONSE ${response.statusCode} ; BODY = ${response.body}");
return (response.body) ;
}
Here is my print result :
I/flutter ( 6942): RESPONSE 307 ; BODY =
As you can see, I am getting a 307 error, and the problem does not come from the server, as it worked with Postman.
Am I sending this form-urlencoded POST request correctly ?
I also tried :
http.Response response = await http.post(
url,
body: "name=$name&surname=$firstName&mail=$mail&password=$password&birth=$birthDate&phone=$phone&confirmPassword=$confirmPassword",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
encoding: convert.Encoding.getByName("utf-8"),
);
but with the same results. I tried too :
http.Response response = await http.post(
url,
body: formMap,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
encoding: convert.Encoding.getByName("utf-8"),
);
with same result again.
What am I doing wrong ?
EDIT :
I tried FoggyDay answer, here is my request now :
final client = HttpClient() ;
final request = await client.postUrl(Uri.parse(url));
request.headers.set(HttpHeaders.contentTypeHeader, "application/x-www_form-urlencoded");
request.followRedirects = true ;
request.write(formMap);
final response = await request.close();
print("STATUS CODE = ${response.statusCode}");
However I still have a 307 error. Did I create the right request ?
EDIT 2 :
As asked, I printed location as follow :
final client = HttpClient() ;
final request = await client.postUrl(Uri.parse(url));
request.headers.set(HttpHeaders.contentTypeHeader, "application/x-www_form-urlencoded");
request.followRedirects = true ;
request.write(formMap);
final response = await request.close();
print("STATUS CODE = ${response.statusCode}");
print("Response headers = ${response.headers}");
And I get :
I/flutter ( 7671): STATUS CODE = 307
I/flutter ( 7671): Response headers = location: /app/createUser/
I/flutter ( 7671): date: Tue, 26 May 2020 09:00:29 GMT
I/flutter ( 7671): content-length: 0
I/flutter ( 7671): server: Apache/2.4.41 (Amazon) OpenSSL/1.0.2k-fips
The thing is I am already making a call on /app/createUser... ('/app/' is in BASE_URL)
For x-www-form-urlencoded parameters, just use this:
Future<String> login(user, pass) async {
final response = await http.post(
Uri.parse('https:youraddress.com/api'),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
encoding: Encoding.getByName('utf-8'),
body: {"title": "title"},
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
}
}
official http package from flutter is buggy with urlencoded type, you can use Dio package instead.
final dio = Dio();
final res = dio.post(
'/info',
data: {'id': 5},
options: Options(contentType: Headers.formUrlEncodedContentType),
);
As you can see, I am getting a 307 error, and the problem does not come from the server, as it worked with Postman.
No, that's NOT necessarily the case. Look here:
MDN: 307 Temporary Redirect
In other words, Postman is following the redirect ... and your Flutter app isn't.
SUGGESTION: Try setting followRedirects to true:
https://api.flutter.dev/flutter/dart-io/HttpClientRequest/followRedirects.html
ADDITIONAL INFO:
The default value for request.followRedirects happens to be "true" anyway. It doesn't hurt to explicitly set it ... but it explains why the behavior didn't change.
Per this post:
The Dart HTTP client won't follow
redirects
for POSTs unless the response code is 303. It follows 302 redirects
for GET or HEAD.
Per this post
The correct way to handle redirects on POST requests is to manually
implement an appropriate strategy for your use case:
var response = await client.post(...);
if (response.statusCode == 301 || response.statusCode == 302) {
// send post request again if appropriate
}
let try with this code, it works well for me.
var headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
var request = http.Request('POST', Uri.parse('https://oauth2.googleapis.com/token'));
request.bodyFields = {
'client_id': '',
'client_secret': '',
'code': '',
'grant_type': 'authorization_code',
'redirect_uri': ''
};
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}
If you are using http, you should add the below lines
Android -
android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<application
android:label="first_app"
android:usesCleartextTraffic="true" //this line
android:icon="#mipmap/ic_launcher">
iOS -
ios/Runner/info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Be warned that you will need to have an explanation for Apple's review team when enabling this, otherwise, your app will get rejected on submission.
Uninstall the app and Reinstall again if you have the app already in the emulator when you add those lines to avoid confusions.
If you send HTTP GET request, you can use query parameters as follows:
QueryParameters
http://example.com/path/to/page?name=ferret&color=purple
The contents are encoded as query parameters in the URL
application/x-www-form- urlencoded
The contents are encoded as query parameters in the body of the
request instead of the URL.
The data is sent as a long query string. The query string contains
name-value pairs separated by & character
POST example
flutter http package version - http: ^0.13.1
import 'package:http/http.dart' as httpClient;
Future<dynamic> postData() async {
//Uri.https("192.168.1.30:5000", "/api/data")
//Uri.parse("your url");
final Uri uri = Uri.http("192.168.1.30:5000", "/api/data");
final response = await httpClient.post(
uri,
body: {
"name": "yourName",
"age": "yourAge"
},
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
encoding: Encoding.getByName('utf-8'),
);
return response.body;
}