41次发布

1.0.0-beta.202024年7月31日
1.0.0-beta.182024年6月27日
1.0.0-beta.142024年3月13日
1.0.0-beta.112023年12月19日
0.1.0 2022年7月27日

#15 in 编程语言

Download history 2004/week @ 2024-04-28 1945/week @ 2024-05-05 1804/week @ 2024-05-12 2339/week @ 2024-05-19 1902/week @ 2024-05-26 2694/week @ 2024-06-02 3262/week @ 2024-06-09 3098/week @ 2024-06-16 2692/week @ 2024-06-23 2065/week @ 2024-06-30 2141/week @ 2024-07-07 1876/week @ 2024-07-14 2441/week @ 2024-07-21 2704/week @ 2024-07-28 2158/week @ 2024-08-04 2242/week @ 2024-08-11

9,678 每月下载量
用于 8 个crate (7 直接)

MIT/Apache

1MB
31K SLoC

Rust 23K SLoC // 0.0% comments GraphQL 8K SLoC // 0.0% comments Python 3 SLoC

apollo-compiler

基于查询的GraphQL查询语言编译器。

Crates.io version Download docs.rs docs

功能

  • GraphQL语法的(相对)低级AST,以及Schema和ExecutableDocument的高级表示。
  • 三者都可以通过内部使用apollo-parser进行解析、创建或修改,并序列化。
  • 验证Schema和可执行文档,如GraphQL规范中定义。

入门

添加依赖项以开始使用apollo-compiler

cargo add apollo-compiler

或将其添加到您的Cargo.toml以进行手动安装

# Just an example, change to the necessary package version.
# Using an exact dependency is recommended for beta versions
[dependencies]
apollo-compiler = "=1.0.0-beta.20"

Rust版本

apollo-compiler在最新稳定版本的Rust上进行测试。旧版本可能兼容或不兼容。

用法

您可以使用apollo-compiler开始

use apollo_compiler::Schema;

let input = r#"
  interface Pet {
    name: String
  }

  type Dog implements Pet {
    name: String
    nickname: String
    barkVolume: Int
  }

  type Cat implements Pet {
    name: String
    nickname: String
    meowVolume: Int
  }

  union CatOrDog = Cat | Dog

  type Human {
    name: String
    pets: [Pet]
  }

  type Query {
    human: Human
  }
"#;

/// In case of validation errors, the panic message will be nicely formatted
/// to point at relevant parts of the source file(s)
let schema = Schema::parse_and_validate(input, "document.graphql").unwrap();

示例

访问片段定义字段类型

use apollo_compiler::{Schema, ExecutableDocument, Node, executable};

let schema_input = r#"
type User {
  id: ID
  name: String
  profilePic(size: Int): URL
}

schema { query: User }

scalar URL @specifiedBy(url: "https://tools.ietf.org/html/rfc3986")
"#;
let query_input = r#"
query getUser {
  ... vipCustomer
}

#fragment definition where we want to know the field types.
fragment vipCustomer on User {
  id
  name
  profilePic(size: 50)
}
"#;

let schema = Schema::parse_and_validate(schema_input, "schema.graphql").unwrap();
let document = ExecutableDocument::parse_and_validate(&schema, query_input, "query.graphql")
    .unwrap();

let op = document.operations.get(Some("getUser")).expect("getUser query does not exist");
let fragment_in_op = op.selection_set.selections.iter().filter_map(|sel| match sel {
    executable::Selection::FragmentSpread(spread) => {
        Some(document.fragments.get(&spread.fragment_name)?.as_ref())
    }
    _ => None
}).collect::<Vec<&executable::Fragment>>();

let fragment_fields = fragment_in_op.iter().flat_map(|frag| {
    frag.selection_set.fields()
}).collect::<Vec<&Node<executable::Field>>>();
let field_ty = fragment_fields
    .iter()
    .map(|f| f.ty().inner_named_type().as_str())
    .collect::<Vec<&str>>();
assert_eq!(field_ty, ["ID", "String", "URL"]);

获取在查询操作定义中使用的字段上定义的指令。

use apollo_compiler::{Schema, ExecutableDocument, Node, executable};

let schema_input = r#"
type Query {
  topProducts: Product
  name: String
  size: Int
}

type Product {
  inStock: Boolean @join__field(graph: INVENTORY)
  name: String @join__field(graph: PRODUCTS)
  price: Int
  shippingEstimate: Int
  upc: String!
  weight: Int
}

enum join__Graph {
  INVENTORY,
  PRODUCTS,
}
scalar join__FieldSet
directive @join__field(graph: join__Graph, requires: join__FieldSet, provides: join__FieldSet) on FIELD_DEFINITION
"#;
let query_input = r#"
query getProduct {
  size
  topProducts {
    name
    inStock
  }
}
"#;

let schema = Schema::parse_and_validate(schema_input, "schema.graphql").unwrap();
let document = ExecutableDocument::parse_and_validate(&schema, query_input, "query.graphql")
    .unwrap();

let get_product_op = document
    .operations
    .get(Some("getProduct"))
    .expect("getProduct query does not exist");

let in_stock_field = &get_product_op
    .selection_set
    .fields()
    .find(|f| f.name == "topProducts")
    .expect("topProducts field does not exist")
    .selection_set
    .fields()
    .find(|f| f.name == "inStock")
    .expect("inStock field does not exist")
    .definition;
let in_stock_directive: Vec<_> = in_stock_field
    .directives
    .iter()
    .map(|dir| &dir.name)
    .collect();
assert_eq!(in_stock_directive, ["join__field"]);

打印有故障的GraphQL文档的诊断信息

let input = r#"
query {
  cat {
    name
  }
}

query getPet {
  cat {
    owner {
      name
    }
  }
}

query getPet {
  cat {
    treat
  }
}

subscription sub {
  newMessage {
    body
    sender
  }
  disallowedSecondRootField
}

type Query {
  cat: Pet
}

type Subscription {
  newMessage: Result
}

interface Pet {
  name: String
}

type Dog implements Pet {
  name: String
  nickname: String
  barkVolume: Int
}

type Cat implements Pet {
  name: String
  nickname: String
  meowVolume: Int
}

union CatOrDog = Cat | Dog
"#;

if let Err(diagnostics) = apollo_compiler::parse_mixed_validate(input, "document.graphql") {
    println!("{diagnostics}")
}

许可

根据以下任一许可进行许可

供您选择。

依赖

~7–10MB
~175K SLoC