-
Notifications
You must be signed in to change notification settings - Fork 252
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* feat: Add support for relative baseUrl in RestApi * docs: Add example project for relative baseUrl in RestApi
- Loading branch information
1 parent
7f5c050
commit 0e51fd2
Showing
11 changed files
with
384 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
include: package:lints/recommended.yaml | ||
analyzer: | ||
exclude: | ||
- lib/**/*.reflectable.dart | ||
- lib/**/*.g.dart |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
targets: | ||
$default: | ||
builders: | ||
reflectable: | ||
generate_for: | ||
- lib/json_mapper_example.dart |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import 'package:json_annotation/json_annotation.dart'; | ||
|
||
part 'api_result.g.dart'; | ||
|
||
@JsonSerializable(genericArgumentFactories: true) | ||
class ApiResult<T> { | ||
const ApiResult({ | ||
required this.code, | ||
required this.data, | ||
this.msg, | ||
}); | ||
|
||
factory ApiResult.fromJson( | ||
Map<String, dynamic> json, T Function(Object?) fromJsonT) => | ||
_$ApiResultFromJson(json, fromJsonT); | ||
|
||
///接口调用成功的code码 | ||
static const success = 0; | ||
static const unknown = -1; | ||
final int code; | ||
final T data; | ||
final String? msg; | ||
|
||
///业务接口执行成功 | ||
bool get isSuccess => code == success; | ||
|
||
Map<String, dynamic> toJson(Object? Function(T) toJsonT) => | ||
_$ApiResultToJson(this, toJsonT); | ||
|
||
@override | ||
String toString() => 'ApiResult{code: $code, data: $data, msg: $msg}'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import 'dart:convert'; | ||
import 'dart:io'; | ||
|
||
import 'package:dio/dio.dart' hide Headers; | ||
import 'package:http_parser/http_parser.dart'; | ||
import 'package:json_annotation/json_annotation.dart'; | ||
import 'package:retrofit/retrofit.dart'; | ||
import 'package:retrofit_example/api_result.dart'; | ||
|
||
part 'example.g.dart'; | ||
|
||
@RestApi(baseUrl: 'tasks') | ||
abstract class TasksRestClient { | ||
factory TasksRestClient(Dio dio, {String baseUrl}) = _TasksRestClient; | ||
|
||
@GET('/tasks/{id}') | ||
Future<List<Task?>> getTaskById(); | ||
|
||
@GET('/') | ||
Future<List<Task>> getTasks(); | ||
|
||
@GET('/{id}') | ||
Future<Task> getTask(@Path('id') String id); | ||
|
||
@PATCH('/tasks/{id}') | ||
Future<Task> updateTaskPart( | ||
@Path() String id, | ||
@Body() Map<String, dynamic> map, | ||
); | ||
|
||
@PUT('/tasks/{id}') | ||
Future<Task> updateTask(@Path() String id, @Body() Task task); | ||
|
||
@DELETE('/tasks/{id}') | ||
Future<void> deleteTask(@Path() String id); | ||
|
||
@POST('/tasks') | ||
Future<Task> createTask(@Body() Task task); | ||
|
||
@POST('/tasks') | ||
Future<List<Task>> createTasks(@Body() List<Task> tasks); | ||
} | ||
|
||
@JsonSerializable() | ||
class Task { | ||
const Task({ | ||
required this.id, | ||
required this.name, | ||
required this.avatar, | ||
required this.createdAt, | ||
}); | ||
|
||
factory Task.fromJson(Map<String, dynamic> json) => _$TaskFromJson(json); | ||
|
||
final String id; | ||
final String name; | ||
final String avatar; | ||
final String createdAt; | ||
|
||
Map<String, dynamic> toJson() => _$TaskToJson(this); | ||
} | ||
|
||
// ignore_for_file: constant_identifier_names | ||
enum Status { | ||
@JsonValue('new') | ||
New, | ||
@JsonValue('on_going') | ||
OnGoing, | ||
@JsonValue('closed') | ||
Closed, | ||
} | ||
|
||
@JsonSerializable() | ||
class TaskQuery { | ||
const TaskQuery(this.statuses); | ||
|
||
factory TaskQuery.fromJson(Map<String, dynamic> json) => | ||
_$TaskQueryFromJson(json); | ||
|
||
final List<Status> statuses; | ||
|
||
Map<String, dynamic> toJson() => _$TaskQueryToJson(this); | ||
} | ||
|
||
@JsonSerializable() | ||
class TaskGroup { | ||
const TaskGroup({ | ||
required this.date, | ||
required this.todos, | ||
required this.completed, | ||
required this.inProgress, | ||
}); | ||
|
||
factory TaskGroup.fromJson(Map<String, dynamic> json) => | ||
_$TaskGroupFromJson(json); | ||
|
||
final DateTime date; | ||
final List<Task> todos; | ||
final List<Task> completed; | ||
final List<Task> inProgress; | ||
|
||
Map<String, dynamic> toJson() => _$TaskGroupToJson(this); | ||
} | ||
|
||
@JsonSerializable(genericArgumentFactories: true) | ||
class ValueWrapper<T> { | ||
const ValueWrapper({required this.value}); | ||
|
||
factory ValueWrapper.fromJson( | ||
Map<String, dynamic> json, | ||
T Function(Object? json) fromJsonT, | ||
) => | ||
_$ValueWrapperFromJson(json, fromJsonT); | ||
|
||
final T value; | ||
|
||
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) => | ||
_$ValueWrapperToJson(this, toJsonT); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
dart: | ||
- dev | ||
|
||
stages: | ||
# Register two jobs to run under the `analyze` stage. | ||
- analyze: | ||
- dartanalyzer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
name: retrofit_example | ||
description: Retrofit generator | ||
version: 1.0.0 | ||
|
||
environment: | ||
sdk: '>=2.18.0 <3.0.0' | ||
|
||
dependencies: | ||
retrofit: | ||
json_annotation: | ||
logger: ^1.2.2 | ||
dio: ^5.0.1 | ||
http_parser: | ||
|
||
dev_dependencies: | ||
test: ^1.23.1 | ||
retrofit_generator: | ||
build_runner: ^2.3.3 | ||
json_serializable: ^6.6.1 | ||
mock_web_server: ^5.0.0-nullsafety.1 | ||
lints: ^2.0.1 | ||
|
||
dependency_overrides: | ||
retrofit: | ||
path: ../retrofit | ||
retrofit_generator: | ||
path: ../generator | ||
source_gen: ^1.2.7 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import 'package:dio/dio.dart'; | ||
import 'package:mock_web_server/mock_web_server.dart'; | ||
import 'package:retrofit_example/example.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
import 'task_data.dart'; | ||
|
||
late MockWebServer _server; | ||
late TasksRestClient _client; | ||
final _headers = {'Content-Type': 'application/json'}; | ||
final dispatcherMap = <String, MockResponse>{}; | ||
|
||
void main() { | ||
setUp(() async { | ||
_server = MockWebServer(); | ||
await _server.start(); | ||
final dio = Dio(BaseOptions(baseUrl: _server.url)); | ||
dio.interceptors.add(LogInterceptor(responseBody: true)); | ||
dio.interceptors.add(DateTimeInterceptor()); | ||
_client = TasksRestClient(dio); | ||
}); | ||
|
||
tearDown(() { | ||
_server.shutdown(); | ||
}); | ||
|
||
test('test empty task list', () async { | ||
_server.enqueue( | ||
body: demoEmptyListJson, headers: {'Content-Type': 'application/json'}); | ||
final tasks = await _client.getTasks(); | ||
expect(tasks, isNotNull); | ||
expect(tasks.length, 0); | ||
}); | ||
|
||
test('test task list', () async { | ||
_server.enqueue(body: demoTaskListJson, headers: _headers); | ||
final tasks = await _client.getTasks(); | ||
expect(tasks, isNotNull); | ||
expect(tasks.length, 1); | ||
}); | ||
|
||
test('test task detail', () async { | ||
_server.enqueue(headers: _headers, body: demoTaskJson); | ||
final task = await _client.getTask('id'); | ||
expect(task, isNotNull); | ||
expect(task.id, demoTask.id); | ||
expect(task.avatar, demoTask.avatar); | ||
expect(task.name, demoTask.name); | ||
expect(task.createdAt, demoTask.createdAt); | ||
}); | ||
|
||
test('create new task', () async { | ||
_server.enqueue(headers: _headers, body: demoTaskJson); | ||
final task = await _client.createTask(demoTask); | ||
expect(task, isNotNull); | ||
expect(task.id, demoTask.id); | ||
expect(task.avatar, demoTask.avatar); | ||
expect(task.name, demoTask.name); | ||
expect(task.createdAt, demoTask.createdAt); | ||
}); | ||
|
||
test('update task all content', () async { | ||
_server.enqueue(headers: _headers, body: demoTaskJson); | ||
final task = await _client.updateTask('id', demoTask); | ||
expect(task, isNotNull); | ||
expect(task.id, demoTask.id); | ||
expect(task.avatar, demoTask.avatar); | ||
expect(task.name, demoTask.name); | ||
expect(task.createdAt, demoTask.createdAt); | ||
}); | ||
|
||
test('update task part content', () async { | ||
_server.enqueue(headers: _headers, body: demoTaskJson); | ||
final task = await _client | ||
.updateTaskPart('id', <String, String>{'name': 'demo name 2'}); | ||
expect(task, isNotNull); | ||
expect(task.id, demoTask.id); | ||
expect(task.avatar, demoTask.avatar); | ||
expect(task.name, demoTask.name); | ||
expect(task.createdAt, demoTask.createdAt); | ||
}); | ||
|
||
test('delete a task', () async { | ||
_server.enqueue(); | ||
await _client.deleteTask('id').then((it) { | ||
expect(null, null); | ||
}); | ||
}); | ||
} | ||
|
||
class DateTimeInterceptor extends Interceptor { | ||
@override | ||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) { | ||
options.queryParameters = options.queryParameters.map((key, value) { | ||
if (value is DateTime) { | ||
//may be change to string from any you use object | ||
return MapEntry(key, value.toString()); | ||
} else { | ||
return MapEntry(key, value); | ||
} | ||
}); | ||
handler.next(options); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:retrofit_example/example.dart'; | ||
|
||
final demoTask = Task( | ||
id: '123455151', | ||
name: 'demo task', | ||
avatar: | ||
'https://p7.hiclipart.com/preview/312/283/679/avatar-computer-icons-user-profile-business-user-avatar.jpg', | ||
createdAt: '2017/09/08 21:35:19', | ||
); | ||
|
||
final demoTaskJson = jsonEncode(demoTask); | ||
final List<Task> demoTaskList = [demoTask]; | ||
final demoTaskListJson = jsonEncode(demoTaskList); | ||
final List<Task> demoEmptyList = []; | ||
final demoEmptyListJson = jsonEncode(demoEmptyList); | ||
|
||
final groupTask = TaskGroup( | ||
date: DateTime.now(), | ||
todos: demoTaskList, | ||
completed: demoTaskList, | ||
inProgress: demoEmptyList, | ||
); | ||
|
||
final groupTaskList = [groupTask]; | ||
final groupTaskListJson = jsonEncode(groupTaskList); |
Oops, something went wrong.