google-cloud-rust icon indicating copy to clipboard operation
google-cloud-rust copied to clipboard

Firestore: Invalid request routing header

Open kaankoken opened this issue 1 month ago • 4 comments

Thanks for the amazing library.

Environment details

  • Programming language: Rust
  • OS: MacOS 15.7.2
  • Language runtime version: v1.93.0-nightly
  • Package version: firestore: 0.0.0

Issue

I am using the experimental firestore library at the moment.

google-cloud-firestore = { git = "https://github.com/googleapis/google-cloud-rust", rev = "50f65b0c024f080888c62ca33fe19af35dc607e6" }

There is an issue with the generated code.

I received this error below:

Error: Firestore("Batch write failed: the service reports an error with code INVALID_ARGUMENT described as: Invalid request routing header &database
=projects/{project-name}/databases/{database-name}. Please fill in the request header with format x-goog-request-params:project_id={project-name}&database_id={database-name}. Please refer to https://firebase.google.com/docs/firestore/manage-databases#access_a_named_database_with_a_client_library for more details.")

After I noticed the issue, I forked the library, google-cloud-rust, and tried to see whether the generated code was wrong.

I made some changes to src/firestore/src/generated/gapic/transport.rs

# Before
        let x_goog_request_params = [Some(&req)
            .map(|m| &m.database)
            .map(|s| s.as_str())
            .map(|v| format!("database={v}"))]
        .into_iter()
        .flatten()
        .fold(String::new(), |b, p| b + "&" + &p);

# After
        let x_goog_request_params = gaxi::routing_parameter::format(&[
            // Extract project_id from "projects/{project_id}/databases/{database_id}"
            gaxi::routing_parameter::value(
                Some(req.database.as_str()),
                &[gaxi::routing_parameter::Segment::Literal("projects/")],
                &[gaxi::routing_parameter::Segment::SingleWildcard],
                &[gaxi::routing_parameter::Segment::Literal("/databases/"), gaxi::routing_parameter::Segment::SingleWildcard],
            )
            .map(|v| ("project_id", v)),
            // Extract database_id from "projects/{project_id}/databases/{database_id}"
            gaxi::routing_parameter::value(
                Some(req.database.as_str()),
                &[gaxi::routing_parameter::Segment::Literal("projects/"), gaxi::routing_parameter::Segment::SingleWildcard, gaxi::routing_parameter::Segment::Literal("/databases/")],
                &[gaxi::routing_parameter::Segment::SingleWildcard],
                &[],
            )
            .map(|v| ("database_id", v)),
        ]);

After the manual changes, everything started to work.

kaankoken avatar Dec 09 '25 00:12 kaankoken

After a further investigation of the generated code.

on googleapis, the proto definitions need this block

    option (google.api.routing) = {
      routing_parameters {
        field: "database"
        path_template: "projects/{project_id=*}/**"
      }
      routing_parameters {
        field: "database"
        path_template: "projects/*/databases/{database_id=*}/**"
      }
    };

Edit: I opened a PR

kaankoken avatar Dec 09 '25 01:12 kaankoken

Thanks for the detailed bug report and the investigation. I think in most other languages a hand-written layer adds these routing headers. Your patch sounds like a better solution to me, but there may be good reasons to prefer a hand-written layer that I may be missing.

Oh, and I should say that writing this layer is in our roadmap, but we have prioritized other services ahead of Firestore.

coryan avatar Dec 09 '25 13:12 coryan

For other Googlers: b/275088289 may be of interest.

coryan avatar Dec 09 '25 14:12 coryan

Hi @coryan,

Thank you for getting back to me. Is there a way I could contribute to this project, especially to firestore?

Many thanks.

kaankoken avatar Dec 10 '25 12:12 kaankoken