Skip to content

Commit

Permalink
feat: 831 - latest "prices" API changes (#897)
Browse files Browse the repository at this point in the history
Deleted files:
* `get_prices_results.dart`
* `validation_error.dart`
* `validation_error.g.dart`
* `validation_errors.dart`
* `validation_errors.g.dart`

New files:
* `get_locations_order.dart`: Field for the "order by" clause of "get locations".
* `get_locations_parameters.dart`: Parameters for the "get locations" API query.
* `get_locations_result.dart`: List of location objects returned by the "get locations" method.
* `get_locations_result.g.dart`: generated
* `order_by.dart`: "Order by" clause for "get list" methods (e.g. "get prices")

Impacted files:
* `api_prices_test.dart`: impacted by `MaybeError` refactoring; tests for new methods `getOSMLocation`, `getLocations`, `getPriceProductByCode`
* `get_prices_order.dart`: refactored using new class `OrderByField`
* `get_prices_parameters.dart`: refactored using new class `OrderBy`
* `open_prices_api_client.dart`: refactored using more systematically `MaybeError`; renamed `getPriceProduct` as `getPriceProductById`; added methods `getOSMLocation`, `getLocations`, `getPriceProductByCode`
* `openfoodfacts.dart`: added the new files; removed the deleted files
  • Loading branch information
monsieurtanuki authored Apr 1, 2024
1 parent 56446da commit 88dada6
Show file tree
Hide file tree
Showing 15 changed files with 468 additions and 168 deletions.
7 changes: 4 additions & 3 deletions lib/openfoodfacts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -89,22 +89,23 @@ export 'src/personalized_search/preference_importance.dart';
export 'src/personalized_search/product_preferences_manager.dart';
export 'src/personalized_search/product_preferences_selection.dart';
export 'src/prices/currency.dart';
export 'src/prices/get_locations_order.dart';
export 'src/prices/get_locations_parameters.dart';
export 'src/prices/get_locations_result.dart';
// export 'src/prices/get_parameters_helper.dart'; // uncomment if really needed
export 'src/prices/get_prices_order.dart';
export 'src/prices/get_prices_parameters.dart';
export 'src/prices/get_prices_result.dart';
export 'src/prices/get_prices_results.dart';
export 'src/prices/location.dart';
export 'src/prices/location_osm_type.dart';
export 'src/prices/maybe_error.dart';
export 'src/prices/order_by.dart';
export 'src/prices/price.dart';
export 'src/prices/price_per.dart';
export 'src/prices/price_product.dart';
export 'src/prices/proof.dart';
export 'src/prices/proof_type.dart';
export 'src/prices/session.dart';
export 'src/prices/validation_error.dart';
export 'src/prices/validation_errors.dart';
export 'src/search/autocomplete_search_result.dart';
export 'src/search/autocomplete_single_result.dart';
export 'src/search/fuzziness.dart';
Expand Down
154 changes: 132 additions & 22 deletions lib/src/open_prices_api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import 'package:path/path.dart';
import 'prices/maybe_error.dart';
import 'prices/price.dart';
import 'prices/proof.dart';
import 'prices/get_locations_parameters.dart';
import 'prices/get_locations_result.dart';
import 'prices/get_parameters_helper.dart';
import 'prices/get_prices_parameters.dart';
import 'prices/get_prices_result.dart';
import 'prices/get_prices_results.dart';
import 'prices/location.dart';
import 'prices/location_osm_type.dart';
import 'prices/price_product.dart';
import 'prices/proof_type.dart';
import 'prices/session.dart';
import 'prices/validation_errors.dart';
import 'utils/http_helper.dart';
import 'utils/open_food_api_configuration.dart';
import 'utils/uri_helper.dart';
Expand All @@ -36,7 +37,7 @@ class OpenPricesAPIClient {
static String _getHost(final UriProductHelper uriHelper) =>
uriHelper.getHost(_subdomain);

static Future<GetPricesResults> getPrices(
static Future<MaybeError<GetPricesResult>> getPrices(
final GetPricesParameters parameters, {
final UriProductHelper uriHelper = uriHelperFoodProd,
final String? bearerToken,
Expand All @@ -51,14 +52,72 @@ class OpenPricesAPIClient {
uriHelper: uriHelper,
bearerToken: bearerToken,
);
dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
if (response.statusCode == 200) {
return GetPricesResults.result(GetPricesResult.fromJson(decodedResponse));
try {
final dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
return MaybeError<GetPricesResult>.value(
GetPricesResult.fromJson(decodedResponse),
);
} catch (e) {
//
}
}
return MaybeError<GetPricesResult>.responseError(response);
}

static Future<MaybeError<Location>> getOSMLocation({
required final int locationOSMId,
required final LocationOSMType locationOSMType,
final UriProductHelper uriHelper = uriHelperFoodProd,
}) async {
final Uri uri = uriHelper.getUri(
path: '/api/v1/locations/osm/${locationOSMType.offTag}/$locationOSMId',
forcedHost: _getHost(uriHelper),
);
final Response response = await HttpHelper().doGetRequest(
uri,
uriHelper: uriHelper,
);
if (response.statusCode == 200) {
try {
final dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
return MaybeError<Location>.value(Location.fromJson(decodedResponse));
} catch (e) {
//
}
}
return GetPricesResults.error(ValidationErrors.fromJson(decodedResponse));
return MaybeError<Location>.responseError(response);
}

static Future<Location?> getLocation(
static Future<MaybeError<GetLocationsResult>> getLocations(
final GetLocationsParameters parameters, {
final UriProductHelper uriHelper = uriHelperFoodProd,
final String? bearerToken,
}) async {
final Uri uri = uriHelper.getUri(
path: '/api/v1/locations',
queryParameters: parameters.getQueryParameters(),
forcedHost: _getHost(uriHelper),
);
final Response response = await HttpHelper().doGetRequest(
uri,
uriHelper: uriHelper,
bearerToken: bearerToken,
);
if (response.statusCode == 200) {
try {
final dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
return MaybeError<GetLocationsResult>.value(
GetLocationsResult.fromJson(decodedResponse),
);
} catch (e) {
//
}
}
return MaybeError<GetLocationsResult>.responseError(response);
}

static Future<MaybeError<Location>> getLocation(
final int locationId, {
final UriProductHelper uriHelper = uriHelperFoodProd,
}) async {
Expand All @@ -70,14 +129,18 @@ class OpenPricesAPIClient {
uri,
uriHelper: uriHelper,
);
dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
if (response.statusCode == 200) {
return Location.fromJson(decodedResponse);
try {
final dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
return MaybeError<Location>.value(Location.fromJson(decodedResponse));
} catch (e) {
//
}
}
return null;
return MaybeError<Location>.responseError(response);
}

static Future<PriceProduct?> getPriceProduct(
static Future<MaybeError<PriceProduct>> getPriceProductById(
final int productId, {
final UriProductHelper uriHelper = uriHelperFoodProd,
}) async {
Expand All @@ -89,11 +152,42 @@ class OpenPricesAPIClient {
uri,
uriHelper: uriHelper,
);
dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
if (response.statusCode == 200) {
return PriceProduct.fromJson(decodedResponse);
try {
final dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
return MaybeError<PriceProduct>.value(
PriceProduct.fromJson(decodedResponse),
);
} catch (e) {
//
}
}
return MaybeError<PriceProduct>.responseError(response);
}

static Future<MaybeError<PriceProduct>> getPriceProductByCode(
final String productCode, {
final UriProductHelper uriHelper = uriHelperFoodProd,
}) async {
final Uri uri = uriHelper.getUri(
path: '/api/v1/products/code/$productCode',
forcedHost: _getHost(uriHelper),
);
final Response response = await HttpHelper().doGetRequest(
uri,
uriHelper: uriHelper,
);
if (response.statusCode == 200) {
try {
final dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
return MaybeError<PriceProduct>.value(
PriceProduct.fromJson(decodedResponse),
);
} catch (e) {
//
}
}
return null;
return MaybeError<PriceProduct>.responseError(response);
}

/// Returns the status of the server.
Expand Down Expand Up @@ -147,9 +241,13 @@ class OpenPricesAPIClient {
'password': password,
},
);
dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
if (response.statusCode == 200) {
return MaybeError<String>.value(decodedResponse['access_token']);
try {
final dynamic decodedResponse = HttpHelper().jsonDecodeUtf8(response);
return MaybeError<String>.value(decodedResponse['access_token']);
} catch (e) {
//
}
}
return MaybeError<String>.responseError(response);
}
Expand All @@ -168,9 +266,13 @@ class OpenPricesAPIClient {
uriHelper: uriHelper,
bearerToken: bearerToken,
);
final Map<String, dynamic> json = HttpHelper().jsonDecodeUtf8(response);
if (response.statusCode == 200) {
return MaybeError<Session>.value(Session.fromJson(json));
try {
final Map<String, dynamic> json = HttpHelper().jsonDecodeUtf8(response);
return MaybeError<Session>.value(Session.fromJson(json));
} catch (e) {
//
}
}
return MaybeError<Session>.responseError(response);
}
Expand Down Expand Up @@ -247,9 +349,13 @@ class OpenPricesAPIClient {
uriHelper: uriHelper,
bearerToken: bearerToken,
);
final Map<String, dynamic> json = HttpHelper().jsonDecodeUtf8(response);
if (response.statusCode == 201) {
return MaybeError<Price>.value(Price.fromJson(json));
try {
final Map<String, dynamic> json = HttpHelper().jsonDecodeUtf8(response);
return MaybeError<Price>.value(Price.fromJson(json));
} catch (e) {
//
}
}
return MaybeError<Price>.responseError(response);
}
Expand Down Expand Up @@ -317,8 +423,12 @@ class OpenPricesAPIClient {
response,
);
if (response.statusCode == 201) {
final Map<String, dynamic> json = HttpHelper().jsonDecode(responseBody);
return MaybeError<Proof>.value(Proof.fromJson(json));
try {
final Map<String, dynamic> json = HttpHelper().jsonDecode(responseBody);
return MaybeError<Proof>.value(Proof.fromJson(json));
} catch (e) {
//
}
}
return MaybeError<Proof>.error(
error: responseBody,
Expand Down
12 changes: 12 additions & 0 deletions lib/src/prices/get_locations_order.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'order_by.dart';

/// Field for the "order by" clause of "get locations".
enum GetLocationsOrderField implements OrderByField {
created(offTag: 'created'),
updated(offTag: 'updated');

const GetLocationsOrderField({required this.offTag});

@override
final String offTag;
}
39 changes: 39 additions & 0 deletions lib/src/prices/get_locations_parameters.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import 'get_locations_order.dart';
import 'order_by.dart';
import 'get_parameters_helper.dart';

/// Parameters for the "get locations" API query.
///
/// cf. https://prices.openfoodfacts.org/api/docs
class GetLocationsParameters extends GetParametersHelper {
String? osmNameLike;
String? osmCityLike;
String? osmPostcodeLike;
String? osmCountryLike;
int? priceCount;
int? priceCountGte;
int? priceCountLte;
List<OrderBy<GetLocationsOrderField>>? orderBy;

@override
Map<String, String> getQueryParameters() {
super.getQueryParameters();
addNonNullString(osmNameLike, 'osm_name__like');
addNonNullString(osmCityLike, 'osm_address_city__like');
addNonNullString(osmPostcodeLike, 'osm_address_postcode__like');
addNonNullString(osmCountryLike, 'osm_address_country__like');
addNonNullInt(priceCount, 'price_count');
addNonNullInt(priceCountGte, 'price_count__gte');
addNonNullInt(priceCountLte, 'price_count__lte');
if (orderBy != null) {
final List<String> orders = <String>[];
for (final OrderBy order in orderBy!) {
orders.add(order.offTag);
}
if (orders.isNotEmpty) {
addNonNullString(orders.join(','), 'order_by');
}
}
return result;
}
}
33 changes: 33 additions & 0 deletions lib/src/prices/get_locations_result.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:openfoodfacts/openfoodfacts.dart';

import '../interface/json_object.dart';

part 'get_locations_result.g.dart';

/// List of location objects returned by the "get locations" method.
@JsonSerializable()
class GetLocationsResult extends JsonObject {
@JsonKey()
List<Location>? items;

@JsonKey()
int? total;

@JsonKey(name: 'page')
int? pageNumber;

@JsonKey(name: 'size')
int? pageSize;

@JsonKey(name: 'pages')
int? numberOfPages;

GetLocationsResult();

factory GetLocationsResult.fromJson(Map<String, dynamic> json) =>
_$GetLocationsResultFromJson(json);

@override
Map<String, dynamic> toJson() => _$GetLocationsResultToJson(this);
}
26 changes: 26 additions & 0 deletions lib/src/prices/get_locations_result.g.dart

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

Loading

0 comments on commit 88dada6

Please sign in to comment.