Skip to content

Commit 6ce5555

Browse files
committed
Add form Data handling
1 parent f33061e commit 6ce5555

File tree

5 files changed

+220
-47
lines changed

5 files changed

+220
-47
lines changed

CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
# 0.0.5-dev
1+
## 0.0.1
2+
3+
- Add formData handling
4+
- Update readme
5+
6+
## 0.0.6-dev
7+
8+
- Fix
9+
10+
## 0.0.5-dev
211

312
- Fix const error
413

README.md

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,55 @@
1-
# flutter_feathersjs
1+
# flutter_feathersjs :bird:
22

3-
Communicate with you feathers js server from flutter.
3+
Communicate with your feathers js server from flutter.
4+
*__FormData support out the box, auth, reAuth, socketio send event, rest ...__ But event listen via socketio not yet implemented*
45

5-
## :warning: UNDER ACTIVE DEV
66

7-
## TODO
7+
## Import it
88

9-
- [x] Write auth for rest
10-
- [x] Write reAuth for rest
11-
- [x] Write rest client method (feathers js service methods)
12-
- [ ] Handle formData on rest
9+
```dart
10+
import 'package:flutter_feathersjs/flutter_feathersjs.dart';
1311
14-
- [X] Write auth for socket
15-
- [X] Write reAuth for socket
16-
- [X] Write socket client method (feathers js service methods)
17-
- [ ] Handle formData on socket
18-
- [ ] Write an unique flutter_feathersjs plugin which won't mater if you calling service via rest or sock
19-
- [ ] Write doc
12+
```
13+
14+
## Init
15+
16+
```dart
17+
FlutterFeathersjs flutterFeathersjs = FlutterFeathersjs()
18+
..init(baseUrl: BASE_URL);
19+
20+
```
21+
22+
## Authentication with either with rest or socketio
23+
24+
```dart
25+
// Auth with rest client
26+
var authResponse = await flutterFeathersjs.rest
27+
.authenticate(email: user["email"], password: user["password"]);
28+
29+
//Second time, application will restart, just:
30+
var reAuthResponse = await flutterFeathersjs.rest.reAuthenticate();
31+
32+
// Or With socketio
33+
// Note: This must be call after rest auth success
34+
var authResponse = await flutterFeathersjs.scketio.authWithJWT();
35+
36+
```
37+
38+
## Simplify yor life, Auth both client one time
39+
40+
```dart
41+
42+
// Auth first time with credentials
43+
var authResponse = await flutterFeathersjs.authenticate(email: null, password: null);
44+
45+
// on App restart, don't disturbe user, just reAuth with with accessToken, early store by FlutterFeathersjs
46+
var reAuthResponse = await flutterFeathersjs.reAuthenticate()
47+
48+
```
49+
50+
## Important
51+
52+
- Listen to event on socketio is not yet implemented
53+
- Documentation is coming
54+
- Contact-me for improvment or contribution purpose
55+
- Example is coming

lib/src/rest_client.dart

Lines changed: 132 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class RestClient extends FlutterFeathersjs {
1212
Dio dio;
1313
Utils utils;
1414

15-
//Using singleton to ensure we the same instance of it
15+
//Using singleton to ensure we use the same instance of it
1616
static final RestClient _restClient = RestClient._internal();
1717
factory RestClient() {
1818
return _restClient;
@@ -200,27 +200,71 @@ class RestClient extends FlutterFeathersjs {
200200
/// POST /serviceName
201201
/// Create a new resource with data.
202202
Future<Response<dynamic>> create(
203-
{String serviceName, Map<String, dynamic> data}) async {
204-
var response;
205-
try {
206-
response = response = await this.dio.post("/$serviceName", data: data);
207-
} catch (e) {
208-
print("Error in rest::create");
209-
print(e);
203+
{String serviceName,
204+
Map<String, dynamic> data,
205+
containsFile = false,
206+
hasSingleFile = true,
207+
fileFieldName = "file",
208+
List<Map<String, String>> files}) async {
209+
Response<dynamic> response;
210+
211+
if (!containsFile) {
212+
try {
213+
response = await this.dio.post("/$serviceName", data: data);
214+
} catch (e) {
215+
print("Error in rest::create");
216+
print(e);
217+
}
218+
} else {
219+
FormData formData = await this.makeFormData(
220+
hasSingleFile: hasSingleFile,
221+
nonFilesFieldsMap: data,
222+
fileFieldName: fileFieldName,
223+
files: files);
224+
try {
225+
response = await this.dio.post("/$serviceName", data: formData);
226+
} catch (e) {
227+
print("Error in rest::create::with:file");
228+
print(e);
229+
}
210230
}
211231
return response;
212232
}
213233

214234
/// PUT /serviceName/_id
215235
/// Completely replace a single resource.
216236
Future<Response<dynamic>> update(
217-
{String serviceName, objectId, Map<String, dynamic> data}) async {
218-
var response;
219-
try {
220-
response = await this.dio.put("/$serviceName" + "/$objectId", data: data);
221-
} catch (e) {
222-
print("Error in rest::update");
223-
print(e);
237+
{String serviceName,
238+
objectId,
239+
Map<String, dynamic> data,
240+
containsFile = false,
241+
hasSingleFile = true,
242+
fileFieldName = "file",
243+
List<Map<String, String>> files}) async {
244+
Response<dynamic> response;
245+
246+
if (!containsFile) {
247+
try {
248+
response =
249+
await this.dio.put("/$serviceName" + "/$objectId", data: data);
250+
} catch (e) {
251+
print("Error in rest::update");
252+
print(e);
253+
}
254+
} else {
255+
FormData formData = await this.makeFormData(
256+
hasSingleFile: hasSingleFile,
257+
nonFilesFieldsMap: data,
258+
fileFieldName: fileFieldName,
259+
files: files);
260+
try {
261+
response = await this
262+
.dio
263+
.patch("/$serviceName" + "/$objectId", data: formData);
264+
} catch (e) {
265+
print("Error in rest::update::with:file");
266+
print(e);
267+
}
224268
}
225269
return response;
226270
}
@@ -229,15 +273,39 @@ class RestClient extends FlutterFeathersjs {
229273
/// Merge the existing data of a single resources with the new data.
230274
/// NOT TESTED
231275
Future<Response<dynamic>> patch(
232-
{String serviceName, objectId, Map<String, dynamic> data}) async {
233-
var response;
234-
try {
235-
response =
236-
await this.dio.patch("/$serviceName" + "/$objectId", data: data);
237-
} catch (e) {
238-
print("Error in rest::patch");
239-
print(e);
276+
{String serviceName,
277+
objectId,
278+
Map<String, dynamic> data,
279+
containsFile = false,
280+
hasSingleFile = true,
281+
fileFieldName = "file",
282+
List<Map<String, String>> files}) async {
283+
Response<dynamic> response;
284+
285+
if (!containsFile) {
286+
try {
287+
response =
288+
await this.dio.patch("/$serviceName" + "/$objectId", data: data);
289+
} catch (e) {
290+
print("Error in rest::patch");
291+
print(e);
292+
}
293+
} else {
294+
FormData formData = await this.makeFormData(
295+
hasSingleFile: hasSingleFile,
296+
nonFilesFieldsMap: data,
297+
fileFieldName: fileFieldName,
298+
files: files);
299+
try {
300+
response = await this
301+
.dio
302+
.patch("/$serviceName" + "/$objectId", data: formData);
303+
} catch (e) {
304+
print("Error in rest::patch::with:file");
305+
print(e);
306+
}
240307
}
308+
241309
return response;
242310
}
243311

@@ -255,4 +323,45 @@ class RestClient extends FlutterFeathersjs {
255323
}
256324
return response;
257325
}
326+
327+
///@var fieldsMap: other field non file
328+
///@var hasSingleFile: true for signle file , false otherwise
329+
///@ fileFieldName: the file | files field which must be send to the server
330+
///@var files: a List map of {"filePath": the file path, "fileName": the file ame}
331+
///if hasSingleFile is true, just the file first entry of the list otherwise looping through the
332+
///list
333+
Future<FormData> makeFormData(
334+
{Map<String, dynamic> nonFilesFieldsMap,
335+
hasSingleFile = true,
336+
fileFieldName = "file",
337+
List<Map<String, String>> files}) async {
338+
var formData = FormData();
339+
340+
// Non file
341+
if (nonFilesFieldsMap != null) {
342+
nonFilesFieldsMap.forEach((key, value) {
343+
formData.fields..add(MapEntry(key, value));
344+
});
345+
}
346+
347+
if (hasSingleFile) {
348+
//File
349+
var fileData = files[0];
350+
formData.files.add(MapEntry(
351+
fileFieldName,
352+
await MultipartFile.fromFile(fileData["filePath"],
353+
filename: fileData["fileName"]),
354+
));
355+
} else {
356+
// Non file
357+
for (var fileData in files) {
358+
formData.files.add(MapEntry(
359+
fileFieldName,
360+
await MultipartFile.fromFile(fileData["filePath"],
361+
filename: fileData["fileName"]),
362+
));
363+
}
364+
}
365+
return formData;
366+
}
258367
}

pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: flutter_feathersjs
2-
description: Communicate with you feathers js server from flutter.
3-
version: 0.0.5-dev
2+
description: Communicate with your feathers js server from flutter.
3+
version: 0.0.1
44
homepage: https://github.com/Dahkenangnon/flutter_feathersjs.dart
55
repository: https://github.com/Dahkenangnon/flutter_feathersjs.dart
66

test/feathersjs_test.dart

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,13 @@ void main() async {
2727
.authenticate(email: user["email"], password: user["password"]);
2828
//Then use this one to reuse access token as it still valide
2929
//var reAuthResp = await flutterFeathersjs.rest.reAuthenticate();
30-
3130
// //////////////////////////////////////////////////
3231
// /
3332
// / Singleton testing
3433
// /
3534
// //////////////////////////////////////////////////
3635

37-
//Singleton pattern if the flutterFeathersjs class
36+
// Singleton pattern if the flutterFeathersjs class
3837
test('Testing singleton ', () {
3938
FlutterFeathersjs flutterFeathersjs1 = FlutterFeathersjs();
4039
expect(identical(flutterFeathersjs1, flutterFeathersjs), true);
@@ -108,6 +107,30 @@ void main() async {
108107
print(rep2.data);
109108
});
110109

110+
test(' \n Rest create news with image (FormData support testing) \n ',
111+
() async {
112+
var data2Send = {
113+
"title": "formdata testing",
114+
"content": "yo",
115+
"by": "5f9aceba20bc3d3a74b7bf8b",
116+
"enterprise": "5f9acf4f20bc3d3a74b7bf91"
117+
};
118+
119+
var files = [
120+
{"filePath": "spin.PNG", "fileName": "spin.PNG"}
121+
];
122+
123+
var rep2 = await flutterFeathersjs.rest.create(
124+
serviceName: "v1/news",
125+
data: data2Send,
126+
containsFile: true,
127+
hasSingleFile: true,
128+
fileFieldName: "file",
129+
files: files);
130+
print("\n The new news menu created is: \n");
131+
print(rep2.data);
132+
});
133+
111134
//////////////////////////////////////////////////
112135
//
113136
// Scketio client methods
@@ -123,12 +146,8 @@ void main() async {
123146
expect(identical(so1, so2), true);
124147
});
125148

126-
//Testing the authentication with jwt method
149+
// //Testing the authentication with jwt method
127150
test('socketio reAuthentication method', () async {
128-
//SocketioClient socketioClient = new SocketioClient(baseUrl: BASE_URL);
129-
130-
// var reps = await flutterFeathersjs.scketio
131-
// .authenticate(email: user['email'], password: user["password"]);
132151
var repss = await flutterFeathersjs.scketio.authWithJWT();
133152

134153
//print(reps);

0 commit comments

Comments
 (0)