Skip to content

Commit 06cbc4a

Browse files
authored
fix(grpc): schema validation for fields in snake_case (#1527)
1 parent d591d33 commit 06cbc4a

File tree

6 files changed

+51
-5
lines changed

6 files changed

+51
-5
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ async-graphql = { version = "7.0.3", features = [
121121
"apollo_tracing",
122122
"opentelemetry",
123123
]}
124+
convert_case = "0.6.0"
124125

125126
[dev-dependencies]
126127
criterion = "0.5.1"

src/grpc/protobuf.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ impl ProtobufOperation {
201201
}
202202

203203
#[cfg(test)]
204-
mod tests {
204+
pub mod tests {
205205
// TODO: Rewrite protobuf tests
206206
use std::path::PathBuf;
207207

@@ -232,7 +232,7 @@ mod tests {
232232
test_file
233233
}
234234

235-
async fn get_proto_file(name: &str) -> Result<FileDescriptorSet> {
235+
pub async fn get_proto_file(name: &str) -> Result<FileDescriptorSet> {
236236
let runtime = crate::runtime::test::init(None);
237237
let reader = ConfigReader::init(runtime);
238238

src/grpc/tests/proto/news.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ message News {
88
int32 id = 1;
99
string title = 2;
1010
string body = 3;
11-
string postImage = 4;
11+
string post_image = 4;
1212
}
1313

1414
service NewsService {

src/grpc/tests/proto/news_no_pkg.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ message News {
66
int32 id = 1;
77
string title = 2;
88
string body = 3;
9-
string postImage = 4;
9+
string post_image = 4;
1010
}
1111

1212
service NewsService {

src/json/json_schema.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::HashMap;
22

3+
use convert_case::{Case, Casing};
34
use prost_reflect::{FieldDescriptor, Kind, MessageDescriptor};
45
use serde::{Deserialize, Serialize};
56

@@ -158,7 +159,10 @@ impl TryFrom<&MessageDescriptor> for JsonSchema {
158159
for field in fields {
159160
let field_schema = JsonSchema::try_from(&field)?;
160161

161-
map.insert(field.name().to_string(), field_schema);
162+
// the snake_case for field names is automatically converted to camelCase
163+
// by prost on serde serialize/deserealize and in graphql type name should be in
164+
// camelCase as well, so convert field.name to camelCase here
165+
map.insert(field.name().to_case(Case::Camel), field_schema);
162166
}
163167

164168
Ok(JsonSchema::Obj(map))
@@ -210,9 +214,14 @@ impl TryFrom<&FieldDescriptor> for JsonSchema {
210214

211215
#[cfg(test)]
212216
mod tests {
217+
use std::collections::HashMap;
218+
213219
use async_graphql::Name;
214220
use indexmap::IndexMap;
215221

222+
use crate::blueprint::GrpcMethod;
223+
use crate::grpc::protobuf::tests::get_proto_file;
224+
use crate::grpc::protobuf::ProtobufSet;
216225
use crate::json::JsonSchema;
217226
use crate::valid::{Valid, Validator};
218227

@@ -274,4 +283,30 @@ mod tests {
274283
let result = schema.validate(&value);
275284
assert_eq!(result, Valid::succeed(()));
276285
}
286+
287+
#[tokio::test]
288+
async fn test_from_protobuf_conversion() -> anyhow::Result<()> {
289+
let grpc_method = GrpcMethod::try_from("news.NewsService.GetNews").unwrap();
290+
291+
let file = ProtobufSet::from_proto_file(&get_proto_file("news.proto").await?)?;
292+
let service = file.find_service(&grpc_method)?;
293+
let operation = service.find_operation(&grpc_method)?;
294+
295+
let schema = JsonSchema::try_from(&operation.output_type)?;
296+
297+
assert_eq!(
298+
schema,
299+
JsonSchema::Obj(HashMap::from_iter([
300+
(
301+
"postImage".to_owned(),
302+
JsonSchema::Opt(JsonSchema::Str.into())
303+
),
304+
("title".to_owned(), JsonSchema::Opt(JsonSchema::Str.into())),
305+
("id".to_owned(), JsonSchema::Opt(JsonSchema::Num.into())),
306+
("body".to_owned(), JsonSchema::Opt(JsonSchema::Str.into())),
307+
]))
308+
);
309+
310+
Ok(())
311+
}
277312
}

0 commit comments

Comments
 (0)