Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class {{classname}} {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'{{{path}}}'{{#pathParams}}.replaceAll('{' r'{{{baseName}}}' '}', {{#includeLibraryTemplate}}api/query_param{{/includeLibraryTemplate}}.toString()){{/pathParams}};
final _path = r'{{{path}}}'{{#pathParams}}.replaceAll('{' r'{{{baseName}}}' '}', {{#includeLibraryTemplate}}api/path_param{{/includeLibraryTemplate}},){{/pathParams}};
final _options = Options(
method: r'{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}}',
{{#isResponseFile}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,12 @@ dev_dependencies:
build_runner: any
freezed: '^3.0.0'
json_serializable: '^6.9.3'
# unlike the json_serializable variant, this one has no copy_with_extension_gen
# whose source_gen constraint would hold source_helper back; source_helper 1.4.0
# added extension members that clash with json_serializable 6.x's internal
# copies and break the build_runner build script, so hold it below 1.4.0.
# 1.3.9+ requires Dart 3.9 while this variant advertises >=3.8.0, so keep the
# 1.3.8 lower bound resolvable for 3.8 users
source_helper: '>=1.3.8 <1.4.0'
{{/useFreezed}}
test: '^1.16.0'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Uri.encodeComponent({{#includeLibraryTemplate}}api/query_param{{/includeLibraryTemplate}}.toString())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Uri.encodeComponent({{#includeLibraryTemplate}}api/query_param{{/includeLibraryTemplate}}.toString())
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Uri.encodeComponent({{#includeLibraryTemplate}}api/query_param{{/includeLibraryTemplate}}.toString())
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,47 @@ public void testFreezedIgnoresUseOptional() throws IOException {
TestUtils.assertFileNotContains(output.toPath().resolve("lib/src/model/pet.dart"), "Optional<");
}

/**
* Path parameters must be URI-encoded as path components: the query_param helpers pass
* strings through unchanged, so a value containing '/' or spaces would otherwise break
* the request path. Every path substitution must therefore go through
* Uri.encodeComponent.
*/
@Test
public void testPathParamsAreUriEncoded() throws IOException {
for (Object[] libraryOption : serializationLibraries()) {
String serializationLibrary = (String) libraryOption[0];
File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();

final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("dart-dio")
.setInputSpec("src/test/resources/3_0/petstore.yaml")
.setOutputDir(output.getAbsolutePath().replace("\\", "/"))
.addAdditionalProperty(CodegenConstants.SERIALIZATION_LIBRARY, serializationLibrary);

ClientOptInput opts = configurator.toClientOptInput();
Generator generator = new DefaultGenerator().opts(opts);
List<File> files = generator.generate();
files.forEach(File::deleteOnExit);

// check every generated api class, not just one
Path apiDir = output.toPath().resolve("lib/src/api");
try (var apiFiles = Files.list(apiDir)) {
for (Path apiFile : apiFiles.filter(p -> p.getFileName().toString().endsWith("_api.dart"))
.collect(java.util.stream.Collectors.toList())) {
String content = Files.readString(apiFile, StandardCharsets.UTF_8);
int substitutions = content.split("\\.replaceAll\\(", -1).length - 1;
Assert.assertTrue(substitutions > 0,
"expected path substitutions in " + apiFile + ": " + content);
int encodings = content.split("Uri\\.encodeComponent\\(", -1).length - 1;
Assert.assertEquals(encodings, substitutions,
"every path substitution in " + apiFile + " must be URI-encoded: " + content);
}
}
}
}

private Path generateFormParamsClient(String serializationLibrary) throws IOException {
File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class PetApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', encodeQueryParameter(_serializers, petId, const FullType(int)).toString());
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', Uri.encodeComponent(encodeQueryParameter(_serializers, petId, const FullType(int)).toString()),);
final _options = Options(
method: r'DELETE',
headers: <String, dynamic>{
Expand Down Expand Up @@ -370,7 +370,7 @@ class PetApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', encodeQueryParameter(_serializers, petId, const FullType(int)).toString());
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', Uri.encodeComponent(encodeQueryParameter(_serializers, petId, const FullType(int)).toString()),);
final _options = Options(
method: r'GET',
headers: <String, dynamic>{
Expand Down Expand Up @@ -558,7 +558,7 @@ class PetApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', encodeQueryParameter(_serializers, petId, const FullType(int)).toString());
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', Uri.encodeComponent(encodeQueryParameter(_serializers, petId, const FullType(int)).toString()),);
final _options = Options(
method: r'POST',
headers: <String, dynamic>{
Expand Down Expand Up @@ -636,7 +636,7 @@ class PetApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}/uploadImage'.replaceAll('{' r'petId' '}', encodeQueryParameter(_serializers, petId, const FullType(int)).toString());
final _path = r'/pet/{petId}/uploadImage'.replaceAll('{' r'petId' '}', Uri.encodeComponent(encodeQueryParameter(_serializers, petId, const FullType(int)).toString()),);
final _options = Options(
method: r'POST',
headers: <String, dynamic>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class StoreApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/store/order/{orderId}'.replaceAll('{' r'orderId' '}', encodeQueryParameter(_serializers, orderId, const FullType(String)).toString());
final _path = r'/store/order/{orderId}'.replaceAll('{' r'orderId' '}', Uri.encodeComponent(encodeQueryParameter(_serializers, orderId, const FullType(String)).toString()),);
final _options = Options(
method: r'DELETE',
headers: <String, dynamic>{
Expand Down Expand Up @@ -170,7 +170,7 @@ class StoreApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/store/order/{orderId}'.replaceAll('{' r'orderId' '}', encodeQueryParameter(_serializers, orderId, const FullType(int)).toString());
final _path = r'/store/order/{orderId}'.replaceAll('{' r'orderId' '}', Uri.encodeComponent(encodeQueryParameter(_serializers, orderId, const FullType(int)).toString()),);
final _options = Options(
method: r'GET',
headers: <String, dynamic>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ class UserApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', encodeQueryParameter(_serializers, username, const FullType(String)).toString());
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', Uri.encodeComponent(encodeQueryParameter(_serializers, username, const FullType(String)).toString()),);
final _options = Options(
method: r'DELETE',
headers: <String, dynamic>{
Expand Down Expand Up @@ -320,7 +320,7 @@ class UserApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', encodeQueryParameter(_serializers, username, const FullType(String)).toString());
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', Uri.encodeComponent(encodeQueryParameter(_serializers, username, const FullType(String)).toString()),);
final _options = Options(
method: r'GET',
headers: <String, dynamic>{
Expand Down Expand Up @@ -529,7 +529,7 @@ class UserApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', encodeQueryParameter(_serializers, username, const FullType(String)).toString());
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', Uri.encodeComponent(encodeQueryParameter(_serializers, username, const FullType(String)).toString()),);
final _options = Options(
method: r'PUT',
headers: <String, dynamic>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class PetApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', petId.toString());
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', Uri.encodeComponent(petId.toString()),);
final _options = Options(
method: r'DELETE',
headers: <String, dynamic>{
Expand Down Expand Up @@ -336,7 +336,7 @@ _responseData = rawData == null ? null : deserialize<Set<Pet>, Pet>(rawData, 'Se
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', petId.toString());
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', Uri.encodeComponent(petId.toString()),);
final _options = Options(
method: r'GET',
headers: <String, dynamic>{
Expand Down Expand Up @@ -494,7 +494,7 @@ _responseData = rawData == null ? null : deserialize<Pet, Pet>(rawData, 'Pet', g
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', petId.toString());
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', Uri.encodeComponent(petId.toString()),);
final _options = Options(
method: r'POST',
headers: <String, dynamic>{
Expand Down Expand Up @@ -572,7 +572,7 @@ _responseData = rawData == null ? null : deserialize<Pet, Pet>(rawData, 'Pet', g
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}/uploadImage'.replaceAll('{' r'petId' '}', petId.toString());
final _path = r'/pet/{petId}/uploadImage'.replaceAll('{' r'petId' '}', Uri.encodeComponent(petId.toString()),);
final _options = Options(
method: r'POST',
headers: <String, dynamic>{
Expand Down Expand Up @@ -675,7 +675,7 @@ _responseData = rawData == null ? null : deserialize<ApiResponse, ApiResponse>(r
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/fake/{petId}/uploadImageWithRequiredFile'.replaceAll('{' r'petId' '}', petId.toString());
final _path = r'/fake/{petId}/uploadImageWithRequiredFile'.replaceAll('{' r'petId' '}', Uri.encodeComponent(petId.toString()),);
final _options = Options(
method: r'POST',
headers: <String, dynamic>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class StoreApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/store/order/{order_id}'.replaceAll('{' r'order_id' '}', orderId.toString());
final _path = r'/store/order/{order_id}'.replaceAll('{' r'order_id' '}', Uri.encodeComponent(orderId.toString()),);
final _options = Options(
method: r'DELETE',
headers: <String, dynamic>{
Expand Down Expand Up @@ -164,7 +164,7 @@ _responseData = rawData == null ? null : deserialize<Map<String, int>, int>(rawD
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/store/order/{order_id}'.replaceAll('{' r'order_id' '}', orderId.toString());
final _path = r'/store/order/{order_id}'.replaceAll('{' r'order_id' '}', Uri.encodeComponent(orderId.toString()),);
final _options = Options(
method: r'GET',
headers: <String, dynamic>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ class UserApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', username.toString());
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', Uri.encodeComponent(username.toString()),);
final _options = Options(
method: r'DELETE',
headers: <String, dynamic>{
Expand Down Expand Up @@ -297,7 +297,7 @@ class UserApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', username.toString());
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', Uri.encodeComponent(username.toString()),);
final _options = Options(
method: r'GET',
headers: <String, dynamic>{
Expand Down Expand Up @@ -496,7 +496,7 @@ _responseData = rawData == null ? null : deserialize<String, String>(rawData, 'S
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', username.toString());
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', Uri.encodeComponent(username.toString()),);
final _options = Options(
method: r'PUT',
headers: <String, dynamic>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,11 @@ dev_dependencies:
build_runner: any
freezed: '^3.0.0'
json_serializable: '^6.9.3'
# unlike the json_serializable variant, this one has no copy_with_extension_gen
# whose source_gen constraint would hold source_helper back; source_helper 1.4.0
# added extension members that clash with json_serializable 6.x's internal
# copies and break the build_runner build script, so hold it below 1.4.0.
# 1.3.9+ requires Dart 3.9 while this variant advertises >=3.8.0, so keep the
# 1.3.8 lower bound resolvable for 3.8 users
source_helper: '>=1.3.8 <1.4.0'
test: '^1.16.0'
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class PetApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', petId.toString());
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', Uri.encodeComponent(petId.toString()),);
final _options = Options(
method: r'DELETE',
headers: <String, dynamic>{
Expand Down Expand Up @@ -332,7 +332,7 @@ _responseData = rawData == null ? null : deserialize<Set<Pet>, Pet>(rawData, 'Se
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', petId.toString());
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', Uri.encodeComponent(petId.toString()),);
final _options = Options(
method: r'GET',
headers: <String, dynamic>{
Expand Down Expand Up @@ -486,7 +486,7 @@ _responseData = rawData == null ? null : deserialize<Pet, Pet>(rawData, 'Pet', g
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', petId.toString());
final _path = r'/pet/{petId}'.replaceAll('{' r'petId' '}', Uri.encodeComponent(petId.toString()),);
final _options = Options(
method: r'POST',
headers: <String, dynamic>{
Expand Down Expand Up @@ -564,7 +564,7 @@ _responseData = rawData == null ? null : deserialize<Pet, Pet>(rawData, 'Pet', g
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/pet/{petId}/uploadImage'.replaceAll('{' r'petId' '}', petId.toString());
final _path = r'/pet/{petId}/uploadImage'.replaceAll('{' r'petId' '}', Uri.encodeComponent(petId.toString()),);
final _options = Options(
method: r'POST',
headers: <String, dynamic>{
Expand Down Expand Up @@ -667,7 +667,7 @@ _responseData = rawData == null ? null : deserialize<ApiResponse, ApiResponse>(r
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/fake/{petId}/uploadImageWithRequiredFile'.replaceAll('{' r'petId' '}', petId.toString());
final _path = r'/fake/{petId}/uploadImageWithRequiredFile'.replaceAll('{' r'petId' '}', Uri.encodeComponent(petId.toString()),);
final _options = Options(
method: r'POST',
headers: <String, dynamic>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class StoreApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/store/order/{order_id}'.replaceAll('{' r'order_id' '}', orderId.toString());
final _path = r'/store/order/{order_id}'.replaceAll('{' r'order_id' '}', Uri.encodeComponent(orderId.toString()),);
final _options = Options(
method: r'DELETE',
headers: <String, dynamic>{
Expand Down Expand Up @@ -164,7 +164,7 @@ _responseData = rawData == null ? null : deserialize<Map<String, int>, int>(rawD
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/store/order/{order_id}'.replaceAll('{' r'order_id' '}', orderId.toString());
final _path = r'/store/order/{order_id}'.replaceAll('{' r'order_id' '}', Uri.encodeComponent(orderId.toString()),);
final _options = Options(
method: r'GET',
headers: <String, dynamic>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ class UserApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', username.toString());
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', Uri.encodeComponent(username.toString()),);
final _options = Options(
method: r'DELETE',
headers: <String, dynamic>{
Expand Down Expand Up @@ -285,7 +285,7 @@ class UserApi {
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', username.toString());
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', Uri.encodeComponent(username.toString()),);
final _options = Options(
method: r'GET',
headers: <String, dynamic>{
Expand Down Expand Up @@ -484,7 +484,7 @@ _responseData = rawData == null ? null : deserialize<String, String>(rawData, 'S
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', username.toString());
final _path = r'/user/{username}'.replaceAll('{' r'username' '}', Uri.encodeComponent(username.toString()),);
final _options = Options(
method: r'PUT',
headers: <String, dynamic>{
Expand Down
Loading
Loading