URL with %7B and %7D - flutter

I'm learning to use APIs with Flutter and I'm trying to use the Open Weather Map to this but, my code is inserting this %7B and %7D in every variable that I use in URL.
actual URL:
https://api.openweathermap.org/data/2.5/weather?lat=%7B-15.783783783783784%7D&lon=%7B-47.93345625648786%7D&appid=%7Bf0060b47028a54500c466c7288e41d31%7D
This is what i want:
https://api.openweathermap.org/data/2.5/weather?lat=-15.783783783783784&lon=-47.93345625648786&appid=f0060b47028a54500c466c7288e41d31
What's wrong with my code ?
My code:
import 'package:flutter/material.dart';
import 'package:clima/services/location.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
const apiKey = 'f0060b47028a54500c466c7288e41d31';
class LoadingScreen extends StatefulWidget {
#override
_LoadingScreenState createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
double latitude;
double longitude;
void getLocation() async {
Location location = Location();
await location.getCurrentLocation();
latitude = location.latitude;
longitude = location.longitude;
getData();
}
void getData() async {
var url = Uri.https('api.openweathermap.org', '/data/2.5/weather', {
'lat': '{$latitude}',
'lon': '{$longitude}',
'appid': '{$apiKey}',
});
var response = await http.get(url);
if (response.statusCode == 200) {
String data = response.body;
var temperature = jsonDecode(data)['main']['temp'];
print(temperature);
} else {
print(response.statusCode);
print(url);
}
}
#override
void initState() {
getLocation();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
#override
void deactivate() {
super.deactivate();
}
}

In your getData() function, try removing the curly braces around the url parameters, like this:
var url = Uri.https('api.openweathermap.org', '/data/2.5/weather', {
'lat': '$latitude',
'lon': '$longitude',
'appid': '$apiKey',
});
Alternatively, you can concatenate the URL tring yourself like this.
var baseUrl = 'https://api.openweathermap.org/data/2.5/weather?';
var appid = 'f0060b47028a54500c466c7288e41d31';
var latString = '-15.783783783783784';
var lonString = '-47.93345625648786';
var urlString =
baseUrl + 'lat=$latString' + '&' + 'lon=$lonString' + '&' + 'appid=$appid';

Related

How to write and read data anywhere by shared_preferences on Flutter 3.7 background isolates?

On Flutter 3.7 platform channels can run on any isolate. So I tried this sample,
import ‘package:flutter/services.dart’;
import ‘package:shared_preferences/shared_preferences.dart’;
void main() {
// Identify the root isolate to pass to the background isolate.
// (API introduced in Flutter 3.7)
RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
Isolate.spawn(_isolateMain, rootIsolateToken);
}
void _isolateMain(RootIsolateToken rootIsolateToken) async {
// Register the background isolate with the root isolate.
BackgroundIsolateBinaryMessenger
.ensureInitialized(rootIsolateToken);
// You can now use the shared_preferences plugin.
SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
print(sharedPreferences.getBool(‘isDebug’));
}
I can read from data on shared_preferences in this sample okey. But how can I use this feature anywhere in my app? How can I set or read data using this isolate on initState for example?
Basically you need to implement communication between isolates. You can read more about it here
Here is an example, you can change flutter_secure_storage that i used with shared_preferences package
import 'dart:async';
import 'dart:isolate';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class CreationEvent {
final RootIsolateToken isolateToken;
final SendPort sendPort;
CreationEvent(this.isolateToken, this.sendPort);
}
class DeletetionEvent {}
class ReadEvent {
final String key;
const ReadEvent(this.key);
}
class ReadResult {
final String key;
final String? content;
const ReadResult(this.key, this.content);
}
class IsolateIO {
IsolateIO._();
final _toBgPort = Completer();
final Map<Object, Completer> _completerMap = {};
Isolate? _isolate;
StreamSubscription? _fromBgListener;
void start() async {
RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
ReceivePort fromBG = ReceivePort();
_fromBgListener = fromBG.listen((message) {
// setup process
if (message is SendPort) {
_toBgPort.complete(message);
return;
}
if (message is ReadResult) {
_completerMap['read:${message.key}']?.complete(message.content);
_completerMap.remove('read:${message.key}');
}
});
_isolate = await Isolate.spawn(
(CreationEvent data) {
final worker = IsolateWorker(data.isolateToken, data.sendPort);
worker.listen();
},
CreationEvent(rootIsolateToken, fromBG.sendPort),
);
}
Future<String?> readFromStorage(String key) async {
// make sure isolate created with ports
final port = await _toBgPort.future;
// store completer
final completer = Completer<String?>();
_completerMap['read:$key'] = completer;
// send key to be read
port.send(ReadEvent(key));
// return result
return completer.future;
}
void stop() async {
if (_toBgPort.isCompleted) {
final port = await _toBgPort.future;
port.send(DeletetionEvent());
}
_fromBgListener?.cancel();
_isolate?.kill(priority: Isolate.immediate);
}
static final i = IsolateIO._();
}
class IsolateWorker {
final RootIsolateToken rootIsolateToken;
final SendPort toMain;
final FlutterSecureStorage storage;
StreamSubscription? subs;
IsolateWorker(
this.rootIsolateToken,
this.toMain, {
this.storage = const FlutterSecureStorage(
aOptions: AndroidOptions(
encryptedSharedPreferences: true,
),
),
}) {
// Register the background isolate with the root isolate.
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
}
void listen() {
ReceivePort fromMain = ReceivePort();
toMain.send(fromMain.sendPort);
subs = fromMain.listen((message) => onMessage(message));
}
void onMessage(dynamic message) async {
if (message is DeletetionEvent) {
subs?.cancel();
return;
}
if (message is ReadEvent) {
final rawJson = await storage.read(key: message.key);
toMain.send(ReadResult(message.key, rawJson));
}
}
}
class View extends StatefulWidget {
const View({super.key});
#override
State<View> createState() => _ViewState();
}
class _ViewState extends State<View> {
String username = '';
#override
void initState() {
super.initState();
IsolateIO.i.start();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final name = await IsolateIO.i.readFromStorage('username');
setState(() {
username = name ?? '';
});
});
}
#override
void dispose() {
IsolateIO.i.stop();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SizedBox(
child: Text(username),
);
}
}

Get request of google maps api from postman is working properly but in the app it is showing null(NoSuchMethodError)

Why is the GET request to the Google Maps API working properly in Postman but showing a null error (NoSuchMethodError) when implemented in the app?
Environment
I've configured a local REST API:
static const String BASE_URL = "http://localhost:8000";
static const String GEOCODE_URI = "api/v1/config/geocode-api";
Code I'm Using
Here are the excerpts of the code I'm attempting this with.
The main implementation is in location_controller.dart:
<!-- location_controller.dart -->
import 'package:ecommerceapp/models/address_model.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get_connect/http/src/response/response.dart';
import 'package:get/get_state_manager/get_state_manager.dart';
import 'package:ecommerceapp/data/repositary/location_repo.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class LocationController extends GetxController implements GetxService {
LocationRepo locationRepo;
LocationController({
required this.locationRepo,
});
bool _loading = false;
late Position _position;
late Position _pickPosition;
Placemark _placemark = Placemark();
Placemark _pickPlacemark = Placemark();
List<AddressModel> _addressList = [];
late List<AddressModel> _allAddressList = [];
List<String> _addressTypelist = ["home", "office", "others"];
int _addressTypeIndex = 0;
late Map<String, dynamic> _getAddress;
late GoogleMapController _mapController;
List<AddressModel> get addressList => _addressList;
bool get loading => _loading;
Position get position => _position;
Position get pickPosition => _pickPosition;
Map get getAddress => _getAddress;
bool _updateAddressData = true;
bool _changeAddress = true;
void setMapController(GoogleMapController mapController) {
_mapController = mapController;
}
void updatePosition(CameraPosition position, bool fromAddress) async {
print("Update Position");
if (_updateAddressData) {
_loading = true;
update();
try {
if (fromAddress) {
_position = Position(
latitude: position.target.latitude,
longitude: position.target.longitude,
timestamp: DateTime.now(),
heading: 1,
accuracy: 1,
altitude: 1,
speedAccuracy: 1,
speed: 1,
);
} else {
_pickPosition = Position(
latitude: position.target.latitude,
longitude: position.target.longitude,
timestamp: DateTime.now(),
heading: 1,
accuracy: 1,
altitude: 1,
speedAccuracy: 1,
speed: 1,
);
}
if (_changeAddress) {
String _address = await getAddressfromGeocode(LatLng(position.target.latitude, position.target.longitude));
}
} catch (e) {
print(e);
}
}
}
Future<String> getAddressfromGeocode(LatLng latLng) async {
String _address = "Unknown Location Found";
print("Address : $_address");
Response response = await locationRepo.getAddressfromGeocode(latLng);
print("Status Code : ${response.statusCode}");
print(response.body);
if (response.body["status"] == "OK") {
_address = response.body["result"][0]['formatted_address'].toString();
print("Printing Address : $_address");
} else {
print("Error getting the google api");
}
return _address;
}
}
which calls the location_repo.dart:
import 'package:ecommerceapp/utils/app_constants.dart';
import 'package:get/get_connect/http/src/response/response.dart';
import 'package:google_maps_flutter_platform_interface/src/types/location.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:ecommerceapp/data/api/api_client.dart';
class LocationRepo {
final ApiClient apiClient;
final SharedPreferences sharedPreferences;
LocationRepo({
required this.apiClient,
required this.sharedPreferences,
});
Future<Response> getAddressfromGeocode(LatLng latLng) async {
return await apiClient.getData('${AppConstants.GEOCODE_URI}'
'?lat=${latLng.latitude}&lng=${latLng.longitude}');
}
}
In the getAddressfromGeocode method, when I tried to print the latitude and longitude, the print statements were also working fine:
Future<Response> getData(String uri, {Map<String, String>? headers}) async {
try {
Response response = await get(
uri,
headers: headers == null ? _mainHeaders : headers,
);
return response;
} catch (e) {
return Response(statusCode: 1, statusText: e.toString());
}
}
But, my code fails and response.body is null:
flutter: NoSuchMethodError: The method '\[\]' was called on null.
Receiver: null
Tried calling: \[\]("status")
I have no idea what I'm doing and still haven't asked ChatGTP, so I did not find any working solutions. Please help.

I can't get data open weather map

I don't know why but keeps telling me error 400 when it tries to fetch data from open weather map
even i tried to change the api key and tried to change the code it self but it didn't work
so i want to know why this happening and i want to know the solution for this problem
import 'package:clima/services/location.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
const apiKey = '*****53a8**************';
class LoadingScreen extends StatefulWidget {
#override
_LoadingScreenState createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
double lontitude;
double latitude;
#override
void initState() {
getLocation();
getData();
super.initState();
}
Future getLocation() async {
Location location = Location();
await location.getCurrentLocation();
latitude = location.latitude;
lontitude = location.lontitude;
}
Future getData() async {
http.Response response = await http.get(
Uri.parse(
'https://api.openweathermap.org/data/2.5/weather?lat=$latitude&lon=$lontitude&appid=$apiKey'),
);
if (response.statusCode == 200) {
String data = response.body;
var temperature = jsonDecode(data)['main']['temp'];
print(temperature);
var condition = jsonDecode(data)['weather'][0]['id'];
print(condition);
var city = jsonDecode(data)['name'];
print(city);
} else {
print(response.statusCode);
}
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
Just typing in that URL in a browser and substituting longitude, latitude, and apiKey with values works just fine for me.
https://api.openweathermap.org/data/2.5/weather?lat=50,123123&lon=13.123123&appid=************** // add private key
OUTPUT:
{"coord":{"lon":13.1231,"lat":50.1231},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}],"base":"stations","main":{"temp":281.16,"feels_like":279.56,"temp_min":279.08,"temp_max":283.95,"pressure":1023,"humidity":79},"visibility":10000,"wind":{"speed":2.57,"deg":250},"clouds":{"all":0},"dt":1632954450,"sys":{"type":2,"id":47765,"country":"CZ","sunrise":1632978356,"sunset":1633020533},"timezone":7200,"id":3061350,"name":"Žlutice","cod":200}
You should check the format of the things that get substituted by your code.

How to Store API model object in Local Storage in flutter?

I fatch this issue during use Local Storage(shared_preferences: ^2.0.6) in my code....but i cant store the api model object in local storage...How can i do?
storeModelInPrefs() async {
http.Response response =
await http.get(Uri.parse('http://18.191.193.64/api/view_categories'));
String encodeData = jsonEncode(response.body);
///Write Data in local Storage
GetStorageUtility.prefs!.write('key', encodeData);
///Read Data from local Storage
String data = GetStorageUtility.prefs!.read('key');
if (data == null) {
print('no data in GetStorage');
} else {
Map<String, dynamic> map = jsonDecode(data);
print(map);
}
}
This is the sample example that i have created from the code that you have provided.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_app/utilities.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
GetStorageUtility.init();
super.initState();
getRemoteData();
}
getRemoteData() async {
/// This is where the api is fetching the data
var response =
await http.get(Uri.parse('http://18.191.193.64/api/view_categories'));
/// This is where the string getting
String encodeData = jsonEncode(response.body);
GetStorageUtility.write("key", encodeData);
/// this is where you fetch the data
String data = GetStorageUtility.read("key");
if (data == null) {
print('no data in GetStorage');
} else {
Map<String, dynamic> jsonData = json.decode(data);
jsonData.forEach((key, value) {
print("$key : $value\n");
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text(" Page"),
),
);
}
}
SharadPrefs Singleton,
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';
class GetStorageUtility {
static Future<SharedPreferences> get _instance async =>
_prefsInstance ??= await SharedPreferences.getInstance();
static SharedPreferences _prefsInstance;
static Future<SharedPreferences> init() async {
_prefsInstance = await _instance;
return _prefsInstance;
}
static String read(String key, [String defValue]) {
return _prefsInstance.getString(key) ?? defValue ?? "";
}
static Future<bool> write(String key, String value) async {
var prefs = await _instance;
return prefs?.setString(key, value) ?? Future.value(false);
}
}
Now there is on thing that you have see that you have added in you android manifest file
<application android:usesCleartextTraffic="true" />
This one should be there and the internet permission should be there in the debug and the main folders manifestfile.
This will work but this is not the best practice to store the data as string in the sharedprefs. Shared Prefs has only the job to manage the small data like bool or string. For your use case you can use a sqlite as a local data base. where you can fetch the data based on the condititions.
Let me know if it works.
Happy Coding.

Flutter - Openweathermap api call error - Passing parameter to api call doesn't work

Location class is the responsible for getting the longitude and latitude.
getData() method from the Loading_screen class is the responsible for calling the api to get weather data. The problem is when I pass the longitude and latitude values to the url of api, it returned error 400.
Workaround is to hardcode the longitude and latitude and it successfully retrieved api data. I can't figure why passing longitude and latitude values to api call doesn't work
Location
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
class Location{
double longitude;
double latitude;
Future<void> getCurrentLocation() async{
try{
Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.low);
longitude = position.longitude;
latitude = position.latitude;
print('Longitude: $longitude \n' +
'Latitude: $latitude');
}catch(e){
print(e);
}
}
}
Loading_screen class
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:clima/location.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class LoadingScreen extends StatefulWidget {
#override
_LoadingScreenState createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
var apiKey = 'secret';
double lat, lon;
#override
void initState() {
getLocation();
}
void getData() async{
var url = 'http://api.openweathermap.org/data/2.5/weather?lat=${lat}&${lon}&appid=$apiKey';
//var url = 'http://api.openweathermap.org/data/2.5/weather?lat=14.6102473&121.0043158&appid=secret';
//var url = 'http://api.openweathermap.org/data/2.5/weather?lat=14.6102473&lon=121.0043158&appid=secret';
var request = await http.get(url);
if(request.statusCode == 200){
String data = request.body.toString();
var city = jsonDecode(data)['name'];
var description = jsonDecode(data)['weather'][0]['description'];
print('Welcome to $city city!');
print('Weather: $description');
}else{
print(request.statusCode);
print('Latitude is: $lat *** Longitude is: $lon'); // this prints longitude and latitude values
print('request $url'); // when I entered the url in postman, I'm getting the same error 400
}
}
void getLocation() async{
Location location = new Location();
await location.getCurrentLocation();
lat = location.latitude;
lon = location.longitude;
getData();
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
You are missing the parameter name lon in your url.
Instead of:
var url = 'http://api.openweathermap.org/data/2.5/weather?lat=${lat}&${lon}&appid=$apiKey';
Write:
var url = 'http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=$apiKey';
Change that;
var url = 'http://api.openweathermap.org/data/2.5/weather?lat=${lat}&${lon}&appid=$apiKey';
with this;
var url = 'http://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=$apiKey';