/
HttpHelper.dart
155 lines (136 loc) · 4.64 KB
/
HttpHelper.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';
import 'package:openfoodfacts/model/UserAgent.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:openfoodfacts/utils/UriReader.dart';
import 'package:path/path.dart';
import 'OpenFoodAPIConfiguration.dart';
import 'QueryType.dart';
/// General functions for sending http requests (post, get, multipart, ...)
class HttpHelper {
/// Gets the instance
static HttpHelper get instance => _instance ??= HttpHelper.internal();
static HttpHelper? _instance;
@visibleForTesting
static set instance(HttpHelper value) => _instance = value;
factory HttpHelper() => instance;
@protected
/// A protected constructor to allow subclasses to create themselves.
HttpHelper.internal();
static const String USER_AGENT = 'Dart API';
static const String FROM = 'anonymous';
/// Send a http get request to the specified uri.
/// The data of the request (if any) has to be provided as parameter within the uri.
/// The result of the request will be returned as string.
/// By default the query will hit the PROD DB
Future<http.Response> doGetRequest(
Uri uri, {
User? user,
QueryType? queryType,
}) async {
http.Response response = await http.get(
uri,
headers: _buildHeaders(
user: user,
isTestModeActive:
OpenFoodAPIConfiguration.getQueryType(queryType) == QueryType.PROD
? false
: true,
),
);
return response;
}
/// Send a http post request to the specified uri.
/// The data / body of the request has to be provided as map. (key, value)
/// The result of the request will be returned as string.
Future<http.Response> doPostRequest(
Uri uri,
Map<String, String?> body,
User? user, {
QueryType? queryType,
}) async {
http.Response response = await http.post(
uri,
headers: _buildHeaders(
user: user,
isTestModeActive:
OpenFoodAPIConfiguration.getQueryType(queryType) == QueryType.PROD
? false
: true),
body: body,
);
return response;
}
/// Send a multipart post request to the specified uri.
/// The data / body of the request has to be provided as map. (key, value)
/// The files to send have to be provided as map containing the source file uri.
/// As result a json object of the "type" Status is expected.
Future<Status> doMultipartRequest(
Uri uri,
Map<String, String> body, {
Map<String, Uri>? files,
User? user,
QueryType? queryType,
}) async {
var request = http.MultipartRequest('POST', uri);
request.headers.addAll(
_buildHeaders(
user: user,
isTestModeActive:
OpenFoodAPIConfiguration.getQueryType(queryType) == QueryType.PROD
? false
: true,
) as Map<String, String>,
);
request.headers.addAll({'Content-Type': 'multipart/form-data'});
request.fields.addAll(body);
// add all file entries to the request
if (files != null) {
for (MapEntry<String, Uri> entry in files.entries) {
List<int> fileBytes =
await UriReader.instance!.readAsBytes(entry.value);
var multipartFile = http.MultipartFile.fromBytes(entry.key, fileBytes,
filename: basename(entry.value.toString()));
request.files.add(multipartFile);
}
}
// get the response status
Status status = await request.send().then((response) {
if (response.statusCode == 200) {
return response.stream.first.then((responseBody) {
try {
return Status.fromJson(json.decode(utf8.decode(responseBody)));
} catch (e) {
//When the server returns html instead of json
return Status(status: 200, body: utf8.decode(responseBody));
}
});
} else {
return Status(
status: response.statusCode, error: response.reasonPhrase);
}
});
return status;
}
/// build the request headers
/// By default isTestMode is false
Map<String, String>? _buildHeaders({
User? user,
bool isTestModeActive = false,
}) {
Map<String, String>? headers = {};
headers.addAll({
'Accept': 'application/json',
'UserAgent':
OpenFoodAPIConfiguration.userAgent?.toValueString() ?? USER_AGENT,
'From': OpenFoodAPIConfiguration.getUser(user)?.toValueString() ?? FROM,
});
if (isTestModeActive) {
var token = 'Basic ' + base64Encode(utf8.encode('off:off'));
headers.addAll({'authorization': token});
}
return headers;
}
}