Repository: rusoto/rusoto (language: rust)

Issue:
service_crategen can't parse operations with multiple static parameters
Currently `service_crategen` assumes there could be at max one parameter to a service operaion.
This assumption [breaks for CloudSearch](https://github.com/boto/botocore/blob/29f598cd50b3ff2d5ad514fc6352c90136e0772e/botocore/data/cloudsearchdomain/2013-01-01/service-2.json#L19.)
This results in a [broken client for CloudSearchDomain](https://github.com/rusoto/rusoto/blob/583bc8be4c6d86d6b7ff920d025b8c2e751ca7a4/rusoto/services/cloudsearchdomain/src/generated.rs#L552).
The issue could be addressed by simply splitting the parameters via `&` - I'll attach a PR shortly.
A more sophisticated approach would be to use [Url crate](https://docs.rs/url/2.1.0/url/) to parse the parameters in a more robust way.


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index af84e5fed27..50f88647a31 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
 - Deserialize PostTextResponse correctly by allowing null values in the slots field
 - Fix Profile Config Loading should ignore comments with '=' chars
 - Add App Mesh service
+- Fix service_crategen to parse operations with multiple static params
 
 ## [0.40.0] - 2019-06-28
 
diff --git a/rusoto/services/cloudsearchdomain/src/generated.rs b/rusoto/services/cloudsearchdomain/src/generated.rs
index c896e70238d..d5d9ee5a7fb 100644
--- a/rusoto/services/cloudsearchdomain/src/generated.rs
+++ b/rusoto/services/cloudsearchdomain/src/generated.rs
@@ -549,7 +549,8 @@ impl CloudSearchDomain for CloudSearchDomainClient {
         if let Some(ref x) = input.stats {
             params.put("stats", x);
         }
-        params.put("format", "sdk&pretty");
+        params.put("format", "sdk");
+        params.put("pretty", "true");
         request.set_params(params);
 
         self.client.sign_and_dispatch(request, |response| {
@@ -586,7 +587,8 @@ impl CloudSearchDomain for CloudSearchDomainClient {
             params.put("size", x);
         }
         params.put("suggester", &input.suggester);
-        params.put("format", "sdk&pretty");
+        params.put("format", "sdk");
+        params.put("pretty", "true");
         request.set_params(params);
 
         self.client.sign_and_dispatch(request, |response| {
diff --git a/rusoto/services/s3/src/generated.rs b/rusoto/services/s3/src/generated.rs
index 758ebb1d651..11e584f8e06 100644
--- a/rusoto/services/s3/src/generated.rs
+++ b/rusoto/services/s3/src/generated.rs
@@ -23768,7 +23768,8 @@ impl S3 for S3Client {
             );
         }
         let mut params = Params::new();
-        params.put("select&select-type", "2");
+        params.put_key("select");
+        params.put("select-type", "2");
         request.set_params(params);
         let mut writer = EventWriter::new(Vec::new());
         SelectObjectContentRequestSerializer::serialize(
diff --git a/service_crategen/src/commands/generate/codegen/rest_request_generator.rs b/service_crategen/src/commands/generate/codegen/rest_request_generator.rs
index 7feeb827eb7..b57e86eb369 100644
--- a/service_crategen/src/commands/generate/codegen/rest_request_generator.rs
+++ b/service_crategen/src/commands/generate/codegen/rest_request_generator.rs
@@ -166,16 +166,18 @@ fn generate_static_param_strings(operation: &Operation) -> Vec<String> {
     // Sometimes the key has the query param already set, like "list-type=2"
     // These need to get parsed out of the URI and added to the params map
     // with the other "queryparam" members
-    if let Some(ref key) = maybe_params {
-        match key.find('=') {
-            Some(_) => {
-                let key_val_vec: Vec<&str> = key.split('=').collect();
-                static_params.push(format!(
-                    "params.put(\"{}\", \"{}\");",
-                    key_val_vec[0], key_val_vec[1]
-                ))
+    if let Some(ref params) = maybe_params {
+        for param in params.split('&') {
+            match param.find('=') {
+                Some(_) => {
+                    let key_val_vec: Vec<&str> = param.split('=').collect();
+                    static_params.push(format!(
+                        "params.put(\"{}\", \"{}\");",
+                        key_val_vec[0], key_val_vec[1]
+                    ))
+                }
+                None => static_params.push(format!("params.put_key(\"{}\");", param)),
             }
-            None => static_params.push(format!("params.put_key(\"{}\");", key)),
         }
     };
 
@@ -340,4 +342,21 @@ mod tests {
         );
     }
 
+    #[test]
+    fn generate_static_param_strings_parses_mixed_params() {
+        let service_json = "{\
+            \"name\": \"Search\",
+            \"http\":{
+                \"method\":\"GET\",
+                \"requestUri\":\"/2013-01-01/suggest?format=sdk&pretty\"
+            }\
+        }";
+        let operation = serde_json::from_str(service_json).expect("failed to parse operation json");
+
+        let static_params = generate_static_param_strings(&operation);
+
+        assert_eq!(static_params.len(), 2);
+        assert_eq!(static_params.get(0), Some(&"params.put(\"format\", \"sdk\");".to_owned()));
+        assert_eq!(static_params.get(1), Some(&"params.put_key(\"pretty\");".to_owned()));
+    }
 }


Test patch: