Skip to content

Commit

Permalink
[Feature] Replace the String based path with Uri (#383)
Browse files Browse the repository at this point in the history
  • Loading branch information
Guldem authored Oct 31, 2022
1 parent 1e3e7f4 commit b0fd18f
Show file tree
Hide file tree
Showing 19 changed files with 467 additions and 207 deletions.
12 changes: 6 additions & 6 deletions chopper/example/definition.chopper.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion chopper/example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'definition.dart';

Future<void> main() async {
final chopper = ChopperClient(
baseUrl: 'http://localhost:8000',
baseUrl: Uri.parse('http://localhost:8000'),
services: [
// the generated service
MyService.create(ChopperClient()),
Expand Down
50 changes: 28 additions & 22 deletions chopper/lib/src/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ final List<Type> allowedInterceptorsType = [
class ChopperClient {
/// Base URL of each request of the registered services.
/// E.g., the hostname of your service.
final String baseUrl;
final Uri baseUrl;

/// The [http.Client] used to make network calls.
final http.Client httpClient;
Expand Down Expand Up @@ -60,6 +60,7 @@ class 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.
/// If not provided, a empty default [Uri] will be used.
///
/// A custom HTTP client can be passed as the [client] parameter to be used
/// with the created [ChopperClient].
Expand All @@ -70,7 +71,7 @@ class ChopperClient {
///
/// ```dart
/// final chopper = ChopperClient(
/// baseUrl: 'localhost:8000',
/// baseUrl: Uri.parse('localhost:8000'),
/// services: [
/// // Add a generated service
/// TodosListService.create()
Expand Down Expand Up @@ -111,14 +112,19 @@ class ChopperClient {
/// );
/// ```
ChopperClient({
this.baseUrl = '',
Uri? baseUrl,
http.Client? client,
Iterable interceptors = const [],
this.authenticator,
this.converter,
this.errorConverter,
Iterable<ChopperService> services = const [],
}) : httpClient = client ?? http.Client(),
}) : assert(
baseUrl == null || !baseUrl.hasQuery,
'baseUrl should not contain query parameters.'
'Use a request interceptor to add default query parameters'),
baseUrl = baseUrl ?? Uri(),
httpClient = client ?? http.Client(),
_clientIsInternal = client == null {
if (!interceptors.every(_isAnInterceptor)) {
throw ArgumentError(
Expand Down Expand Up @@ -152,7 +158,7 @@ class ChopperClient {
///
/// ```dart
/// final chopper = ChopperClient(
/// baseUrl: 'localhost:8000',
/// baseUrl: Uri.parse('localhost:8000'),
/// services: [
/// // Add a generated service
/// TodosListService.create()
Expand Down Expand Up @@ -341,10 +347,10 @@ class ChopperClient {

/// Makes a HTTP GET request using the [send] function.
Future<Response<BodyType>> get<BodyType, InnerType>(
String url, {
Uri url, {
Map<String, String> headers = const {},
Uri? baseUrl,
Map<String, dynamic> parameters = const {},
String? baseUrl,
dynamic body,
}) =>
send<BodyType, InnerType>(
Expand All @@ -360,13 +366,13 @@ class ChopperClient {

/// Makes a HTTP POST request using the [send] function
Future<Response<BodyType>> post<BodyType, InnerType>(
String url, {
Uri url, {
dynamic body,
List<PartValue> parts = const [],
Map<String, String> headers = const {},
Map<String, dynamic> parameters = const {},
bool multipart = false,
String? baseUrl,
Uri? baseUrl,
}) =>
send<BodyType, InnerType>(
Request(
Expand All @@ -376,20 +382,20 @@ class ChopperClient {
body: body,
parts: parts,
headers: headers,
multipart: multipart,
parameters: parameters,
multipart: multipart,
),
);

/// Makes a HTTP PUT request using the [send] function.
Future<Response<BodyType>> put<BodyType, InnerType>(
String url, {
Uri url, {
dynamic body,
List<PartValue> parts = const [],
Map<String, String> headers = const {},
Map<String, dynamic> parameters = const {},
bool multipart = false,
String? baseUrl,
Uri? baseUrl,
}) =>
send<BodyType, InnerType>(
Request(
Expand All @@ -399,20 +405,20 @@ class ChopperClient {
body: body,
parts: parts,
headers: headers,
multipart: multipart,
parameters: parameters,
multipart: multipart,
),
);

/// Makes a HTTP PATCH request using the [send] function.
Future<Response<BodyType>> patch<BodyType, InnerType>(
String url, {
Uri url, {
dynamic body,
List<PartValue> parts = const [],
Map<String, String> headers = const {},
Map<String, dynamic> parameters = const {},
bool multipart = false,
String? baseUrl,
Uri? baseUrl,
}) =>
send<BodyType, InnerType>(
Request(
Expand All @@ -422,17 +428,17 @@ class ChopperClient {
body: body,
parts: parts,
headers: headers,
multipart: multipart,
parameters: parameters,
multipart: multipart,
),
);

/// Makes a HTTP DELETE request using the [send] function.
Future<Response<BodyType>> delete<BodyType, InnerType>(
String url, {
Uri url, {
Map<String, String> headers = const {},
Map<String, dynamic> parameters = const {},
String? baseUrl,
Uri? baseUrl,
}) =>
send<BodyType, InnerType>(
Request(
Expand All @@ -446,10 +452,10 @@ class ChopperClient {

/// Makes a HTTP HEAD request using the [send] function.
Future<Response<BodyType>> head<BodyType, InnerType>(
String url, {
Uri url, {
Map<String, String> headers = const {},
Map<String, dynamic> parameters = const {},
String? baseUrl,
Uri? baseUrl,
}) =>
send<BodyType, InnerType>(
Request(
Expand All @@ -463,10 +469,10 @@ class ChopperClient {

/// Makes a HTTP OPTIONS request using the [send] function.
Future<Response<BodyType>> options<BodyType, InnerType>(
String url, {
Uri url, {
Map<String, String> headers = const {},
Map<String, dynamic> parameters = const {},
String? baseUrl,
Uri? baseUrl,
}) =>
send<BodyType, InnerType>(
Request(
Expand Down
92 changes: 43 additions & 49 deletions chopper/lib/src/request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import 'package:meta/meta.dart';

/// This class represents an HTTP request that can be made with Chopper.
class Request extends http.BaseRequest {
final String path;
final String origin;
final Uri uri;
final Uri baseUri;
final dynamic body;
final Map<String, dynamic> parameters;
final bool multipart;
Expand All @@ -18,50 +18,27 @@ class Request extends http.BaseRequest {

Request(
String method,
this.path,
this.origin, {
this.body,
this.parameters = const {},
Map<String, String> headers = const {},
this.multipart = false,
this.parts = const [],
this.useBrackets = false,
this.includeNullQueryVars = false,
}) : super(
method,
buildUri(
origin,
path,
parameters,
useBrackets: useBrackets,
includeNullQueryVars: includeNullQueryVars,
),
) {
this.headers.addAll(headers);
}

/// Build the Chopper [Request] using a [Uri] instead of a [path] and [origin].
/// Both the query parameters in the [Uri] and those provided explicitly in
/// the [parameters] are merged together.
Request.uri(
String method,
Uri url, {
this.uri,
this.baseUri, {
this.body,
Map<String, dynamic>? parameters,
Map<String, String> headers = const {},
this.multipart = false,
this.parts = const [],
this.useBrackets = false,
this.includeNullQueryVars = false,
}) : origin = url.origin,
path = url.path,
parameters = {...url.queryParametersAll, ...?parameters},
}) : assert(
!baseUri.hasQuery,
'baseUri should not contain query parameters.'
'Use a request interceptor to add default query parameters'),
// Merge uri.queryParametersAll in the final parameters object so the request object reflects all configured queryParameters
parameters = {...uri.queryParametersAll, ...?parameters},
super(
method,
buildUri(
url.origin,
url.path,
{...url.queryParametersAll, ...?parameters},
baseUri,
uri,
{...uri.queryParametersAll, ...?parameters},
useBrackets: useBrackets,
includeNullQueryVars: includeNullQueryVars,
),
Expand All @@ -72,8 +49,8 @@ class Request extends http.BaseRequest {
/// Makes a copy of this [Request], replacing original values with the given ones.
Request copyWith({
String? method,
String? path,
String? origin,
Uri? uri,
Uri? baseUri,
dynamic body,
Map<String, dynamic>? parameters,
Map<String, String>? headers,
Expand All @@ -84,8 +61,8 @@ class Request extends http.BaseRequest {
}) =>
Request(
method ?? this.method,
path ?? this.path,
origin ?? this.origin,
uri ?? this.uri,
baseUri ?? this.baseUri,
body: body ?? this.body,
parameters: parameters ?? this.parameters,
headers: headers ?? this.headers,
Expand All @@ -100,27 +77,44 @@ class Request extends http.BaseRequest {
/// If [url] starts with 'http://' or 'https://', baseUrl is ignored.
@visibleForTesting
static Uri buildUri(
String baseUrl,
String url,
Uri baseUrl,
Uri url,
Map<String, dynamic> parameters, {
bool useBrackets = false,
bool includeNullQueryVars = false,
}) {
// If the request's url is already a fully qualified URL, we can use it
// as-is and ignore the baseUrl.
final Uri uri = url.startsWith('http://') || url.startsWith('https://')
? Uri.parse(url)
: Uri.parse('${baseUrl.strip('/')}/${url.leftStrip('/')}');
final Uri uri = url.isScheme('HTTP') || url.isScheme('HTTPS')
? url
: _mergeUri(baseUrl, url);

// Check if parameter also has all the queryParameters from the url (not the merged uri)
final bool parametersContainsUriQuery = parameters.keys
.every((element) => url.queryParametersAll.keys.contains(element));
final Map<String, dynamic> allParameters = parametersContainsUriQuery
? parameters
: {...url.queryParametersAll, ...parameters};

final String query = mapToQuery(
parameters,
allParameters,
useBrackets: useBrackets,
includeNullQueryVars: includeNullQueryVars,
);

return query.isNotEmpty
? uri.replace(query: uri.hasQuery ? '${uri.query}&$query' : query)
: uri;
return query.isNotEmpty ? uri.replace(query: query) : uri;
}

/// Merges Uri into another Uri preserving queries and paths
static Uri _mergeUri(Uri baseUri, Uri addToUri) {
final path = baseUri.hasEmptyPath
? addToUri.path
: '${baseUri.path.rightStrip('/')}/${addToUri.path.leftStrip('/')}';

return baseUri.replace(
path: path,
query: addToUri.hasQuery ? addToUri.query : null,
);
}

/// Converts this Chopper Request into a [http.BaseRequest].
Expand Down
Loading

0 comments on commit b0fd18f

Please sign in to comment.