Rust GraphQL解析库apollo-parser的使用:高效解析和操作GraphQL查询与模式的工具
Rust GraphQL解析库apollo-parser的使用:高效解析和操作GraphQL查询与模式的工具
特性
- 根据2021年10月GraphQL规范提供的类型化具体语法树
- 错误恢复能力
- 在发现词法或语法错误时,不会导致词法分析或解析失败
- GraphQL词法分析器
- GraphQL解析器
快速开始
添加依赖开始使用apollo-parser:
cargo add apollo-parser
或者在Cargo.toml中手动添加:
[dependencies]
apollo-parser = "0.8.4"
Rust版本
apollo-parser在最新的Rust稳定版本上测试。旧版本可能兼容也可能不兼容。
使用方法
apollo-parser用于解析GraphQL模式和查询,根据最新规范生成类型化语法树。快速开始示例:
use apollo_parser::Parser;
let input = "union SearchResult = Photo | Person | Cat | Dog";
let parser = Parser::new(input);
let cst = parser.parse();
apollo-parser具有错误恢复能力,这意味着遇到错误时不会中止解析,parser.parse()总是会产生一个CST(具体语法树),并伴随任何遇到的错误:
use apollo_parser::Parser;
let input = "union SearchResult = Photo | Person | Cat | Dog";
let parser = Parser::new(input);
let cst = parser.parse();
// cst.errors()返回在词法分析和解析期间遇到的错误迭代器
assert_eq!(0, cst.errors().len());
// cst.document()获取树的文档或根节点
let doc = cst.document();
示例
以下是两个示例:
获取对象中的字段名
use apollo_parser::{cst, Parser};
let input = "
type ProductDimension {
size: String
weight: Float @tag(name: \"hi from inventory value type field\")
}
";
let parser = Parser::new(input);
let cst = parser.parse();
assert_eq!(0, cst.errors().len());
let doc = cst.document();
for def in doc.definitions() {
if let cst::Definition::ObjectTypeDefinition(object_type) = def {
assert_eq!(object_type.name().unwrap().text(), "ProductDimension");
for field_def in object_type.fields_definition().unwrap().field_definitions() {
println!("{}", field_def.name().unwrap().text()); // 输出 size weight
}
}
}
获取查询中使用的变量
use apollo_parser::{cst, Parser};
let input = "
query GraphQuery($graph_id: ID!, $variant: String) {
service(id: $graph_id) {
schema(tag: $variant) {
document
}
}
}
";
let parser = Parser::new(input);
let cst = parser.parse();
assert_eq!(0, cst.errors().len());
let doc = cst.document();
for def in doc.definitions() {
if let cst::Definition::OperationDefinition(op_def) = def {
assert_eq!(op_def.name().unwrap().text(), "GraphQuery");
let variable_defs = op_def.variable_definitions();
let variables: Vec<String> = variable_defs
.iter()
.map(|v| v.variable_definitions())
.flatten
.filter_map(|v| Some(v.variable()?.text().to_string()))
.collect();
assert_eq!(
variables.as_slice(),
["graph_id".to_string(), "variant".to_string()]
);
}
}
完整示例
解析GraphQL模式并遍历类型定义
use apollo_parser::{cst, Parser};
fn main() {
let schema = r#"
type Query {
hello: String
user(id: ID!): User
}
type User {
id: ID!
name: String
email: String
}
scalar ID
"#;
let parser = Parser::new(schema);
let cst = parser.parse();
// 检查是否有错误
if !cst.errors().is_empty() {
for error in cst.errors() {
eprintln!("Error: {:?}", error);
}
return;
}
let document = cst.document();
for definition in document.definitions() {
match definition {
cst::Definition::ObjectTypeDefinition(object_type) => {
println!("Found object type: {}", object_type.name().unwrap().text());
if let Some(fields) = object_type.fields_definition() {
for field in fields.field_definitions() {
println!(" Field: {}", field.name().unwrap().text());
if let Some(args) = field.arguments_definition() {
for arg in args.input_value_definitions() {
println!(" Argument: {}: {}",
arg.name().unwrap().text(),
arg.ty().unwrap().text()
);
}
}
}
}
}
cst::Definition::ScalarTypeDefinition(scalar) => {
println!("Found scalar type: {}", scalar.name().unwrap().text());
}
_ => {}
}
}
}
解析GraphQL查询并提取操作信息
use apollo_parser::{cst, Parser};
fn main() {
let query = r#"
query GetUser($userId极速查询($userId: ID!) {
user(id: $userId) {
id
name
email
}
}
"#;
let parser = Parser::new(query);
let cst = parser.parse();
// 检查是否有错误
if !cst.errors().is_empty() {
for error in cst.errors() {
eprintln!("Error: {:?}", error);
}
return;
}
let document = cst.document();
for definition in document.definitions() {
if let cst::Definition::OperationDefinition(op) = definition {
println!("Operation type: {:?}", op.operation_type());
if let Some(name) = op.name() {
println!("Operation name: {}", name.text());
}
// 处理变量定义
if let Some(vars) = op.variable_definitions() {
for var_def in vars.variable_definitions() {
println!("Variable: {}: {}",
var_def.variable().unwrap().text(),
var_def.ty().unwrap().text()
);
}
}
// 处理选择集
if let Some(selection_set) = op.selection_set() {
for selection in selection_set.selections() {
if let cst::Selection::Field(field) = selection {
println!("Field: {}", field.name().unwrap().text());
// 处理参数
if let Some(args) = field.arguments() {
for arg in args.arguments() {
println!(" Argument: {}: {:?}",
arg.name().unwrap().text(),
arg.value().unwrap()
);
}
}
// 处理嵌套选择
if let Some(nested_selection) = field.selection_set() {
for nested in nested_selection.selections() {
if let cst::Selection::Field(nested_field) = nested {
println!(" Nested field: {}", nested_field.name().unwrap().text());
}
}
}
}
}
}
}
}
}
许可证
根据以下任一许可证授权:
- Apache License, Version 2.0
- MIT license
1 回复
Rust GraphQL解析库apollo-parser的使用指南
简介
apollo-parser 是一个用Rust编写的GraphQL解析器,专门用于高效解析和操作GraphQL查询与模式。它由Apollo团队开发,是Rust生态中处理GraphQL的优秀工具。
主要特性
- 完全兼容GraphQL规范
- 高性能解析
- 详细的语法树表示
- 支持查询和模式定义语言(SDL)
- 提供丰富的AST访问接口
安装
在Cargo.toml中添加依赖:
[dependencies]
apollo-parser = "0.8"
基本使用方法
1. 解析GraphQL查询
use apollo_parser::Parser;
fn main() {
let query = r#"
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
"#;
let parser = Parser::new(query);
let ast = parser.parse();
// 检查是否有错误
if !ast.errors().is_empty() {
for error in ast.errors() {
println!("Error: {}", error);
}
}
// 访问文档节点
let document = ast.document();
for definition in document.definitions() {
println!("Definition: {:?}", definition);
}
}
2. 解析GraphQL模式(SDL)
use apollo_parser::Parser;
fn main() {
let schema = r#"
type User {
id: ID!
name: String
email: String
}
type Query {
user(id: ID!): User
}
"#;
let parser = Parser::new(schema);
let ast = parser.parse();
if !ast.errors().is_empty() {
for error in ast.errors() {
println!("Error: {}", error);
}
return;
}
// 遍历类型定义
for definition in ast.document().definitions() {
if let apollo_parser::cst::Definition::TypeDefinition(type_def) = definition {
println!("Type: {}", type_def.name().unwrap().text());
}
}
}
3. 遍历和修改AST
use apollo_parser::{Parser, cst};
fn main() {
let query = r#"{ user { id name } }"#;
let parser = Parser::new(query);
let ast = parser.parse();
// 遍历选择集
if let Some(cst::Definition::OperationDefinition(op)) = ast.document().definitions().next() {
if let Some(selection_set) = op.selection_set() {
for selection in selection_set.selections() {
if let cst::Selection::Field(field) = selection {
println!("Field: {}", field.name().unwrap().text());
}
}
}
}
}
高级用法
1. 自定义访问器模式
use apollo_parser::{Parser, cst, visit};
struct FieldVisitor;
impl visit::Visitor for FieldVisitor {
fn enter_field(&mut self, node: &cst::Field) {
println!("Visiting field: {}", node.name().unwrap().text());
}
}
fn main() {
let query = r#"
{
user {
id
name
friends {
name
}
}
}
"#;
let parser = Parser::new(query);
let ast = parser.parse();
let mut visitor = FieldVisitor;
visit::visit(&ast.document(), &mut visitor);
}
2. 验证GraphQL文档
use apollo_parser::Parser;
fn validate_graphql(document: &str) -> Result<(), Vec<String>> {
let parser = Parser::new(document);
let ast = parser.parse();
if ast.errors().is_empty() {
Ok(())
} else {
Err(ast.errors().map(|e| e.to_string()).collect())
}
}
fn main() {
let invalid_query = r#"{ user { id name } "#; // 缺少闭合大括号
match validate_graphql(invalid_query) {
Ok(_) => println!("Valid GraphQL"),
Err(errors) => {
println!("Validation errors:");
for error in errors {
println!("- {}", error);
}
}
}
}
性能提示
- 对于重复解析,可以重用Parser实例
- 使用
visit
模块进行AST遍历比手动遍历更高效 - 如果只需要验证而不需要完整AST,可以检查
ast.errors()
后立即返回
总结
apollo-parser提供了强大的GraphQL解析能力,适合构建GraphQL服务器、客户端或工具链。它的Rust原生实现保证了高性能,而详细的AST表示则提供了丰富的操作可能性。
完整示例
// 完整示例:结合查询解析和验证功能的GraphQL处理器
use apollo_parser::{Parser, cst, visit};
// 自定义访问器,收集所有查询字段
struct FieldCollector {
fields: Vec<String>,
}
impl visit::Visitor for FieldCollector {
fn enter_field(&mut self, node: &cst::Field) {
self.fields.push(node.name().unwrap().text().to_string());
}
}
fn process_graphql_query(query: &str) -> Result<Vec<String>, Vec<String>> {
let parser = Parser::new(query);
let ast = parser.parse();
// 先验证查询语法
if !ast.errors().is_empty() {
return Err(ast.errors().map(|e| e.to_string()).collect());
}
// 收集所有字段
let mut collector = FieldCollector { fields: Vec::new() };
visit::visit(&ast.document(), &mut collector);
Ok(collector.fields)
}
fn main() {
let query = r#"
{
user {
id
name
friends {
name
age
}
}
}
"#;
match process_graphql_query(query) {
Ok(fields) => {
println!("Query contains fields:");
for field in fields {
println!("- {}", field);
}
}
Err(errors) => {
println!("Query validation failed:");
for error in errors {
println!("- {}", error);
}
}
}
}
这个完整示例展示了如何:
- 解析GraphQL查询
- 验证查询语法
- 使用访问者模式收集所有查询字段
- 处理解析和验证结果
输出示例:
Query contains fields:
- user
- id
- name
- friends
- name
- age