Skip to content

Commit

Permalink
Merge develop in master (lejard-h#139)
Browse files Browse the repository at this point in the history
* GZip note

* Update faq.md

* CR fixes

* Moved to the faq.md

* HTTP Auth example

* CR fix

* CR fix

* Base url note

Runtime base url note update

Update faq.md

Co-authored-by: Ivan Terekhin <[email protected]>
Co-authored-by: Juhos István <[email protected]>
  • Loading branch information
3 people authored May 8, 2020
1 parent 0a9f5cf commit b9b1319
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 4 deletions.
3 changes: 1 addition & 2 deletions converters/converters.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ abstract class TodosListService extends ChopperService {
}
Response<T> convertResponse<T>(Response res) =>
Response<T> convertResponse<T>(Response res) =>
JsonConverter().convertResponse(res);
```

111 changes: 109 additions & 2 deletions faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ If you have this error, you probably forgot to run the `build` package. To do th

`pub run build_runner build`

It will generate the code that actually do the HTTP request \(YOUR\_FILE.chopper.dart\). If you wish to update the code automatically when you change your definition run the `watch` command.
It will generate the code that actually do the HTTP request \(YOUR_FILE.chopper.dart\). If you wish to update the code automatically when you change your definition run the `watch` command.

`pub run build_runner watch`

Expand Down Expand Up @@ -44,6 +44,86 @@ Request _addQuery(Request req) {
}
```

## GZip converter example

You can use converters for modifying requests and responses.
For example, to use GZip for post request you can write something like this:

```dart
Request compressRequest(Request request) {
request = applyHeader(request, 'Content-Encoding', 'gzip');
request = request.replace(body: gzip.encode(request.body));
return request;
}
...
@FactoryConverter(request: compressRequest)
@Post()
Future<Response> postRequest(@Body() Map<String, String> data);
```

## Runtime baseUrl change

You may need to change the base URL of your network calls during runtime, for example, if you have to use different servers or routes dynamically in your app in case of a "regular" or a "paid" user. You can store the current server base url in your SharedPreferences (encrypt/decrypt it if needed) and use it in an interceptor like this:

```dart
...
(Request request) async =>
SharedPreferences.containsKey('baseUrl')
? request.copyWith(
baseUrl: SharedPreferences.getString('baseUrl'))
: request
...
```

## Mock ChopperClient for testing

Chopper is built on top of `http` package.

So, one can just use the mocking API of the HTTP package.
https://pub.dev/documentation/http/latest/testing/MockClient-class.html

Also, you can follow this code by [ozburo](https://github.com/ozburo):

```dart
import 'dart:convert';
import 'package:chopper/chopper.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
part 'api_service.chopper.dart';
@ChopperApi()
abstract class ApiService extends ChopperService {
static ApiService create() {
final client = ChopperClient(
client: MockClient((request) async {
Map result = mockData[request.url.path]?.firstWhere((mockQueryParams) {
if (mockQueryParams['id'] == request.url.queryParameters['id']) return true;
return false;
}, orElse: () => null);
if (result == null) {
return http.Response(
json.encode({'error': "not found"}), 404);
}
return http.Response(json.encode(result), 200);
}),
baseUrl: 'https://mysite.com/api',
services: [
_$ApiService(),
],
converter: JsonConverter(),
errorConverter: JsonConverter(),
);
return _$ApiService(client);
}
@Get(path: "/get")
Future<Response> get(@Query() String url);
}
```

## Use Https certificate

Chopper is built on top of `http` package and you can override the inner http client.
Expand All @@ -53,11 +133,38 @@ import 'dart:io';
import 'package:http/io_client.dart' as http;
final ioc = new HttpClient();
ioc.badCertificateCallback = (X509Certificate cert, String host, int port)
ioc.badCertificateCallback = (X509Certificate cert, String host, int port)
=> true;
final chopper = ChopperClient(
client: http.IOClient(ioc),
);
```

## Authorized HTTP requests

Basically, the algorithm goes like this (credits to [stewemetal](https://github.com/stewemetal)):

Add the authentication token to the request (by "Authorization" header, for example) -> try the request -> if it fails use the refresh token to get a new auth token ->
if that succeeds, save the auth token and retry the original request with it
if the refresh token is not valid anymore, drop the session (and navigate to the login screen, for example)

Simple code example:

```dart
interceptors: [
// Auth Interceptor
(Request request) async => applyHeader(request, 'authorization',
SharedPrefs.localStorage.getString(tokenHeader),
override: false),
(Response response) async {
if (response?.statusCode == 401) {
SharedPrefs.localStorage.remove(tokenHeader);
// Navigate to some login page or just request new token
}
return response;
},
]
```

The actual implementation of the algorithm above may vary based on how the backend API - more precisely the login and session handling - of your app looks like.

0 comments on commit b9b1319

Please sign in to comment.