pass multiple params from flutter to node - mongodb

I need to pass multiple query params from flutter to node. Do you know the best way? I need to pass the city, date, location.
Here is my dart file
Future<Appointment> searchSingleAppointment({
required BuildContext context,
required String city,
required String date,
required String location,
}) async {
Appointment appointment = Appointment(id: '', city: '', date: '', location: '', appointmentStatus: '', queue: 0);
try {
http.Response res =
await http.get(Uri.parse('$uri/appointments/search/'),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
// 'x-auth-token': userProvider.user.token,
});
httpErrorHandle(
response: res,
context: context,
onSuccess: () {
appointment = Appointment.fromJson(res.body);
},
);
} catch (e) {
showSnackBar(context, e.toString());
}
return appointment;
}
}
and here's my node js file. I need those params so I can use them in my find()
appointmentRouter.get("/appointments/search/", async (req, res) => {
console.log(req.params);
try {
const appointment = await Appointment.find();
res.json(appointment);
} catch (e) {
res.status(500).json({ error: e.message });
}
});

Use queryParameters. Here is the example:
final queryParameters = {'search': 'blue', 'limit': '10'};
final uri = Uri.parse('https://example.com/page/').replace(queryParameters: queryParameters);
print(uri); // https://example.com/page/?search=blue&limit=10

Related

Connection closed before full header was received on http post in flutter

I'm trying to do a http post with the picture the user selects, when trying to make the http call, I get the error 'Connection closed before full header was received', I don't know how to fix it, the same error is happening on a real device.
This is also the documentation for the api, the body is form data.
class UploadVideoServices {
static Future<http.StreamedResponse> postProf({
required String imagePath,
required String title,
required bool isPayPerView,
required bool isDeleted,
required bool show,
required List<String> tags,
required String description,
}) async {
var headers = {'Authorization': 'Bearer ${prefs!.getString('token')}'};
var request = http.MultipartRequest(
'POST',
Uri.parse(
"http url/v1/postpic/634d0ebd2be78793c9474ae0/$title/$description/$show/$isPayPerView/$isDeleted/$tags"));
request.fields.addAll({
'file': imagePath,
});
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
return response;
}
}
=====
using the services
=====
postProf() async {
try {
var result = await UploadVideoServices.postProf(
imagePath: selectedImagePath.value,
title: 'ajanvideo',
isPayPerView: false,
isDeleted: false,
show: true,
tags: ['ajan', 'app'],
description: 'hey',
);
successSnackBar('Done', 'Posted prof');
return result;
} catch (e) {
errorSnackBar('Opps', e.toString());
print(e.toString());
}
}
======
void getImage(ImageSource imageSource) async {
try {
final pickedFile = await ImagePicker().pickImage(source: imageSource);
if (pickedFile != null) {
selectedImagePath.value = pickedFile.path;
}
print(selectedImagePath.value);
await postProf(); // using the method after getting image
} catch (e) {
errorSnackBar('Opps', 'Failed to get image');
}
}

Mockito dont follow 'when()' behavior (Dart/Flutter)

I'm trying to do unit tests, but mockito does not follow the behavior of 'when()' and returns a fake value from the generated code
when from test:
when(MockHttp.post(any)).thenAnswer(
(_) => Future.value(ReturnClass(data: {
'access_token': 'acess',
'token_type': 'token_type',
'expires_in': DateTime.now().add(Duration(hours: 1)).hour,
'scope': 'scope'
}, error: null, status: 0)),
);
Mock generated class:
_i6.Future<_i2.ReturnClass> post(String? path,
{Map<String, dynamic>? body,
Map<String, dynamic>? params,
Map<String, String>? headers}) =>
(super.noSuchMethod(
Invocation.method(
#post, [path], {#body: body, #params: params, #headers: headers}),
returnValue: Future<_i2.JdApiResponseDto>.value(
_FakeReturnClass_0())) as _i6.Future<_i2.ReturnClass>);
In the real function the return value is '_FakeReturnClass_0' instead of ReturnClass from 'when()'
I don't know why this is happening :(
Edit:
basically this is the test:
setUpAll(() {
when(service.post(any)).thenAnswer(
(_) => Future.value(
ReturnClass(data: {
'access_token': 'acess',
'token_type': 'token_type',
'expires_in': DateTime.now().add(Duration(hours: 1)).hour,
'scope': 'scope'
}, error: null, status: 0)),
);
}
group('Test Repository Token', () {
test('getToken should not let token be null', () async {
await _repository.getToken();
expect(_repository.token, isNotNull);
});
});
and that is my real function (it passes the mock of httpbut still not entering 'when()')
try {
var response = await http.post(
api.authUrl ?? '',
params: {
'grant_type': api.grantType,
'client_id': api.clientId,
'client_secret': api.clientSecret,
},
// headers: {
// IService.contentTypeHeader:
// IService.formUrlEncodedContentType,
// },
);
} catch (e) {
print('Token Error:');
print(e);
}
and when I test the real function there is a error because the mock is returning for the response the '_FakeReturnClass_0()' instead of ReturningClass that i put on the 'when()' in the setup of the test

How to pass data to cloud function file in flutter

I am new to flutter and I have just created app that accepts payments from user using flutter_stripe: ^2.1.0 plugin. The amount in cloud function file index.js is fixed but I want to pass the amount that is calculated dynamically. Here is my code.
Future<void> makePayment() async {
final url = Uri.parse(
'https://us-central1-carwashapp-376b6.cloudfunctions.net/stripePayment');
final response =
await http.get(url, headers: {"Content-Type": "application/json"});
paymentIntentData = json.decode(response.body);
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: paymentIntentData['paymentIntent'],
applePay: true,
googlePay: true,
style: ThemeMode.light,
merchantCountryCode: 'US',
merchantDisplayName: 'Kleen My Car',
),
);
setState(() {});
displayPaymentSheet();
}
Future<void> displayPaymentSheet() async {
try {
await Stripe.instance.presentPaymentSheet(
parameters: PresentPaymentSheetParameters(
clientSecret: paymentIntentData['paymentIntent'],
confirmPayment: true));
setState(() {
paymentIntentData = null;
});
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Payment succeeded')));
} catch (e) {
print('error error error');
}
}
and here is my index.js file's code
const functions = require("firebase-functions");
const stripe = require("stripe")(functions.config().stripe.testkey);
exports.stripePayment = functions.https.onRequest(async (req, res) => {
const paymentIntent = await stripe.paymentIntents.create(
{
amount: 120,
currency: "USD",
},
function (err, paymentIntent) {
if (err != null) {
console.log(err);
} else {
res.json({
paymentIntent: paymentIntent.client_secret,
});
}
}
);
});
Any kind of help is much appreciated. Thank you so much!
You need to adapt this line:
final response = await http.get(url, headers: {"Content-Type": "application/json"});
(Firstly, it makes no sense to give a content type on a GET, as GETs don't have any content. Remove that header.)
You could change to a POST and add the amount as a parameter, or leave it as a GET and add the amount to the URL.
With a POST, add (for example) body: {'amount': amount.toString()}
With a GET, add it to the URL, as follows:
final uri = Uri.https('us-central1-carwashapp-376b6.cloudfunctions.net', '/stripepayment', {'amount': amount.toString()});
In your cloud function access amount from the req. (For example, in the GET example, it would be req.query.amount as string.)
We also pass up other parameters like email, unique order id (to be used as the idempotency key), etc.
in index.js file change
const paymentIntent = await stripe.paymentIntents.create(
{
amount: 120,
currency: "USD",
},
to
const paymentIntent = await stripe.paymentIntents.create(
{
amount: req.query.amount,
currency: req.query.currency,
},
and deploy your function.
after that, in makepayment function, change your URL to
https://us-central1-carwashapp-376b6.cloudfunctions.net/stripePayment?amount=$amount&currency=$currency.
In this way, you can pass different amounts every time by changing the value of $amount variable in the URL.

mocking Dio is not working to test my app in Flutter

I am trying to write unit tests for my request with Dio but I keep getting this error:
type 'Null' is not a subtype of type 'BaseOptions'
I tried adding the base options on DioMock in a lot of different ways but the test remains the same.
How can I fix it?
Bellow are my Network class and the test class.
class NetworkService {
final Dio dio;
NetworkService(this.dio){
dio.options.baseUrl = "https://food2fork.ca/api/recipe/search";
dio.options.headers['Authorization'] = 'Token 9c8b06d329136da358c2d00e76946b0111ce2c48';
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler){
print('base ${options.baseUrl}');
print("PATH: ${options.path}");
return handler.next(options);
},
onResponse: (response, handler){
print("RESPONSE: ${response.statusCode} PATH: ${response.requestOptions.path}");
return handler.next(response);
},
onError: (DioError e, handler){
print("ERROR: ${e.response?.statusCode} => PATH: ${e.requestOptions.path}");
return handler.next(e);
}
));
}
Future<List<Recipe>> getRecipe() async {
var response = await dio.get('/?page=1&query=beef');
print("response ${response.data}");
if(response.statusCode == 200){
final List<Recipe> recipeList = [];
for(Map<String, dynamic> recipe in response.data['results']){
recipeList.add(Recipe.fromJson(recipe));
}
return recipeList;
} else {
throw Exception('sss');
}
// ONBOARDING
}
}
class DioMock extends Mock implements DioForNative {}
class RecipeMock extends Mock implements Recipe {}
main() {
final dio = DioMock();
final service = NetworkService(dio);
dio.options.baseUrl = "https://food2fork.ca/api/recipe/search";
dio.options.headers = { 'Content-type': 'application/json', 'Accept': 'application/json' };
test("should return Onboarding Model", () async {
final response = Response(
requestOptions: RequestOptions(
path: 'gfh',
baseUrl: "fgh"
),
data: RecipeMock()
);
when(dio.get(
"https://food2fork.ca/api/recipe/search"))
.thenAnswer((_) async => response);
final result = await service.getRecipe();
expect(result, isA<Recipe>());
});
}
You should use https://pub.dev/packages/http_mock_adapter package to help you mock your DIO requests
See its example https://github.com/lomsa-dev/http-mock-adapter/blob/main/example/main.dart :
void main() async {
late Dio dio;
late DioAdapter dioAdapter;
Response<dynamic> response;
group('Accounts', () {
const baseUrl = 'https://example.com';
const userCredentials = <String, dynamic>{
'email': 'test#example.com',
'password': 'password',
};
setUp(() {
dio = Dio(BaseOptions(baseUrl: baseUrl));
dioAdapter = DioAdapter(dio: dio);
});
test('signs up user', () async {
const route = '/signup';
dioAdapter.onPost(
route,
(server) => server.reply(201, null),
data: userCredentials,
);
// Returns a response with 201 Created success status response code.
response = await dio.post(route, data: userCredentials);
expect(response.statusCode, 201);
});
...
final dioError = DioError(
error: {'message': 'Some beautiful error!'},
requestOptions: RequestOptions(path: path),
response: Response(
statusCode: 500,
requestOptions: RequestOptions(path: path),
),
type: DioErrorType.response,
);
test("should return a DioError", () async {
dioAdapter.onGet(
path,
(server) {
server.throws(404, dioError );
});
final result = await service.getOnboardingAnswer("lastAnswerId");
expect(result, throwsA(isA<DioError>()));
});
}
});

how to pass access token in a http request with flutter?

i would like to create a campaign using marketing API, here is the Curl code, i want to transform into an http post request:
AND MY HTTP REQUEST with the model class
Future<Campaign> createCampaign(String name,String objective,String
status) async {
final http.Response response = await http.post(
'https://graph.facebook.com/v7.0/act_<AD_ACCOUNT_ID>/campaigns',
headers: {HttpHeaders.authorizationHeader: "Basic },
body: jsonEncode(<String, String>{
'name': name,
'objective': objective,
'status': status
}),
);
if (response.statusCode == 201) {
return Campaign.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to create Campaign.');
}
}
class Campaign {
final String name;
final String objective;
final String status;
final Map <String,dynamic> special_ad_categories;
final Map<String,dynamic> access_token;
Campaign({this.name,this.objective,this.status,this.special_ad_categories,
this.access_token});
factory Campaign.fromJson(Map<String, dynamic> json) {
return Campaign(
name: json['name'],
objective: json['objective'],
status: json['status'],
special_ad_categories: json['special_ad_categories'],
access_token: json['access_token'],
);
}
}
Try using dio package. It has API to send form data.
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart' as dio;
const AD_ACCOUNT_ID = '...';
const ACCESS_TOKEN = '...';
Future<Campaign> createCampaign(String name, String objective, String status, String categories) async {
try {
final formData = dio.FormData.fromMap({
'name': name,
'objective': objective,
'status': status,
'special_ad_categories': categories,
'access_token': ACCESS_TOKEN
});
final response = await dio.Dio().post(
'https://graph.facebook.com/v7.0/act_$AD_ACCOUNT_ID/campaigns',
data: formData,
);
if (response.statusCode == HttpStatus.created) {
return Campaign.fromJson(jsonDecode(response.data));
} else {
throw Exception('Failed to create Campaign.');
}
} on dio.DioError {
throw Exception('Failed to create Campaign.');
}
}
// example of calling: createCampaign('test', 'LINK_CLICKS', 'PAUSED', 'NONE');
Don't forget to replace AD_ACCOUNT_ID and ACCESS_TOKEN.
All parameters are in body. Try like this:
Future<http.Response> fetchAlbum() {
return http.post(
'https://your-url',
body: {
'name': name,
'objective': objective,
'status': status,
'special_ad_categories': [],
'access_token': accessToken,
},
);
}
I think you missed the account id in
'https://graph.facebook.com/v7.0/act_<AD_ACCOUNT_ID>/campaigns'