Skip to content

Releases: apollographql/apollo-rs

[email protected] (#762)

30 Nov 13:00
55707c7
Compare
Choose a tag to compare

BREAKING

  • API refactor to make it harder to ignore errors - SimonSapin, pull/752 fixing issue/709:

    • ast::Document, Schema, and ExecutableDocument not longer contain potential errors
      that users need to check separately.
    • Instead, various constructors and methods now return a Result,
      with the Err case containing both both errors and a maybe-incomplete value.
    • Change validate methods of Schema and ExecutableDocument to take ownership of self.
      On success they return the schema or document (unmodified) wrapped in a Valid<_> marker type,
      which is immutable.
    • Change ExecutableDocument to require a &Valid<Schema> instead of &Schema,
      forcing callers to either run validation or opt out explicitly with Valid::assume_valid.
    • Make parse_mixed and to_mixed validate both the schema and document.
      Rename them with a _validate suffix.
    • Corresponding changes to all of the above in Parser method signatures
    • Remove ast::Document::check_parse_errors:
      parse errors are now encoded in the return value of parse.
    • Remove ast::Document::to_schema_builder. Use SchemaBuilder::add_ast instead.
    • Move items from the crate top-level to apollo_compiler::validation:
      • Diagnostic
      • DiagnosticList
      • FileId
      • NodeLocation
    • Move items from the crate top-level to apollo_compiler::execution:
      • GraphQLError
      • GraphQLLocation
    • Remove warning-level and advice-level diagnostics. See issue/751.

    Highlight of signature changes:

    +struct Valid<T>(T); // Implements `Deref` and `AsRef` but not `DerefMut` or `AsMut`
    +
    +struct WithErrors<T> {
    +    partial: T, // Errors may cause components to be missing
    +    errors: DiagnosticList,
    +}
    
    -pub fn parse_mixed(…) -> (Schema, ExecutableDocument)
    +pub fn parse_mixed_validate(…)
    +    -> Result<(Valid<Schema>, Valid<ExecutableDocument>), DiagnosticList>
    
     impl ast::Document {
    -    pub fn parse(…) -> Self
    +    pub fn parse(…) -> Result<Self, WithErrors<Self>>
    
    -    pub fn to_schema(&self) -> Schema
    +    pub fn to_schema(&self) -> Result<Schema, WithErrors<Schema>>
    
    -    pub fn to_executable(&self) -> ExecutableDocument
    +    pub fn to_executable(&self) -> Result<ExecutableDocument, WithErrors<ExecutableDocument>>
    
    -    pub fn to_mixed(&self) -> (Schema, ExecutableDocument)
    +    pub fn to_mixed_validate(
    +        &self,
    +    ) -> Result<(Valid<Schema>, Valid<ExecutableDocument>), DiagnosticList>
     }
    
     impl Schema {
    -    pub fn parse(…) -> Self
    -    pub fn validate(&self) -> Result<DiagnosticList, DiagnosticList>
    
    +    pub fn parse_and_validate(…) -> Result<Valid<Self>, WithErrors<Self>>
    +    pub fn parse(…) -> Result<Self, WithErrors<Self>>
    +    pub fn validate(self) -> Result<Valid<Self>, WithErrors<Self>>
     }
    
     impl SchemaBuilder {
    -    pub fn build(self) -> Schema
    +    pub fn build(self) -> Result<Schema, WithErrors<Schema>>
     }
    
     impl ExecutableDocument {
    -    pub fn parse(schema: &Schema, …) -> Self
    -    pub fn validate(&self, schema: &Schema) -> Result<(), DiagnosticList>
    
    +    pub fn parse_and_validate(schema: &Valid<Schema>, …) -> Result<Valid<Self>, WithErrors<Self>>
    +    pub fn parse(schema: &Valid<Schema>, …) -> Result<Self, WithErrors<Self>>
    +    pub fn validate(self, schema: &Valid<Schema>) -> Result<Valid<Self>, WithErrors<Self>>
     }

Features

  • Add parse_and_validate constructors for Schema and ExecutableDocument - SimonSapin, pull/752:
    when mutating isn’t needed after parsing, this returns an immutable Valid<_> value in one step.

  • Implement serde Serialize and Deserialize for some AST types - SimonSapin, pull/760:

    • Node
    • NodeStr
    • Name
    • IntValue
    • FloatValue
    • Value
    • Type
      Source locations are not preserved through serialization.
  • Add ast::Definition::as_*() -> Option<&_> methods for each variant - SimonSapin, pull/760

  • Serialize (to GraphQL) multi-line strings as block strings - SimonSapin, pull/724:
    Example before:

    "Example\n\nDescription description description"
    schema { query: MyQuery }

    After:

    """
    Example
    
    Description description description
    """
    schema { query: MyQuery }

Fixes

  • Limit recursion in validation - goto-bus-stop, pull/748 fixing issue/742:
    Validation now bails out of very long chains of definitions that refer to each other,
    even if they don't strictly form a cycle. These could previously cause extremely long validation
    times or stack overflows.

    The limit for input objects and directives is set at 32. For fragments, the limit is set at 100.
    Based on our datasets, real-world documents don't come anywhere close to this.

[email protected]

17 Nov 17:20
721e075
Compare
Choose a tag to compare

Features

  • parse_type parses a selection set with optional outer brackets - lrlna, pull/718 fixing issue/715
    This returns a SyntaxTree<Type> which instead of .document() -> cst::Document
    has .type() -> cst::Type.
    This is intended to parse the string value of a @field(type:) argument
    used in some Apollo Federation directives.
    let source = r#"[[NestedList!]]!"#;
    
    let parser = Parser::new(source);
    let cst: SyntaxTree<cst::Type> = parser.parse_type();
    let errors = cst.errors().collect::<Vec<_>>();
    assert_eq!(errors.len(), 0);

Fixes

  • Input object values can be empty - goto-bus-stop, pull/745 fixing issue/744
    apollo-parser version 0.7.3 introduced a regression where empty input objects failed to parse.
    This is now fixed.

    { field(argument: {}) }

[email protected]

17 Nov 17:20
208d2d7
Compare
Choose a tag to compare

Features

  • Helper features for Name and Type - SimonSapin, pull/739:
    • The name! macro also accepts an identifier:
      name!(Query) and name!("Query") create equivalent Name values.
    • InvalidNameError now contain a public NodeStr for the input string that is invalid,
      and implements Display, Debug, and Error traits.
    • Add TryFrom conversion to Name from NodeStr, &NodeStr, &str, String, and &String.
    • Add a ty! macro to build a static ast::Type using GraphQL-like syntax.
  • Add parsing an ast::Type from a string - lrlna and goto-bus-stop, pull/718 fixing issue/715

    Parses GraphQL type syntax:

    use apollo_compiler::ast::Type;
    let ty = Type::parse("[ListItem!]!")?;

Fixes

  • Fix list and null type validation bugs - goto-bus-stop, pull/746 fixing issue/738
    Previous versions of apollo-compiler accepted null inside a list even if the list item type
    was marked as required. Lists were also accepted as inputs to non-list fields. This is now
    fixed.

    input Args {
      string: String
      ints: [Int!]
    }
    type Query { example(args: Args): Int }
    query {
      example(args: {
        # Used to be accepted, now raises an error
        string: ["1"]
        # Used to be accepted, now raises an error
        ints: [1, 2, null, 4]
      })
    }

[email protected]

14 Nov 14:24
366714c
Compare
Choose a tag to compare

BREAKING

  • Make everything know their own name - SimonSapin, pull/727 fixing issue/708.

    In a few places (but not consistently) a name field
    was omitted from some structs used as map values
    on the basis that it would have been redundant with the map key.
    This reverts that decision,
    making it the user’s responsibility when mutating documents to keep names consistent.

    • Add a pub name: Name field to executable::Fragment as well as
      ScalarType, ObjectType, InterfaceType, EnumType, UnionType, and InputObjectType
      in schema.
    • Add a fn name(&self) -> &Name method to the schema::ExtendedType enum
    • Add a pub name: Option<Name> field to executable::Operation
    • Remove executable::OperationRef<'_>
      (which was equivalent to (Option<&Name>, &Node<Operation>)),
      replacing its uses with &Node<Operation>
  • Rename Directives and Diagnostics to DirectiveList and DiagnosticList -
    SimonSapin, pull/732 fixing issue/711.

    The previous names were too similar to Directive and Diagnostic (singular).

  • Rename ComponentStr to ComponentName - SimonSapin, pull/713
    and its node: NodeStr field to name: Name.

  • Assorted changed to GraphQL names - SimonSapin, pull/713 fixing issue/710.

    • Check validity of ast::Name.
      NodeStr is a smart string type with infallible conversion from &str.
      ast::Name used to be a type alias for NodeStr,
      leaving the possibility of creating one invalid in GraphQL syntax.
      Validation and serialization would not check this.
      Name is now a wrapper type for NodeStr.
      Its new constructor checks validity of the given string and returns a Result.
      A new name! macro (see below) creates a Name with compile-time checking.
    • OperationType::default_type_name returns a Name instead of &str
    • Type::new_named("x") is removed. Use Type::Named(name!("x")) instead.
    • ComponentStr is renamed to ComponentName.
      It no longer has infallible conversions from &str or String.
      Its node field is renamed to name;
      the type of that field is changed from NodeStr to Name.
    • NodeStr no longer has a to_component method, only Name does
    • Various function or method parameters changed from impl Into<Name> to Name,
      since there is no longer an infallible conversion from &str

Features

  • Add serialization support for everything - SimonSapin, pull/728.

    Schema, ExecutableDocument, and all AST types
    already supported serialization to GraphQL syntax
    through the Display trait and the .serialize() method.
    This is now also the case of all other Rust types
    representing some element of a GraphQL document:

    • schema::Directives
    • schema::ExtendedType
    • schema::ScalarType
    • schema::ObjectType
    • schema::InterfaceType
    • schema::EnumType
    • schema::UnionType
    • schema::InputObjectType
    • executable::Operation
    • executable::Fragment
    • executable::SelectionSet
    • executable::Selection
    • executable::Field
    • executable::InlineFragment
    • executable::FragmentSpread
    • executable::FieldSet
  • Assorted changed to GraphQL names - SimonSapin, pull/713 fixing issue/710.
    See also the BREAKING section above.

    • Add a name!("example") macro,
      to be imported with use apollo_compiler::name;.
      It creates an ast::Name from a string literal, with a compile-time validity checking.
      A Name created this way does not own allocated heap memory or a reference counter,
      so cloning it is extremely cheap.
    • Add allocation-free NodeStr::from_static.
      This mostly exists to support the name! macro, but can also be used on its own:
      let s = apollo_compiler::NodeStr::from_static(&"example");
      assert_eq!(s, "example");

Fixes

  • Fix crash in validation of self-referential fragments - goto-bus-stop, pull/733 fixing issue/716.
    Now fragments that cyclically reference themselves inside a nested field also produce a
    validation error, instead of causing a stack overflow crash.

[email protected]

08 Nov 02:51
95d9621
Compare
Choose a tag to compare

0.7.3 - 2023-11-07

Fixes

  • Less recursion in parser implementation - goto-bus-stop, pull/721 fixing issue/666
    The parser previously used recursive functions while parsing some repetitive nodes, like members of an enum:

    enum Alphabet { A B C D E F G etc }

    Even though this is a flat list, each member would use a recursive call. Having many members, or fields in a type
    definition, or arguments in a directive, would all contribute to the recursion limit.

    Those cases are now using iteration instead and no longer contribute to the recursion limit. The default recursion limit
    is unchanged at 500, but you could reduce it depending on your needs.

  • Fix overly permissive parsing of implements lists and union member types - goto-bus-stop, pull/721 fixing issue/659
    Previously these definitions were all accepted, despite missing or excessive & and | separators:
    type Ty implements A B
    type Ty implements A && B
    type Ty implements A & B &
    
    union Ty = A B
    union Ty = A || B
    union Ty = A | B |
    Now they report a syntax error.

[email protected]

03 Nov 09:52
f57b9cc
Compare
Choose a tag to compare

0.7.2 - 2023-11-03

Fixes

[email protected]

16 Oct 15:27
278dab3
Compare
Choose a tag to compare

1.0.0-beta.4 - 2023-10-16

Features

  • JSON Serialisable compiler diagnostics - lrlna and goto-bus-stop, pull/698:
    This change brings back JSON error format for diagnostics introduced by goto-bus-stop in pull/668 for [email protected]. As a result, diagnostics' line/column numbers are now also accessible as part of the public API.

    let json = expect_test::expect![[r#"
      {
        "message": "an executable document must not contain an object type definition",
        "locations": [
          {
            "line": 2,
            "column": 1
          }
        ]
      }"#]];
    let diagnostics = executable.validate(&schema).unwrap_err();
    diagnostics.iter().for_each(|diag| {
        assert_eq!(
            diag.get_line_column(),
            Some(GraphQLLocation { line: 2, column: 1 })
        );
        json.assert_eq(&serde_json::to_string_pretty(&diag.to_json()).unwrap());
    });

Fixes

  • Don’t emit a validation error for relying on argument default - SimonSapin, pull/700
    A field argument or directive argument was incorrectly considered required as soon as it had a non-null type, even if it had a default value.

[email protected]

13 Oct 16:36
58518e4
Compare
Choose a tag to compare

1.0.0-beta.3 - 2023-10-13

BREAKING

  • Keep source files in Arc<Map<…>> everywhere - SimonSapin, pull/696:
    Change struct fields from sources: IndexMap<FileId, Arc<SourceFile>> (in Schema) or source: Option<(FileId, Arc<SourceFile>)> (in Document, ExecutablDocument, FieldSet) to sources: SourceMap, with:
    pub type SourceMap = Arc<IndexMap<FileId, Arc<SourceFile>>>;
    Cases other than Schema still only have zero or one source when created by apollo-compiler, but it is now possible to make more sources available to diagnostics, for example when merging documents:
    Arc::make_mut(&mut doc1.sources).extend(doc2.sources.iter().map(|(k, v)| (*k, v.clone())));

Features

  • Add iteration over individual diagnostics - SimonSapin, pull/696:
    let schema = Schema::parse(input, "schema.graphql");
    if let Err(errors) = schema.validate() {
        for error in errors.iter() {
            eprintln!("{error}")
        }
    }

Fixes

  • Don’t panic in validation or omit diagnostics when a source location is missing - SimonSapin, pull/697:
    In apollo-compiler 0.11 every element of the HIR always had a source location because it always came from a parsed input file. In 1.0 source location is always optional. When a node relevant to some diagnostic does not have a source location, the diagnostic should still be emitted but its labels (each printing a bit of source code) may be missing. Essential information should therefore be in the main message, not only in labels.

[email protected]

10 Oct 15:41
c4fc479
Compare
Choose a tag to compare

0.7.1 - 2023-10-10

Features

  • parse_field_set parses a selection set with optional outer brackets - lrlna, pull/685 fixing issue/681
    This returns a SyntaxTree<SelectionSet> which instead of .document() -> cst::Document
    has .field_set() -> cst::SelectionSet.
    This is intended to parse string value of a FieldSet custom scalar
    used in some Apollo Federation directives.
    let source = r#"a { a }"#;
    
    let parser = Parser::new(source);
    let cst: SyntaxTree<cst::SelectionSet> = parser.parse_selection_set();
    let errors = cst.errors().collect::<Vec<_>>();
    assert_eq!(errors.len(), 0);

[email protected]

10 Oct 15:52
f3760db
Compare
Choose a tag to compare

1.0.0-beta.2 - 2023-10-10

BREAKING

Assorted Schema API changes by SimonSapin in pull/678:

  • Type of the schema_definition field changed
    from Option<SchemaDefinition> to SchemaDefinition.
    Default root operations based on object type names
    are now stored explicitly in SchemaDefinition.
    Serialization relies on a heuristic to decide on implicit schema definition.
  • Removed schema_definition_directives method: no longer having an Option allows
    field schema.schema_definition.directives to be accessed directly
  • Removed query_root_operation, mutation_root_operation, and subscription_root_operation
    methods. Instead schema.schema_definition.query etc can be accessed directly.

Features

  • Add executable::FieldSet for a selection set with optional outer brackets - lrlna, pull/685 fixing issue/681
    This is intended to parse string value of a FieldSet custom scalar
    used in some Apollo Federation directives in the context of a specific schema and type.
    Its validate method calls a subset of validation rules relevant to selection sets.
    which is not part of a document.

    let input = r#"
      type Query {
        id: ID
        organization: Org
      }
      type Org {
        id: ID
      }
    "#;
    let schema = Schema::parse(input, "schema.graphql");
    schema.validate().unwrap();
    let input = "id organization { id }";
    let field_set = FieldSet::parse(&schema, "Query", input, "field_set.graphql");
    field_set.validate(&schema).unwrap();
  • Add opt-in configuration for “orphan” extensions to be “adopted” - SimonSapin, pull/678

    Type extensions and schema extensions without a corresponding definition
    are normally ignored except for recording a validation error.
    In this new mode, an implicit empty definition to extend is generated instead.
    This behavious is not the default, as it's non-standard.
    Configure a schema builder to opt in:

    let input = "extend type Query { x: Int }";
    let schema = apollo_compiler::Schema::builder()
        .adopt_orphan_extensions()
        .parse(input, "schema.graphql")
        .build();
    schema.validate()?;

Fixes

  • Allow built-in directives to be redefined - SimonSapin, pull/684 fixing issue/656
  • Allow schema extensions to extend a schema definition implied by object types named after default root operations - SimonSapin, pull/678 fixing [issues/682]