Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The Big Public API Documentation update, volume 1. #189

Merged
merged 11 commits into from
Nov 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions chopper/lib/src/annotations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ class Patch extends Method {
);
}

/// Defined a method as an HTTP HEAD request.
/// Defines a method as an HTTP HEAD request.
@immutable
class Head extends Method {
const Head({
Expand All @@ -262,9 +262,40 @@ class Head extends Method {
);
}

/// A function that should convert the body of a [Request] to the HTTP representation.
typedef ConvertRequest = FutureOr<Request> Function(Request request);
/// A function that should convert the body of a [Response] from the HTTP
/// representation to a Dart object.
typedef ConvertResponse<T> = FutureOr<Response> Function(Response response);

/// Defines custom [Converter] methods for a single network API endpoint.
/// See [ConvertRequest], [ConvertResponse].
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should have an example here

///
/// ```dart
/// @ChopperApi(baseUrl: '/todos')
/// abstract class TodosListService extends ChopperService {
/// static TodosListService create([ChopperClient client]) =>
/// _$TodosListService(client);
///
/// static FutureOr<Request> customRequestConverter(Request request) {
/// return request.copyWith(
/// body: // Convert request.body the way your API needs it. See [JsonConverter.encodeJson] for an example.
/// );
/// }
///
/// static FutureOr<Response> customResponseConverter(Response response) {
/// return response.copyWith(
/// body: // Convert response.body the way your API needs it. See [JsonConverter.decodeJson] for an example.
/// );
/// }
///
/// @Get(path: "/{id}")
/// @FactoryConverter(
/// request: customRequestConverter,
/// response: customResponseConverter
/// )
/// Future<Response<Todo>> getTodo(@Path("id"));
/// }
@immutable
class FactoryConverter {
final ConvertRequest request;
Expand All @@ -276,7 +307,7 @@ class FactoryConverter {
});
}

/// Define a field for a `x-www-form-urlencoded` request.
/// Defines a field for a `x-www-form-urlencoded` request.
/// Automatically binds to the name of the method parameter.
///
/// ```dart
Expand Down Expand Up @@ -311,9 +342,9 @@ class Multipart {
const Multipart();
}

/// Use it to define a part of a [Multipart] request.
/// Use [Part] to define a part of a [Multipart] request.
///
/// All values will be converted to [String] using the [toString] method.
/// All values will be converted to [String] using their [toString] method.
///
/// Also accepts `MultipartFile` (from package:http).
@immutable
Expand All @@ -322,7 +353,7 @@ class Part {
const Part([this.name]);
}

/// Use it to define a file field for a [Multipart] request.
/// Use [PartFile] to define a file field for a [Multipart] request.
///
/// ```
/// @Post(path: 'file')
Expand Down Expand Up @@ -354,7 +385,7 @@ class PartFile {
/// - [String] (path of your file)
/// - `MultipartFile` (from package:http)
@immutable
@Deprecated('use PartFile')
@Deprecated('Use PartFile instead')
class FileField extends PartFile {
const FileField([String name]) : super(name);
}
Expand Down
148 changes: 90 additions & 58 deletions chopper/lib/src/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,25 @@ final allowedInterceptorsType = <Type>[
DynamicResponseInterceptorFunc,
];

/// ChopperClient is the main class of the Chopper API
/// Used to manager services, encode data, intercept request, response and error.
/// ChopperClient is the main class of the Chopper API.
///
/// It manages registered services, encodes and decodes data, and intercepts
/// requests and responses.
class ChopperClient {
/// Base url of each request to your api
/// hostname of your api for example
/// Base URL of each request of the registered services.
/// E.g., the hostname of your service.
final String baseUrl;

/// Http client used to do request
/// from `package:http/http.dart`
/// The [http.Client] used to make network calls.
final http.Client httpClient;

/// Converter call before request interceptor
/// and before interceptor of successful response
/// The [Converter] that handles request and response transformation before
/// the request and response interceptors are called respectively.
final Converter converter;

/// Converter call on error request
/// The [ErrorConverter] that handles response transformation before the
/// response interceptors are called, but only on error responses
/// \(statusCode &lt; 200 || statusCode &gt;= 300\).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I that okay? :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it renders as < and >, but the rendering is HTML based, so it should... 😄 But yes, it's a readability issue. I'll fix it in #193 .

final ErrorConverter errorConverter;

final Map<Type, ChopperService> _services = {};
Expand All @@ -47,37 +50,53 @@ class ChopperClient {

final bool _clientIsInternal;

/// Inject any service using the [services] parameter.
/// See [ChopperApi] annotation to define a service.
/// Creates and configures a [ChopperClient].
///
/// The base URL of each request of the registered services can be defined
/// with the [baseUrl] parameter.
/// E.g., the hostname of your service.
///
/// A custom HTTP client can be passed as the [client] parameter to be used
/// with the created [ChopperClient].
/// If not provided, a default [http.Client] will be used.
///
/// [ChopperService]s can be added to the client with the [services] parameter.
/// See the [ChopperApi] annotation to learn more about creating services.
///
/// ```dart
/// final chopper = ChopperClient(
/// baseUrl: 'localhost:8000',
/// services: [
/// // inject the generated service
/// TodosListService.create()
/// ],
/// );
/// baseUrl: 'localhost:8000',
/// services: [
/// // Add a generated service
/// TodosListService.create()
/// ],
/// );
/// ```
///
/// Interceptors can be use to apply modification or log infos for each
/// requests and responsed happening in that client.
/// See [ResponseInterceptor] and [RequestInterceptor]
/// [RequestInterceptor]s and [ResponseInterceptor]s can be added to the client
/// with the [interceptors] parameter.
///
/// See [RequestInterceptor], [ResponseInterceptor], [HttpLoggingInterceptor],
/// [HeadersInterceptor], [CurlInterceptor]
///
/// ```dart
/// final chopper = ChopperClient(
/// ...
/// interceptors: [
/// HttpLoggingInterceptor(),
/// ]
/// );
/// ...
/// interceptors: [
/// HttpLoggingInterceptor(),
/// ]
/// );
/// ```
///
/// [Converter] is used to apply modification on the body of a request/response
/// like converting an object to json (or json to object).
/// A different converter is used when an error is happening ([Response.isSuccessful] == false)
/// See [JsonConverter]
/// [Converter]s can be added to the client with the [converter]
/// parameter.
/// [Converter]s are used to convert the body of requests and responses to and
/// from the HTTP format.
///
/// A different converter can be used to handle error responses
/// (when [Response.isSuccessful] == false)) with tche [errorConverter] parameter.
///
/// See [Converter], [JsonConverter]
///
/// ```dart
/// final chopper = ChopperClient(
Expand Down Expand Up @@ -123,16 +142,16 @@ class ChopperClient {
bool _isAnInterceptor(value) =>
_isResponseInterceptor(value) || _isRequestInterceptor(value);

/// Retrieve any service injected into the [ChopperClient]
/// Retrieve any service included in the [ChopperClient]
///
/// ```dart
/// final chopper = ChopperClient(
/// baseUrl: 'localhost:8000',
/// services: [
/// // inject the generated service
/// TodosListService.create()
/// ],
/// );
/// baseUrl: 'localhost:8000',
/// services: [
/// // Add a generated service
/// TodosListService.create()
/// ],
/// );
///
/// final todoService = chopper.getService<TodosListService>();
/// ```
Expand Down Expand Up @@ -268,13 +287,14 @@ class ChopperClient {
return request;
}

/// Send request function that apply all interceptors and converters
/// Sends a pre-build [Request], applying all provided [Interceptor]s and
/// [Converter]s.
///
/// [BodyType] is the expected type of your response
/// ex: `String` or `CustomObject`
/// [BodyType] should be the expected type of the response body
/// (e.g., `String` or `CustomObject)`.
///
/// In the case of [BodyType] is a `List` or `BuildList`
/// [InnerType] will be the type of the generic
/// If `BodyType` is a `List` or a `BuiltList`, [InnerType] should be type of the
/// generic parameter (e.g., `convertResponse<List<CustomObject>, CustomObject>(response)`).
///
/// ```dart
/// Response<List<CustomObject>> res = await send<List<CustomObject>, CustomObject>(request);
Expand Down Expand Up @@ -312,7 +332,7 @@ class ChopperClient {
return res;
}

/// Http GET request using [send] function
/// Makes a HTTP GET request using the [send] function.
Future<Response<BodyType>> get<BodyType, InnerType>(
String url, {
Map<String, String> headers,
Expand All @@ -329,7 +349,7 @@ class ChopperClient {
),
);

/// Http POST request using [send] function
/// Makes a HTTP POST request using the [send] function
Future<Response<BodyType>> post<BodyType, InnerType>(
String url, {
dynamic body,
Expand All @@ -352,7 +372,7 @@ class ChopperClient {
),
);

/// Http PUT request using [send] function
/// Makes a HTTP PUT request using the [send] function.
Future<Response<BodyType>> put<BodyType, InnerType>(
String url, {
dynamic body,
Expand All @@ -375,7 +395,7 @@ class ChopperClient {
),
);

/// Http PATCH request using [send] function
/// Makes a HTTP PATCH request using the [send] function.
Future<Response<BodyType>> patch<BodyType, InnerType>(
String url, {
dynamic body,
Expand All @@ -398,7 +418,7 @@ class ChopperClient {
),
);

/// Http DELETE request using [send] function
/// Makes a HTTP DELETE request using the [send] function.
Future<Response<BodyType>> delete<BodyType, InnerType>(
String url, {
Map<String, String> headers,
Expand All @@ -415,7 +435,7 @@ class ChopperClient {
),
);

/// Http Head request using [send] function
/// Makes a HTTP HEAD request using the [send] function.
Future<Response<BodyType>> head<BodyType, InnerType>(
String url, {
Map<String, String> headers,
Expand All @@ -432,9 +452,11 @@ class ChopperClient {
),
);

/// dispose [ChopperClient] to clean memory.
/// Disposes this [ChopperClient] to clean up memory.
///
/// It won't close the http client if you provided it in the [ChopperClient] constructor.
/// **Warning**: If a custom [http.Client] was provided while creating this `ChopperClient`,
/// this method ***will not*** close it. In that case, closing the client is
/// its creator's responsibility.
@mustCallSuper
void dispose() {
_requestController.close();
Expand All @@ -451,25 +473,35 @@ class ChopperClient {
}
}

/// Event stream of request just before http call
/// all converters and interceptors have been run
/// A stream of processed [Request]s, as in after all [Converter]s, and
/// [RequestInterceptor]s have been run.
Stream<Request> get onRequest => _requestController.stream;

/// Event stream of response
/// all converters and interceptors have been run
/// A stream of processed [Response]s, as in after all [Converter]s and
/// [ResponseInterceptor]s have been run.
Stream<Response> get onResponse => _responseController.stream;
}

/// Used by generator to generate apis
/// A marker and helper class used by `chopper_generator` to generate network
/// call implementations.
///
///```dart
///@ChopperApi(baseUrl: "/todos")
///abstract class TodosListService extends ChopperService {
///
/// // A helper method that helps instantiating your service
/// static TodosListService create([ChopperClient client]) =>
/// _$TodosListService(client);
///}
///```
abstract class ChopperService {
ChopperClient client;

/// Internally use to retrieve service from [ChopperClient]
/// FIXME: use runtimeType ?
/// Used internally to retrieve the service from [ChopperClient].
// TODO: use runtimeType
Type get definitionType;

/// Cleanup memory
/// Should be call when the service is not used anymore
/// Disposes this [ChopperService] to clean up memory.
@mustCallSuper
void dispose() {
client = null;
Expand Down
Loading