Skip to content

Commit

Permalink
📝 Improved documentation + added const annotations (#548)
Browse files Browse the repository at this point in the history
  • Loading branch information
Guldem committed Jan 5, 2024
1 parent 6420778 commit 2dc868f
Show file tree
Hide file tree
Showing 8 changed files with 348 additions and 58 deletions.
127 changes: 127 additions & 0 deletions chopper/lib/src/annotations.dart

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions chopper/lib/src/http_logging_interceptor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ enum Level {
body,
}

/// {@template http_logging_interceptor}
/// A [RequestInterceptor] and [ResponseInterceptor] implementation which logs
/// HTTP request and response data.
///
Expand All @@ -70,9 +71,11 @@ enum Level {
/// leak sensitive information, such as `Authorization` headers and user data
/// in response bodies. This interceptor should only be used in a controlled way
/// or in a non-production environment.
/// {@endtemplate}
@immutable
class HttpLoggingInterceptor
implements RequestInterceptor, ResponseInterceptor {
/// {@macro http_logging_interceptor}
HttpLoggingInterceptor({this.level = Level.body, Logger? logger})
: _logger = logger ?? chopperLogger,
_logBody = level == Level.body,
Expand Down
9 changes: 9 additions & 0 deletions chopper/lib/src/interceptor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,17 @@ abstract interface class ErrorConverter {
FutureOr<Response> convertError<BodyType, InnerType>(Response response);
}

/// {@template HeadersInterceptor}
/// A [RequestInterceptor] that adds [headers] to every request.
///
/// Note that this interceptor will overwrite existing headers having the same
/// keys as [headers].
/// {@endtemplate}
@immutable
class HeadersInterceptor implements RequestInterceptor {
final Map<String, String> headers;

/// {@macro HeadersInterceptor}
const HeadersInterceptor(this.headers);

@override
Expand Down Expand Up @@ -163,6 +166,7 @@ class CurlInterceptor implements RequestInterceptor {
}
}

/// {@template JsonConverter}
/// A [Converter] implementation that calls [json.encode] on [Request]s and
/// [json.decode] on [Response]s using the [dart:convert](https://api.dart.dev/stable/2.10.3/dart-convert/dart-convert-library.html)
/// package's [utf8] and [json] utilities.
Expand All @@ -176,8 +180,10 @@ class CurlInterceptor implements RequestInterceptor {
/// If content type header is modified (for example by using
/// `@Post(headers: {'content-type': '...'})`), `JsonConverter` won't add the
/// header and it won't call json.encode if content type is not JSON.
/// {@endtemplate}
@immutable
class JsonConverter implements Converter, ErrorConverter {
/// {@macro JsonConverter}
const JsonConverter();

@override
Expand Down Expand Up @@ -270,13 +276,16 @@ class JsonConverter implements Converter, ErrorConverter {
}
}

/// {@template FormUrlEncodedConverter}
/// A [Converter] implementation that converts only [Request]s having a [Map] as their body.
///
/// This `Converter` also adds the `content-type: application/x-www-form-urlencoded`
/// header to each request, but only if the `content-type` header is not set in
/// the original request.
/// {@endtemplate}
@immutable
class FormUrlEncodedConverter implements Converter, ErrorConverter {
/// {@macro FormUrlEncodedConverter}
const FormUrlEncodedConverter();

@override
Expand Down
3 changes: 3 additions & 0 deletions chopper/lib/src/request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import 'package:equatable/equatable.dart' show EquatableMixin;
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';

/// {@template request}
/// This class represents an HTTP request that can be made with Chopper.
/// {@endtemplate}
base class Request extends http.BaseRequest with EquatableMixin {
final Uri uri;
final Uri baseUri;
Expand All @@ -17,6 +19,7 @@ base class Request extends http.BaseRequest with EquatableMixin {
final bool useBrackets;
final bool includeNullQueryVars;

/// {@macro request}
Request(
String method,
this.uri,
Expand Down
3 changes: 3 additions & 0 deletions chopper/lib/src/response.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:equatable/equatable.dart' show EquatableMixin;
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';

/// {@template response}
/// A [http.BaseResponse] wrapper representing a response of a Chopper network call.
///
/// ```dart
Expand All @@ -16,6 +17,7 @@ import 'package:meta/meta.dart';
/// @Get(path: '/items/{id}')
/// Future<Response<Item>> fetchItem();
/// ```
/// {@endtemplate}
@immutable
base class Response<BodyType> with EquatableMixin {
/// The [http.BaseResponse] from `package:http` that this [Response] wraps.
Expand All @@ -31,6 +33,7 @@ base class Response<BodyType> with EquatableMixin {
/// The body of the response if [isSuccessful] is false.
final Object? error;

/// {@macro response}
const Response(this.base, this.body, {this.error});

/// Makes a copy of this Response, replacing original values with the given ones.
Expand Down
44 changes: 40 additions & 4 deletions faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ The actual implementation of the algorithm above may vary based on how the backe
### Authorized HTTP requests using the special Authenticator interceptor

Similar to OkHTTP's [authenticator](https://github.com/square/okhttp/blob/480c20e46bb1745e280e42607bbcc73b2c953d97/okhttp/src/main/kotlin/okhttp3/Authenticator.kt),
the idea here is to provide a reactive authentication in the event that an auth challenge is raised. It returns a
the idea here is to provide a reactive authentication in the event that an auth challenge is raised. It returns a
nullable Request that contains a possible update to the original Request to satisfy the authentication challenge.

```dart
Expand Down Expand Up @@ -223,7 +223,7 @@ final client = ChopperClient(
## Decoding JSON using Isolates

Sometimes you want to decode JSON outside the main thread in order to reduce janking. In this example we're going to go
even further and implement a Worker Pool using [Squadron](https://pub.dev/packages/squadron/install) which can
even further and implement a Worker Pool using [Squadron](https://pub.dev/packages/squadron/install) which can
dynamically spawn a maximum number of Workers as they become needed.

#### Install the dependencies
Expand Down Expand Up @@ -259,7 +259,7 @@ Extracted from the [full example here](example/lib/json_decode_service.dart).

#### Write a custom JsonConverter

Using [json_serializable](https://pub.dev/packages/json_serializable) we'll create a [JsonConverter](https://github.com/lejard-h/chopper/blob/master/chopper/lib/src/interceptor.dart#L228)
Using [json_serializable](https://pub.dev/packages/json_serializable) we'll create a [JsonConverter](https://github.com/lejard-h/chopper/blob/master/chopper/lib/src/interceptor.dart#L228)
which works with or without a [WorkerPool](https://github.com/d-markey/squadron#features).

```dart
Expand Down Expand Up @@ -412,4 +412,40 @@ This barely scratches the surface. If you want to know more about [squadron](htt
[squadron_builder](https://github.com/d-markey/squadron_builder) make sure to head over to their respective repositories.

[David Markey](https://github.com/d-markey]), the author of squadron, was kind enough as to provide us with an [excellent Flutter example](https://github.com/d-markey/squadron_builder) using
both packages.
both packages.

## How to use Chopper with [Injectable](https://pub.dev/packages/injectable)

### Create a module for your ChopperClient

Define a module for your ChopperClient. You can use the `@lazySingleton` (or other type if preferred) annotation to make sure that only one is created.

```dart
@module
abstract class ChopperModule {
@lazySingleton
ChopperClient get chopperClient =>
ChopperClient(
baseUrl: 'https://base-url.com',
converter: JsonConverter(),
);
}
```

### Create ChopperService with Injectable

Define your ChopperService as usual. Annotate the class with `@lazySingleton` (or other type if preferred) and use the `@factoryMethod` annotation to specify the factory method for the service. This would normally be the static create method.

```dart
@lazySingleton
@ChopperApi(baseUrl: '/todos')
abstract class TodosListService extends ChopperService {
@factoryMethod
static TodosListService create(ChopperClient client) => _$TodosListService(client);
@Get()
Future<Response<List<Todo>>> getTodos();
}
```
14 changes: 11 additions & 3 deletions getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ Run `pub get` to start using Chopper in your project.

### ChopperApi

To define a client, use the `@
ChopperApi` annotation on an abstract class that extends the `ChopperService` class.
To define a client, use the `@ChopperApi` annotation on an abstract class that extends the `ChopperService` class.

```dart
// YOUR_FILE.dart
Expand Down Expand Up @@ -66,7 +65,9 @@ Use one of the following annotations on abstract methods of a service class to d

* `@Head`

Request methods must return with values of the type `Future<Response>` or `Future<Response<SomeType>>`.
Request methods must return with values of the type `Future<Response>`, `Future<Response<SomeType>>` or `Future<SomeType>`.
The `Response` class is a wrapper around the HTTP response that contains the response body, the status code and the error (if any) of the request.
This class can be omitted if only the response body is needed. When omitting the `Response` class, the request will throw an exception if the response status code is not in the range of `< 200` to ` > 300`.

To define a `GET` request to the endpoint `/todos` in the service class above, add one of the following method declarations to the class:

Expand All @@ -82,6 +83,13 @@ or
Future<Response<List<Todo>>> getTodos();
```

or

```dart
@Get()
Future<List<Todo>> getTodos();
```

URL manipulation with dynamic path, and query parameters is also supported. To learn more about URL manipulation with Chopper, have a look at the [Requests](requests.md) section of the documentation.

## Defining a ChopperClient
Expand Down

0 comments on commit 2dc868f

Please sign in to comment.