├── .github └── workflows │ ├── codeql-analysis.yml │ ├── v1.yml │ └── v2.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── Makefile ├── README.md ├── cmd ├── directiveUnmarshalCode.go ├── gen.go └── root.go ├── doc.go ├── examples ├── chat │ ├── .gitignore │ ├── .gqlgen.yml │ ├── chat_test.go │ ├── generated.go │ ├── go.mod │ ├── go.sum │ ├── handler.go │ ├── models_gen.go │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── index.html │ ├── readme.md │ ├── resolvers.go │ ├── schema.graphql │ ├── server │ │ └── server.go │ ├── src │ │ ├── App.js │ │ ├── Room.js │ │ ├── components │ │ │ └── room.js │ │ └── index.js │ ├── start-server.sh │ └── util.go ├── federation │ ├── README.md │ ├── accounts │ │ ├── gqlgen.yml │ │ ├── graph │ │ │ ├── entity.resolvers.go │ │ │ ├── generated │ │ │ │ ├── federation.go │ │ │ │ └── generated.go │ │ │ ├── handler.go │ │ │ ├── model │ │ │ │ └── models_gen.go │ │ │ ├── resolver.go │ │ │ ├── schema.graphqls │ │ │ └── schema.resolvers.go │ │ └── server.go │ ├── gateway │ │ ├── datasource_poller.go │ │ ├── gateway.go │ │ ├── http │ │ │ ├── handler.go │ │ │ ├── http.go │ │ │ └── ws.go │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── products │ │ ├── gqlgen.yml │ │ ├── graph │ │ │ ├── entity.resolvers.go │ │ │ ├── generated │ │ │ │ ├── federation.go │ │ │ │ └── generated.go │ │ │ ├── handler.go │ │ │ ├── model │ │ │ │ └── models_gen.go │ │ │ ├── products.go │ │ │ ├── resolver.go │ │ │ ├── schema.graphqls │ │ │ ├── schema.resolvers.go │ │ │ └── variables.go │ │ └── server.go │ ├── reviews │ │ ├── gqlgen.yml │ │ ├── graph │ │ │ ├── entity.resolvers.go │ │ │ ├── generated │ │ │ │ ├── federation.go │ │ │ │ └── generated.go │ │ │ ├── handler.go │ │ │ ├── model │ │ │ │ ├── models.go │ │ │ │ └── models_gen.go │ │ │ ├── resolver.go │ │ │ ├── reviews.go │ │ │ ├── schema.graphqls │ │ │ └── schema.resolvers.go │ │ └── server.go │ └── start.sh └── kafka_pubsub │ ├── README.md │ ├── docker-compose-cluster.yml │ ├── docker-compose.yml │ ├── go.mod │ ├── go.sum │ ├── kafka_jaas.conf │ ├── main.go │ ├── transactional_producer │ ├── README.md │ ├── go.mod │ ├── go.sum │ └── main.go │ └── tyk-api-definition.json ├── go.mod ├── go.sum ├── internal └── pkg │ ├── quotes │ ├── quotes.go │ └── quotes_test.go │ ├── unsafebytes │ ├── unsafebytes.go │ └── unsafebytes_test.go │ ├── unsafeparser │ └── unsafeparser.go │ └── unsafeprinter │ └── unsafeprinter.go ├── main.go ├── pkg ├── ast │ ├── ast.go │ ├── ast_argument.go │ ├── ast_description.go │ ├── ast_directive.go │ ├── ast_directive_definition.go │ ├── ast_enum_type_definition.go │ ├── ast_enum_type_extension.go │ ├── ast_enum_value_definition.go │ ├── ast_field.go │ ├── ast_field_alias.go │ ├── ast_field_definition.go │ ├── ast_fragment_definition.go │ ├── ast_fragment_spread.go │ ├── ast_inline_fragment.go │ ├── ast_input_object_type_definition.go │ ├── ast_input_object_type_extension.go │ ├── ast_input_value_definition.go │ ├── ast_interface_type_definition.go │ ├── ast_interface_type_extension.go │ ├── ast_node.go │ ├── ast_node_kind.go │ ├── ast_node_kind_test.go │ ├── ast_object_field.go │ ├── ast_object_type_definition.go │ ├── ast_object_type_definition_test.go │ ├── ast_object_type_extension.go │ ├── ast_operation_definition.go │ ├── ast_operation_definition_test.go │ ├── ast_root_operation_type_definition.go │ ├── ast_root_operation_type_definition_test.go │ ├── ast_scalar_type_definition.go │ ├── ast_scalar_type_extension.go │ ├── ast_schema_definition.go │ ├── ast_schema_extension.go │ ├── ast_selection.go │ ├── ast_string.go │ ├── ast_test.go │ ├── ast_type.go │ ├── ast_type_test.go │ ├── ast_union_type_definition.go │ ├── ast_union_type_extension.go │ ├── ast_val_boolean_value.go │ ├── ast_val_enum_value.go │ ├── ast_val_float_value.go │ ├── ast_val_int_value.go │ ├── ast_val_list_value.go │ ├── ast_val_object_value.go │ ├── ast_val_string_value.go │ ├── ast_val_variable_value.go │ ├── ast_value.go │ ├── ast_value_test.go │ ├── ast_variable_definition.go │ ├── directive_location.go │ ├── directive_location_string.go │ ├── directive_location_test.go │ ├── document_pool.go │ ├── helpers.go │ ├── index.go │ ├── index_test.go │ ├── input.go │ └── path.go ├── astimport │ ├── astimport.go │ └── astimport_test.go ├── astnormalization │ ├── astnormalization.go │ ├── astnormalization_test.go │ ├── definition_normalization.go │ ├── definition_normalization_test.go │ ├── directive_include_skip.go │ ├── directive_include_skip_test.go │ ├── enum_type_extending.go │ ├── enum_type_extending_test.go │ ├── extends_directive.go │ ├── extends_directive_test.go │ ├── field_deduplication.go │ ├── field_deduplication_test.go │ ├── field_selection_merging.go │ ├── field_selection_merging_test.go │ ├── fragment_definition_removal.go │ ├── fragment_spread_inlining.go │ ├── fragment_spread_inlining_test.go │ ├── fragmentspread_depth.go │ ├── fragmentspread_depth_test.go │ ├── implicit_extend_root_operation.go │ ├── implicit_extend_root_operation_test.go │ ├── implicit_schema_definition.go │ ├── implicit_schema_definition_test.go │ ├── inject_input_default_values.go │ ├── inject_input_default_values_test.go │ ├── inline_fragment_merging.go │ ├── inline_fragment_merging_test.go │ ├── input_coercion_for_list.go │ ├── input_coercion_for_list_test.go │ ├── input_object_type_extending.go │ ├── input_object_type_extending_test.go │ ├── interface_type_extending.go │ ├── interface_type_extending_test.go │ ├── object_type_extending.go │ ├── object_type_extending_test.go │ ├── remove_self_aliasing.go │ ├── remove_self_aliasing_test.go │ ├── remove_type_extensions.go │ ├── remove_type_extensions_test.go │ ├── scalar_type_extending.go │ ├── scalar_type_extending_test.go │ ├── subgraph_sdl_normalization.go │ ├── subgraph_sdl_normalization_test.go │ ├── union_type_extending.go │ ├── union_type_extending_test.go │ ├── variables_default_value_extraction.go │ ├── variables_default_value_extraction_test.go │ ├── variables_extraction.go │ ├── variables_extraction_test.go │ ├── variables_unused_deletion.go │ └── variables_unused_deletion_test.go ├── astparser │ ├── errors.go │ ├── parser.go │ ├── parser_test.go │ ├── parser_token_helpers.go │ ├── testdata │ │ ├── big_schema.graphql │ │ ├── github.schema.graphql │ │ ├── introspection_normalized.graphql │ │ ├── introspectionquery.graphql │ │ ├── starwars.schema.graphql │ │ └── todo.graphql │ └── tokenizer.go ├── astprinter │ ├── astprinter.go │ ├── astprinter_test.go │ ├── fixtures │ │ ├── introspectionquery.golden │ │ └── starwars_schema_definition.golden │ └── testdata │ │ ├── introspectionquery.graphql │ │ └── starwars.schema.graphql ├── asttransform │ ├── asttransform.go │ ├── baseschema.go │ ├── baseschema_test.go │ ├── fixtures │ │ ├── complete.golden │ │ ├── custom_query_name.golden │ │ ├── mutation_only.golden │ │ ├── schema_missing.golden │ │ ├── simple.golden │ │ ├── subscription_only.golden │ │ ├── subscription_renamed.golden │ │ └── with_mutation_subscription.golden │ └── typename_visitor.go ├── astvalidation │ ├── definition_validation.go │ ├── definition_validation_test.go │ ├── operation_rule_all_variable_uses_defined.go │ ├── operation_rule_all_variables_used.go │ ├── operation_rule_argument_uniqueness.go │ ├── operation_rule_directives_defined.go │ ├── operation_rule_directives_in_valid_locations.go │ ├── operation_rule_directives_unique_per_location.go │ ├── operation_rule_document_contains_executable_operation.go │ ├── operation_rule_field_selection_merging.go │ ├── operation_rule_fragments.go │ ├── operation_rule_known_arguments.go │ ├── operation_rule_lone_anonymous_operation.go │ ├── operation_rule_operation_name_uniqueness.go │ ├── operation_rule_required_arguments.go │ ├── operation_rule_subscription_single_root_field.go │ ├── operation_rule_valid_arguments.go │ ├── operation_rule_validate_field_selections.go │ ├── operation_rule_values.go │ ├── operation_rule_variable_uniqueness.go │ ├── operation_rule_variables_are_input_types.go │ ├── operation_validation.go │ ├── operation_validation_test.go │ ├── overlapping_fields_test.go │ ├── reference │ │ ├── .gitignore │ │ ├── __tests__ │ │ │ ├── ExecutableDefinitionsRule-test.js │ │ │ ├── FieldsOnCorrectTypeRule-test.js │ │ │ ├── FragmentsOnCompositeTypesRule-test.js │ │ │ ├── KnownArgumentNamesRule-test.js │ │ │ ├── KnownDirectivesRule-test.js │ │ │ ├── KnownFragmentNamesRule-test.js │ │ │ ├── KnownTypeNamesRule-test.js │ │ │ ├── LoneAnonymousOperationRule-test.js │ │ │ ├── LoneSchemaDefinitionRule-test.js │ │ │ ├── NoDeprecatedCustomRule-test.js │ │ │ ├── NoFragmentCyclesRule-test.js │ │ │ ├── NoSchemaIntrospectionCustomRule-test.js │ │ │ ├── NoUndefinedVariablesRule-test.js │ │ │ ├── NoUnusedFragmentsRule-test.js │ │ │ ├── NoUnusedVariablesRule-test.js │ │ │ ├── OverlappingFieldsCanBeMergedRule-test.js │ │ │ ├── PossibleFragmentSpreadsRule-test.js │ │ │ ├── PossibleTypeExtensionsRule-test.js │ │ │ ├── ProvidedRequiredArgumentsRule-test.js │ │ │ ├── ScalarLeafsRule-test.js │ │ │ ├── SingleFieldSubscriptionsRule-test.js │ │ │ ├── UniqueArgumentNamesRule-test.js │ │ │ ├── UniqueDirectiveNamesRule-test.js │ │ │ ├── UniqueDirectivesPerLocationRule-test.js │ │ │ ├── UniqueEnumValueNamesRule-test.js │ │ │ ├── UniqueFieldDefinitionNamesRule-test.js │ │ │ ├── UniqueFragmentNamesRule-test.js │ │ │ ├── UniqueInputFieldNamesRule-test.js │ │ │ ├── UniqueOperationNamesRule-test.js │ │ │ ├── UniqueOperationTypesRule-test.js │ │ │ ├── UniqueTypeNamesRule-test.js │ │ │ ├── UniqueVariableNamesRule-test.js │ │ │ ├── ValuesOfCorrectTypeRule-test.js │ │ │ ├── VariablesAreInputTypesRule-test.js │ │ │ ├── VariablesInAllowedPositionRule-test.js │ │ │ ├── harness.js │ │ │ └── validation-test.js │ │ ├── gen.sh │ │ ├── main.go │ │ ├── replacements.yml │ │ └── testsgo │ │ │ ├── ExecutableDefinitionsRule_test.go │ │ │ ├── FieldsOnCorrectTypeRule_test.go │ │ │ ├── FragmentsOnCompositeTypesRule_test.go │ │ │ ├── KnownArgumentNamesRule_test.go │ │ │ ├── KnownDirectivesRule_test.go │ │ │ ├── KnownFragmentNamesRule_test.go │ │ │ ├── KnownTypeNamesRule_test.go │ │ │ ├── LoneAnonymousOperationRule_test.go │ │ │ ├── LoneSchemaDefinitionRule_test.go │ │ │ ├── NoFragmentCyclesRule_test.go │ │ │ ├── NoUndefinedVariablesRule_test.go │ │ │ ├── NoUnusedFragmentsRule_test.go │ │ │ ├── NoUnusedVariablesRule_test.go │ │ │ ├── OverlappingFieldsCanBeMergedRule_test.go │ │ │ ├── PossibleFragmentSpreadsRule_test.go │ │ │ ├── PossibleTypeExtensionsRule_test.go │ │ │ ├── ProvidedRequiredArgumentsRule_test.go │ │ │ ├── ScalarLeafsRule_test.go │ │ │ ├── SingleFieldSubscriptionsRule_test.go │ │ │ ├── UniqueArgumentNamesRule_test.go │ │ │ ├── UniqueDirectiveNamesRule_test.go │ │ │ ├── UniqueDirectivesPerLocationRule_test.go │ │ │ ├── UniqueEnumValueNamesRule_test.go │ │ │ ├── UniqueFieldDefinitionNamesRule_test.go │ │ │ ├── UniqueFragmentNamesRule_test.go │ │ │ ├── UniqueInputFieldNamesRule_test.go │ │ │ ├── UniqueOperationNamesRule_test.go │ │ │ ├── UniqueOperationTypesRule_test.go │ │ │ ├── UniqueTypeNamesRule_test.go │ │ │ ├── UniqueVariableNamesRule_test.go │ │ │ ├── ValuesOfCorrectTypeRule_test.go │ │ │ ├── VariablesAreInputTypesRule_test.go │ │ │ ├── VariablesInAllowedPositionRule_test.go │ │ │ ├── harness_test.go │ │ │ └── test_schema.graphql │ ├── rule.go │ ├── rule_implement_transitive_interfaces.go │ ├── rule_implement_transitive_interfaces_test.go │ ├── rule_implementing_types_are_supersets.go │ ├── rule_implementing_types_are_supersets_test.go │ ├── rule_known_type_names.go │ ├── rule_known_type_names_test.go │ ├── rule_populated_type_bodies.go │ ├── rule_populated_type_bodies_test.go │ ├── rule_require_defined_types_for_extensions.go │ ├── rule_require_defined_types_for_extensions_test.go │ ├── rule_unique_enum_value_names.go │ ├── rule_unique_enum_value_names_test.go │ ├── rule_unique_field_definition_names.go │ ├── rule_unique_field_definition_names_test.go │ ├── rule_unique_operation_types.go │ ├── rule_unique_operation_types_test.go │ ├── rule_unique_type_names.go │ ├── rule_unique_type_names_test.go │ ├── rule_unique_union_member_types.go │ ├── rule_unique_union_member_types_test.go │ ├── validation_state.go │ └── validation_state_string.go ├── astvisitor │ ├── astvisitor.go │ ├── fixtures │ │ ├── path.golden │ │ ├── schema_visitor.golden │ │ ├── visitor.golden │ │ └── visitor_skip.golden │ ├── simplevisitor.go │ ├── simplevisitor_test.go │ ├── visitor.go │ └── visitor_test.go ├── codegen │ ├── codegen.go │ ├── codegen_test.go │ ├── fixtures │ │ └── DataSource.golden │ ├── manual.go │ ├── manual_test.go │ └── testdata │ │ └── schema.graphql ├── engine │ ├── datasource │ │ ├── graphql_datasource │ │ │ ├── batch.go │ │ │ ├── batch_test.go │ │ │ ├── graphql_datasource.go │ │ │ ├── graphql_datasource_test.go │ │ │ ├── graphql_sse_handler.go │ │ │ ├── graphql_sse_handler_test.go │ │ │ ├── graphql_subscription_client.go │ │ │ ├── graphql_subscription_client_test.go │ │ │ ├── graphql_tws_handler.go │ │ │ ├── graphql_tws_handler_test.go │ │ │ ├── graphql_ws_handler.go │ │ │ ├── graphql_ws_handler_test.go │ │ │ └── graphql_ws_proto_types.go │ │ ├── httpclient │ │ │ ├── httpclient.go │ │ │ ├── httpclient_test.go │ │ │ └── nethttpclient.go │ │ ├── introspection_datasource │ │ │ ├── config_factory.go │ │ │ ├── factory.go │ │ │ ├── fixtures │ │ │ │ ├── enum_values_with_deprecated.golden │ │ │ │ ├── enum_values_without_deprecated.golden │ │ │ │ ├── fields_with_deprecated.golden │ │ │ │ ├── fields_without_deprecated.golden │ │ │ │ ├── not_existing_type.golden │ │ │ │ ├── schema_introspection.golden │ │ │ │ ├── schema_introspection_with_custom_root_operation_types.golden │ │ │ │ └── type_introspection.golden │ │ │ ├── input.go │ │ │ ├── input_test.go │ │ │ ├── planner.go │ │ │ ├── planner_test.go │ │ │ ├── source.go │ │ │ └── source_test.go │ │ ├── kafka_datasource │ │ │ ├── config.go │ │ │ ├── config_test.go │ │ │ ├── kafka_consumer_group.go │ │ │ ├── kafka_consumer_group_test.go │ │ │ ├── kafka_datasource.go │ │ │ ├── kafka_datasource_test.go │ │ │ └── sarama_config_parameters_test.go │ │ ├── rest_datasource │ │ │ ├── rest_datasource.go │ │ │ └── rest_datasource_test.go │ │ └── staticdatasource │ │ │ ├── static_datasource.go │ │ │ └── static_datasource_test.go │ ├── datasourcetesting │ │ └── datasourcetesting.go │ ├── plan │ │ ├── analyze_plan_kind.go │ │ ├── analyze_plan_kind_test.go │ │ ├── local_type_field_extractor.go │ │ ├── local_type_field_extractor_test.go │ │ ├── plan.go │ │ ├── plan_closer_test.go │ │ ├── plan_test.go │ │ ├── required_field_extractor.go │ │ └── required_field_extractor_test.go │ └── resolve │ │ ├── dataloader.go │ │ ├── dataloader.md │ │ ├── dataloader_test.go │ │ ├── defer_test.go │ │ ├── engine.md │ │ ├── fetcher.go │ │ ├── inputtemplate.go │ │ ├── inputtemplate_test.go │ │ ├── resolve.go │ │ ├── resolve_mock_test.go │ │ ├── resolve_test.go │ │ ├── stream_test.go │ │ ├── testdata │ │ ├── defer_1.json │ │ ├── defer_2.json │ │ ├── defer_3.json │ │ ├── posts.json │ │ ├── response_without_defer.json │ │ ├── stream_1.json │ │ ├── stream_2.json │ │ ├── stream_3.json │ │ ├── stream_4.json │ │ ├── stream_5.json │ │ ├── stream_6.json │ │ ├── stream_7.json │ │ ├── stream_8.json │ │ ├── stream_9.json │ │ └── users.json │ │ └── variable.go ├── escape │ ├── bytes.go │ ├── bytes_test.go │ └── escape.go ├── execution │ ├── datasource │ │ ├── datasource.go │ │ ├── datasource_graphql.go │ │ ├── datasource_http_json.go │ │ ├── datasource_http_polling_stream.go │ │ ├── datasource_mqtt.go │ │ ├── datasource_pipeline.go │ │ ├── datasource_schema.go │ │ ├── datasource_static.go │ │ ├── datasource_type.go │ │ └── hooks.go │ ├── datasource_config.go │ ├── datasource_graphql_test.go │ ├── datasource_http_json_test.go │ ├── datasource_pipeline_test.go │ ├── execution.go │ ├── execution_test.go │ ├── fixtures │ │ ├── execution.golden │ │ ├── handler_render_graphql_definitions.golden │ │ ├── introspection_execution.golden │ │ └── render_graphql_definitions.golden │ ├── graphql_definitions │ │ ├── directives │ │ │ ├── graphql_datasource.graphql │ │ │ ├── http_json_datasource.graphql │ │ │ ├── http_polling_stream_datasource.graphql │ │ │ ├── mapping.graphql │ │ │ ├── mqtt_datasource.graphql │ │ │ ├── nats_datasource.graphql │ │ │ ├── pipeline_datasource.graphql │ │ │ ├── static_datasource.graphql │ │ │ ├── transformation.graphql │ │ │ └── wasm_datasource.graphql │ │ ├── enums │ │ │ ├── http_method.graphql │ │ │ ├── mapping_mode.graphql │ │ │ ├── parameter_source.graphql │ │ │ └── transformation_mode.graphql │ │ └── inputs │ │ │ ├── header.graphql │ │ │ ├── parameter.graphql │ │ │ └── statuscode_typename_mapping.graphql │ ├── handler.go │ ├── handler_test.go │ ├── jsonvaluetype.go │ ├── jsonvaluetype_string.go │ ├── jsonvaluetype_test.go │ ├── planning.go │ ├── planning_test.go │ ├── testdata │ │ ├── memory.wasm │ │ └── simple_pipeline.json │ ├── transformation.go │ └── transformation_test.go ├── fastbuffer │ ├── fastbuffer.go │ └── fastbuffer_test.go ├── federation │ ├── fixtures │ │ └── federated_schema.golden │ ├── schema.go │ ├── schema_test.go │ └── sdlmerge │ │ ├── collect_entities.go │ │ ├── collect_entities_test.go │ │ ├── enum_type_extending.go │ │ ├── enum_type_extending_test.go │ │ ├── input_type_extending.go │ │ ├── input_type_extending_test.go │ │ ├── interface_type_extending.go │ │ ├── interface_type_extending_test.go │ │ ├── merge_duplicated_fields.go │ │ ├── object_type_extending.go │ │ ├── object_type_extending_test.go │ │ ├── remove_duplicate_fielded_shared_types.go │ │ ├── remove_duplicate_fielded_shared_types_test.go │ │ ├── remove_duplicate_fieldless_shared_types.go │ │ ├── remove_duplicate_fieldless_shared_types_test.go │ │ ├── remove_empty_object_type_definition.go │ │ ├── remove_empty_object_type_definition_test.go │ │ ├── remove_field_definition_by_directive.go │ │ ├── remove_field_definition_by_directive_test.go │ │ ├── remove_field_definition_directive.go │ │ ├── remove_field_definition_directive_test.go │ │ ├── remove_interface_definition_directive.go │ │ ├── remove_interface_definition_directive_test.go │ │ ├── remove_object_type_definition_directive.go │ │ ├── remove_object_type_definition_directive_test.go │ │ ├── remove_type_extensions.go │ │ ├── remove_type_extensions_test.go │ │ ├── scalar_type_extending.go │ │ ├── scalar_type_extending_test.go │ │ ├── sdlmerge.go │ │ ├── sdlmerge_test.go │ │ ├── shared_types.go │ │ ├── testdata │ │ └── validate-subgraph │ │ │ ├── lack-definition-non-null.graphqls │ │ │ ├── lack-definition.graphqls │ │ │ ├── lack-extend-definition-non-null.graphqls │ │ │ ├── lack-extend-definition.graphqls │ │ │ ├── well-defined-non-null.graphqls │ │ │ └── well-defined.graphqls │ │ ├── union_type_extending.go │ │ └── union_type_extending_test.go ├── graphql │ ├── complexity.go │ ├── config_factory_federation.go │ ├── config_factory_federation_test.go │ ├── config_factory_proxy.go │ ├── config_factory_proxy_test.go │ ├── engine_config_v2.go │ ├── engine_config_v2_test.go │ ├── errors.go │ ├── errors_test.go │ ├── execution_engine.go │ ├── execution_engine_test.go │ ├── execution_engine_v2.go │ ├── execution_engine_v2_custom.go │ ├── execution_engine_v2_custom_test.go │ ├── execution_engine_v2_test.go │ ├── extractor.go │ ├── extractor_test.go │ ├── fixtures │ │ └── introspection_response.golden │ ├── input_validation.go │ ├── input_validation_test.go │ ├── lookup.go │ ├── lookup_test.go │ ├── normalization.go │ ├── normalization_test.go │ ├── request.go │ ├── request_fields_validator.go │ ├── request_fields_validator_test.go │ ├── request_test.go │ ├── response.go │ ├── schema.go │ ├── schema_test.go │ ├── starwars_helpers_test.go │ ├── subscription.go │ ├── types.go │ ├── validation.go │ └── validation_test.go ├── graphqlerrors │ └── location.go ├── graphqljsonschema │ ├── jsonschema.go │ └── jsonschema_test.go ├── http │ ├── handler.go │ ├── handler_test.go │ ├── http.go │ ├── ws.go │ ├── ws_connection_init.json │ ├── ws_start.json │ └── ws_test.go ├── imports │ ├── fixtures │ │ ├── render_result.golden │ │ ├── scanner_regex.golden │ │ ├── scanner_regex_render.golden │ │ └── scanner_result.golden │ ├── graphql_file.go │ ├── graphql_file_test.go │ ├── imports.go │ ├── imports_test.go │ └── testdata │ │ ├── cycle │ │ ├── a │ │ │ └── a.graphql │ │ └── b │ │ │ └── b.graphql │ │ ├── deep │ │ └── deeper │ │ │ ├── custom_types.graphql │ │ │ └── non_graphql.txt │ │ ├── import_cycle.graphql │ │ ├── nested │ │ └── nested.graphql │ │ ├── nested2 │ │ └── nested2.graphql │ │ ├── regexonly │ │ ├── flat.graphql │ │ ├── mutation.graphql │ │ └── query.graphql │ │ ├── scalars │ │ └── json.graphql │ │ ├── schema.graphql │ │ └── types │ │ ├── mutation.graphql │ │ └── query.graphql ├── introspection │ ├── converter.go │ ├── converter_test.go │ ├── fixtures │ │ ├── interfaces_implementing_interfaces.golden │ │ ├── starwars.golden │ │ └── starwars_introspected.golden │ ├── generator.go │ ├── generator_test.go │ ├── introspection.go │ ├── introspection_enum.go │ ├── introspection_test.go │ └── testdata │ │ ├── interfaces_implementing_interfaces.graphql │ │ ├── out_swapi_introspection_response.json │ │ ├── starwars.schema.graphql │ │ └── swapi_introspection_response.json ├── lexer │ ├── fixtures │ │ └── introspection_lexed.golden │ ├── identkeyword │ │ ├── identkeyword.go │ │ └── identkeyword_string.go │ ├── keyword │ │ ├── keyword.go │ │ └── keyword_string.go │ ├── lexer.go │ ├── lexer_test.go │ ├── literal │ │ └── literal.go │ ├── position │ │ └── position.go │ ├── runes │ │ └── runes.go │ └── token │ │ └── token.go ├── middleware │ ├── middleware.go │ └── operation_complexity │ │ ├── operation_complexity.go │ │ └── operation_complexity_test.go ├── operationreport │ ├── externalerror.go │ ├── externalerror_test.go │ ├── operationreport.go │ └── operationreport_test.go ├── playground │ ├── files │ │ ├── favicon.png │ │ ├── logo.png │ │ ├── playground.css │ │ ├── playground.html │ │ └── playground.js │ ├── fixtures │ │ └── handlers.golden │ ├── playground.go │ └── playground_test.go ├── pool │ ├── bytesbuffer.go │ ├── fastbuffer.go │ └── hash64.go ├── postprocess │ ├── datasourceinput.go │ ├── datasourceinput_test.go │ ├── defer.go │ ├── defer_test.go │ ├── fetchinput.go │ ├── injectheader.go │ ├── injectheader_test.go │ ├── modifyheader.go │ ├── modifyheader_test.go │ ├── postprocess.go │ ├── postprocess_test.go │ ├── stream.go │ └── stream_test.go ├── repair │ ├── repair.go │ ├── sdl.go │ └── sdl_test.go ├── starwars │ ├── starwars.go │ └── testdata │ │ ├── mutations │ │ └── create_review.mutation │ │ ├── queries │ │ ├── directives_include.query │ │ ├── directives_skip.query │ │ ├── droid_with_arg.query │ │ ├── droid_with_arg_and_var.query │ │ ├── fragments.query │ │ ├── hero_with_aliases.query │ │ ├── hero_with_operation_name.query │ │ ├── inline_fragments.query │ │ ├── interface_fragments_on_union.graphql │ │ ├── introspection.query │ │ ├── invalid.query │ │ ├── invalid_fragments.query │ │ ├── multi_queries.query │ │ ├── multi_queries_with_arguments.query │ │ ├── simple_hero.query │ │ └── union.query │ │ ├── star_wars.graphql │ │ └── subscriptions │ │ └── remaining_jedis.subscription ├── subscription │ ├── constants.go │ ├── context.go │ ├── context_test.go │ ├── engine.go │ ├── engine_mock_test.go │ ├── engine_test.go │ ├── executor.go │ ├── executor_mock_test.go │ ├── executor_v1.go │ ├── executor_v2.go │ ├── handler.go │ ├── handler_mock_test.go │ ├── handler_test.go │ ├── init.go │ ├── legacy_handler.go │ ├── legacy_handler_test.go │ ├── mock_client_test.go │ ├── time_out.go │ ├── time_out_test.go │ ├── transport_client.go │ ├── transport_client_mock_test.go │ └── websocket │ │ ├── client.go │ │ ├── client_test.go │ │ ├── engine_mock_test.go │ │ ├── handler.go │ │ ├── handler_test.go │ │ ├── init.go │ │ ├── protocol_graphql_transport_ws.go │ │ ├── protocol_graphql_transport_ws_test.go │ │ ├── protocol_graphql_ws.go │ │ └── protocol_graphql_ws_test.go ├── testing │ ├── federationtesting │ │ ├── accounts │ │ │ ├── gqlgen.yml │ │ │ ├── graph │ │ │ │ ├── entity.resolvers.go │ │ │ │ ├── generated │ │ │ │ │ ├── federation.go │ │ │ │ │ └── generated.go │ │ │ │ ├── handler.go │ │ │ │ ├── histories.go │ │ │ │ ├── model │ │ │ │ │ └── models_gen.go │ │ │ │ ├── resolver.go │ │ │ │ ├── schema.graphqls │ │ │ │ ├── schema.resolvers.go │ │ │ │ └── wallets.go │ │ │ └── handler.go │ │ ├── federation_intergation_test.go │ │ ├── gateway │ │ │ ├── datasource_poller.go │ │ │ ├── gateway.go │ │ │ ├── http │ │ │ │ ├── handler.go │ │ │ │ ├── http.go │ │ │ │ └── ws.go │ │ │ └── main.go │ │ ├── graphql_client_test.go │ │ ├── products │ │ │ ├── gqlgen.yml │ │ │ ├── graph │ │ │ │ ├── entity.resolvers.go │ │ │ │ ├── generated │ │ │ │ │ ├── federation.go │ │ │ │ │ └── generated.go │ │ │ │ ├── handler.go │ │ │ │ ├── model │ │ │ │ │ └── models_gen.go │ │ │ │ ├── products.go │ │ │ │ ├── resolver.go │ │ │ │ ├── schema.graphqls │ │ │ │ ├── schema.resolvers.go │ │ │ │ └── variables.go │ │ │ └── handler.go │ │ ├── reviews │ │ │ ├── gqlgen.yml │ │ │ ├── graph │ │ │ │ ├── attachments.go │ │ │ │ ├── entity.resolvers.go │ │ │ │ ├── generated │ │ │ │ │ ├── federation.go │ │ │ │ │ └── generated.go │ │ │ │ ├── handler.go │ │ │ │ ├── model │ │ │ │ │ ├── models.go │ │ │ │ │ └── models_gen.go │ │ │ │ ├── resolver.go │ │ │ │ ├── reviews.go │ │ │ │ ├── schema.graphqls │ │ │ │ └── schema.resolvers.go │ │ │ └── handler.go │ │ ├── testdata │ │ │ ├── mutations │ │ │ │ └── mutation_with_variables.query │ │ │ ├── queries │ │ │ │ ├── complex_nesting.graphql │ │ │ │ ├── interface.query │ │ │ │ ├── interface_fragment_on_object.graphql │ │ │ │ ├── interface_fragments_on_union.graphql │ │ │ │ ├── merged_field.graphql │ │ │ │ ├── multiple_queries.query │ │ │ │ ├── multiple_queries_with_nested_fragments.query │ │ │ │ ├── multiple_queries_with_union_return.query │ │ │ │ ├── multiple_upstream.query │ │ │ │ ├── object_fragment_on_interface.graphql │ │ │ │ ├── single_upstream.query │ │ │ │ └── union.query │ │ │ └── subscriptions │ │ │ │ └── subscription.query │ │ └── util.go │ ├── goldie │ │ ├── goldie.go │ │ ├── goldie_posix.go │ │ └── goldie_win.go │ └── subscriptiontesting │ │ ├── .gqlgen.yml │ │ ├── chat_test.go │ │ ├── generated.go │ │ ├── handler.go │ │ ├── models_gen.go │ │ ├── resolvers.go │ │ ├── schema.graphql │ │ └── util.go └── variablevalidator │ ├── variablevalidator.go │ └── variablevalidator_test.go ├── reimport.sh └── v2 ├── LICENSE ├── Makefile ├── README.md ├── assets └── logo.png ├── doc.go ├── examples ├── chat │ ├── .gitignore │ ├── .gqlgen.yml │ ├── chat_test.go │ ├── generated.go │ ├── go.mod │ ├── go.sum │ ├── handler.go │ ├── models_gen.go │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── index.html │ ├── readme.md │ ├── resolvers.go │ ├── schema.graphql │ ├── server │ │ └── server.go │ ├── src │ │ ├── App.js │ │ ├── Room.js │ │ ├── components │ │ │ └── room.js │ │ └── index.js │ ├── start-server.sh │ └── util.go ├── federation │ ├── README.md │ ├── accounts │ │ ├── gqlgen.yml │ │ ├── graph │ │ │ ├── entity.resolvers.go │ │ │ ├── generated │ │ │ │ ├── federation.go │ │ │ │ └── generated.go │ │ │ ├── handler.go │ │ │ ├── model │ │ │ │ └── models_gen.go │ │ │ ├── resolver.go │ │ │ ├── schema.graphqls │ │ │ └── schema.resolvers.go │ │ └── server.go │ ├── gateway │ │ ├── datasource_poller.go │ │ ├── gateway.go │ │ ├── http │ │ │ ├── handler.go │ │ │ ├── http.go │ │ │ └── ws.go │ │ └── main.go │ ├── go.mod │ ├── go.sum │ ├── products │ │ ├── gqlgen.yml │ │ ├── graph │ │ │ ├── entity.resolvers.go │ │ │ ├── generated │ │ │ │ ├── federation.go │ │ │ │ └── generated.go │ │ │ ├── handler.go │ │ │ ├── model │ │ │ │ └── models_gen.go │ │ │ ├── products.go │ │ │ ├── resolver.go │ │ │ ├── schema.graphqls │ │ │ ├── schema.resolvers.go │ │ │ └── variables.go │ │ └── server.go │ ├── reviews │ │ ├── gqlgen.yml │ │ ├── graph │ │ │ ├── entity.resolvers.go │ │ │ ├── generated │ │ │ │ ├── federation.go │ │ │ │ └── generated.go │ │ │ ├── handler.go │ │ │ ├── model │ │ │ │ └── models_gen.go │ │ │ ├── resolver.go │ │ │ ├── reviews.go │ │ │ └── schema.graphqls │ │ └── server.go │ ├── start.sh │ └── tools.go └── kafka_pubsub │ ├── README.md │ ├── docker-compose-cluster.yml │ ├── docker-compose.yml │ ├── example_datasources.json │ ├── example_field_configs.json │ ├── go.mod │ ├── go.sum │ ├── kafka_jaas.conf │ ├── main.go │ ├── schema.graphql │ └── transactional_producer │ ├── README.md │ ├── go.mod │ ├── go.sum │ └── main.go ├── go.mod ├── go.sum ├── internal └── pkg │ ├── gocompat │ └── .gitkeep │ ├── quotes │ ├── quotes.go │ └── quotes_test.go │ ├── unsafebytes │ ├── unsafebytes.go │ └── unsafebytes_test.go │ ├── unsafeparser │ └── unsafeparser.go │ ├── unsafeprinter │ └── unsafeprinter.go │ └── xcontext │ └── xcontext.go └── pkg ├── ast ├── ast.go ├── ast_argument.go ├── ast_description.go ├── ast_directive.go ├── ast_directive_definition.go ├── ast_enum_type_definition.go ├── ast_enum_type_extension.go ├── ast_enum_value_definition.go ├── ast_field.go ├── ast_field_alias.go ├── ast_field_definition.go ├── ast_fragment_definition.go ├── ast_fragment_spread.go ├── ast_inline_fragment.go ├── ast_input_object_type_definition.go ├── ast_input_object_type_extension.go ├── ast_input_value_definition.go ├── ast_interface_type_definition.go ├── ast_interface_type_extension.go ├── ast_node.go ├── ast_node_kind.go ├── ast_node_kind_test.go ├── ast_object_field.go ├── ast_object_type_definition.go ├── ast_object_type_definition_test.go ├── ast_object_type_extension.go ├── ast_operation_definition.go ├── ast_operation_definition_test.go ├── ast_root_operation_type_definition.go ├── ast_root_operation_type_definition_test.go ├── ast_scalar_type_definition.go ├── ast_scalar_type_extension.go ├── ast_schema_definition.go ├── ast_schema_extension.go ├── ast_selection.go ├── ast_string.go ├── ast_test.go ├── ast_type.go ├── ast_type_test.go ├── ast_union_type_definition.go ├── ast_union_type_extension.go ├── ast_val_boolean_value.go ├── ast_val_enum_value.go ├── ast_val_float_value.go ├── ast_val_int_value.go ├── ast_val_list_value.go ├── ast_val_object_value.go ├── ast_val_string_value.go ├── ast_val_variable_value.go ├── ast_value.go ├── ast_value_test.go ├── ast_variable_definition.go ├── directive_location.go ├── directive_location_string.go ├── directive_location_test.go ├── helpers.go ├── index.go ├── index_test.go ├── input.go └── path.go ├── astimport ├── astimport.go └── astimport_test.go ├── astjson ├── astjson.go └── astjson_test.go ├── astnormalization ├── abstract_field_normalizer.go ├── astnormalization.go ├── astnormalization_test.go ├── definition_normalization.go ├── definition_normalization_test.go ├── directive_include_skip.go ├── directive_include_skip_test.go ├── enum_type_extending.go ├── enum_type_extending_test.go ├── extends_directive.go ├── extends_directive_test.go ├── field_deduplication.go ├── field_deduplication_test.go ├── field_selection_merging.go ├── field_selection_merging_test.go ├── fragment_definition_removal.go ├── fragment_spread_inlining.go ├── fragment_spread_inlining_test.go ├── fragmentspread_depth.go ├── fragmentspread_depth_test.go ├── implicit_extend_root_operation.go ├── implicit_extend_root_operation_test.go ├── implicit_schema_definition.go ├── implicit_schema_definition_test.go ├── inject_input_default_values.go ├── inject_input_default_values_test.go ├── inline_fragment_add_on_type.go ├── inline_fragment_add_on_type_test.go ├── inline_fragment_selection_merging.go ├── inline_fragment_selection_merging_test.go ├── inline_selections_from_inline_fragments.go ├── inline_selections_from_inline_fragments_test.go ├── input_coercion_for_list.go ├── input_coercion_for_list_test.go ├── input_object_type_extending.go ├── input_object_type_extending_test.go ├── interface_type_extending.go ├── interface_type_extending_test.go ├── object_type_extending.go ├── object_type_extending_test.go ├── operation_definition_removal.go ├── remove_self_aliasing.go ├── remove_self_aliasing_test.go ├── remove_type_extensions.go ├── remove_type_extensions_test.go ├── scalar_type_extending.go ├── scalar_type_extending_test.go ├── subgraph_sdl_normalization.go ├── subgraph_sdl_normalization_test.go ├── union_type_extending.go ├── union_type_extending_test.go ├── variables_default_value_extraction.go ├── variables_default_value_extraction_test.go ├── variables_extraction.go ├── variables_extraction_test.go ├── variables_unused_deletion.go └── variables_unused_deletion_test.go ├── astparser ├── errors.go ├── parser.go ├── parser_test.go ├── parser_token_helpers.go ├── testdata │ ├── big_schema.graphql │ ├── github.schema.graphql │ ├── introspection_normalized.graphql │ ├── introspectionquery.graphql │ ├── starwars.schema.graphql │ └── todo.graphql └── tokenizer.go ├── astprinter ├── astprinter.go ├── astprinter_test.go ├── fixtures │ ├── introspectionquery.golden │ └── starwars_schema_definition.golden └── testdata │ ├── introspectionquery.graphql │ └── starwars.schema.graphql ├── asttransform ├── asttransform.go ├── baseschema.go ├── baseschema_test.go ├── fixtures │ ├── complete.golden │ ├── custom_query_name.golden │ ├── mutation_only.golden │ ├── schema_missing.golden │ ├── simple.golden │ ├── subscription_only.golden │ ├── subscription_renamed.golden │ └── with_mutation_subscription.golden └── typename_visitor.go ├── astvalidation ├── definition_validation.go ├── definition_validation_test.go ├── operation_rule_all_variable_uses_defined.go ├── operation_rule_all_variables_used.go ├── operation_rule_argument_uniqueness.go ├── operation_rule_directives_defined.go ├── operation_rule_directives_in_valid_locations.go ├── operation_rule_directives_unique_per_location.go ├── operation_rule_document_contains_executable_operation.go ├── operation_rule_field_selection_merging.go ├── operation_rule_fragments.go ├── operation_rule_known_arguments.go ├── operation_rule_lone_anonymous_operation.go ├── operation_rule_operation_name_uniqueness.go ├── operation_rule_required_arguments.go ├── operation_rule_subscription_single_root_field.go ├── operation_rule_valid_arguments.go ├── operation_rule_validate_field_selections.go ├── operation_rule_values.go ├── operation_rule_variable_uniqueness.go ├── operation_rule_variables_are_input_types.go ├── operation_validation.go ├── operation_validation_test.go ├── overlapping_fields_test.go ├── reference │ ├── .gitignore │ ├── __tests__ │ │ ├── ExecutableDefinitionsRule-test.js │ │ ├── FieldsOnCorrectTypeRule-test.js │ │ ├── FragmentsOnCompositeTypesRule-test.js │ │ ├── KnownArgumentNamesRule-test.js │ │ ├── KnownDirectivesRule-test.js │ │ ├── KnownFragmentNamesRule-test.js │ │ ├── KnownTypeNamesRule-test.js │ │ ├── LoneAnonymousOperationRule-test.js │ │ ├── LoneSchemaDefinitionRule-test.js │ │ ├── NoDeprecatedCustomRule-test.js │ │ ├── NoFragmentCyclesRule-test.js │ │ ├── NoSchemaIntrospectionCustomRule-test.js │ │ ├── NoUndefinedVariablesRule-test.js │ │ ├── NoUnusedFragmentsRule-test.js │ │ ├── NoUnusedVariablesRule-test.js │ │ ├── OverlappingFieldsCanBeMergedRule-test.js │ │ ├── PossibleFragmentSpreadsRule-test.js │ │ ├── PossibleTypeExtensionsRule-test.js │ │ ├── ProvidedRequiredArgumentsRule-test.js │ │ ├── ScalarLeafsRule-test.js │ │ ├── SingleFieldSubscriptionsRule-test.js │ │ ├── UniqueArgumentNamesRule-test.js │ │ ├── UniqueDirectiveNamesRule-test.js │ │ ├── UniqueDirectivesPerLocationRule-test.js │ │ ├── UniqueEnumValueNamesRule-test.js │ │ ├── UniqueFieldDefinitionNamesRule-test.js │ │ ├── UniqueFragmentNamesRule-test.js │ │ ├── UniqueInputFieldNamesRule-test.js │ │ ├── UniqueOperationNamesRule-test.js │ │ ├── UniqueOperationTypesRule-test.js │ │ ├── UniqueTypeNamesRule-test.js │ │ ├── UniqueVariableNamesRule-test.js │ │ ├── ValuesOfCorrectTypeRule-test.js │ │ ├── VariablesAreInputTypesRule-test.js │ │ ├── VariablesInAllowedPositionRule-test.js │ │ ├── harness.js │ │ └── validation-test.js │ ├── gen.sh │ ├── main.go │ ├── replacements.yml │ └── testsgo │ │ ├── ExecutableDefinitionsRule_test.go │ │ ├── FieldsOnCorrectTypeRule_test.go │ │ ├── FragmentsOnCompositeTypesRule_test.go │ │ ├── KnownArgumentNamesRule_test.go │ │ ├── KnownDirectivesRule_test.go │ │ ├── KnownFragmentNamesRule_test.go │ │ ├── KnownTypeNamesRule_test.go │ │ ├── LoneAnonymousOperationRule_test.go │ │ ├── LoneSchemaDefinitionRule_test.go │ │ ├── NoFragmentCyclesRule_test.go │ │ ├── NoUndefinedVariablesRule_test.go │ │ ├── NoUnusedFragmentsRule_test.go │ │ ├── NoUnusedVariablesRule_test.go │ │ ├── OverlappingFieldsCanBeMergedRule_test.go │ │ ├── PossibleFragmentSpreadsRule_test.go │ │ ├── PossibleTypeExtensionsRule_test.go │ │ ├── ProvidedRequiredArgumentsRule_test.go │ │ ├── ScalarLeafsRule_test.go │ │ ├── SingleFieldSubscriptionsRule_test.go │ │ ├── UniqueArgumentNamesRule_test.go │ │ ├── UniqueDirectiveNamesRule_test.go │ │ ├── UniqueDirectivesPerLocationRule_test.go │ │ ├── UniqueEnumValueNamesRule_test.go │ │ ├── UniqueFieldDefinitionNamesRule_test.go │ │ ├── UniqueFragmentNamesRule_test.go │ │ ├── UniqueInputFieldNamesRule_test.go │ │ ├── UniqueOperationNamesRule_test.go │ │ ├── UniqueOperationTypesRule_test.go │ │ ├── UniqueTypeNamesRule_test.go │ │ ├── UniqueVariableNamesRule_test.go │ │ ├── ValuesOfCorrectTypeRule_test.go │ │ ├── VariablesAreInputTypesRule_test.go │ │ ├── VariablesInAllowedPositionRule_test.go │ │ ├── harness_test.go │ │ └── test_schema.graphql ├── rule.go ├── rule_implement_transitive_interfaces.go ├── rule_implement_transitive_interfaces_test.go ├── rule_implementing_types_are_supersets.go ├── rule_implementing_types_are_supersets_test.go ├── rule_known_type_names.go ├── rule_known_type_names_test.go ├── rule_populated_type_bodies.go ├── rule_populated_type_bodies_test.go ├── rule_require_defined_types_for_extensions.go ├── rule_require_defined_types_for_extensions_test.go ├── rule_unique_enum_value_names.go ├── rule_unique_enum_value_names_test.go ├── rule_unique_field_definition_names.go ├── rule_unique_field_definition_names_test.go ├── rule_unique_operation_types.go ├── rule_unique_operation_types_test.go ├── rule_unique_type_names.go ├── rule_unique_type_names_test.go ├── rule_unique_union_member_types.go ├── rule_unique_union_member_types_test.go ├── validation_state.go └── validation_state_string.go ├── astvisitor ├── astvisitor.go ├── fixtures │ ├── path.golden │ ├── schema_visitor.golden │ ├── visitor.golden │ └── visitor_skip.golden ├── simplevisitor.go ├── simplevisitor_test.go ├── visitor.go └── visitor_test.go ├── engine ├── datasource │ ├── graphql_datasource │ │ ├── entity_interfaces_engine_config.go │ │ ├── graphql_datasource.go │ │ ├── graphql_datasource_federation_entity_interfaces_test.go │ │ ├── graphql_datasource_federation_test.go │ │ ├── graphql_datasource_test.go │ │ ├── graphql_sse_handler.go │ │ ├── graphql_sse_handler_test.go │ │ ├── graphql_subscription_client.go │ │ ├── graphql_subscription_client_test.go │ │ ├── graphql_tws_handler.go │ │ ├── graphql_tws_handler_test.go │ │ ├── graphql_ws_handler.go │ │ ├── graphql_ws_handler_test.go │ │ ├── graphql_ws_proto_types.go │ │ ├── representation_variable.go │ │ └── representation_variable_test.go │ ├── httpclient │ │ ├── httpclient.go │ │ ├── httpclient_test.go │ │ └── nethttpclient.go │ ├── introspection_datasource │ │ ├── config_factory.go │ │ ├── factory.go │ │ ├── fixtures │ │ │ ├── enum_values_with_deprecated.golden │ │ │ ├── enum_values_without_deprecated.golden │ │ │ ├── fields_with_deprecated.golden │ │ │ ├── fields_without_deprecated.golden │ │ │ ├── not_existing_type.golden │ │ │ ├── schema_introspection.golden │ │ │ ├── schema_introspection_with_custom_root_operation_types.golden │ │ │ └── type_introspection.golden │ │ ├── input.go │ │ ├── input_test.go │ │ ├── planner.go │ │ ├── planner_test.go │ │ ├── source.go │ │ └── source_test.go │ ├── kafka_datasource │ │ ├── config.go │ │ ├── config_test.go │ │ ├── kafka_consumer_group.go │ │ ├── kafka_consumer_group_test.go │ │ ├── kafka_datasource.go │ │ ├── kafka_datasource_test.go │ │ └── sarama_config_parameters_test.go │ ├── pubsub_datasource │ │ ├── pubsub_datasource.go │ │ └── pubsub_datasource_test.go │ ├── rest_datasource │ │ ├── rest_datasource.go │ │ └── rest_datasource_test.go │ └── staticdatasource │ │ ├── static_datasource.go │ │ └── static_datasource_test.go ├── datasourcetesting │ └── datasourcetesting.go ├── plan │ ├── abstract_selection_rewriter.go │ ├── abstract_selection_rewriter_helpers.go │ ├── abstract_selection_rewriter_info.go │ ├── abstract_selection_rewriter_test.go │ ├── analyze_plan_kind.go │ ├── analyze_plan_kind_test.go │ ├── configuration.go │ ├── configuration_visitor.go │ ├── datasource_configuration.go │ ├── datasource_filter_visitor.go │ ├── datasource_filter_visitor_test.go │ ├── federation_metadata.go │ ├── plan.go │ ├── planner.go │ ├── planner_configuration.go │ ├── planner_test.go │ ├── provides_fields_visitor.go │ ├── provides_fields_visitor_test.go │ ├── required_fields_visitor.go │ ├── schemausageinfo.go │ ├── schemausageinfo_test.go │ ├── skip_include_visitor.go │ ├── type_field.go │ └── visitor.go ├── postprocess │ ├── create_concrete_single_fetch_types.go │ ├── create_multi_fetch_types.go │ ├── create_multi_fetch_types_test.go │ ├── fetchinput.go │ ├── injectheader.go │ ├── injectheader_test.go │ ├── modifyheader.go │ ├── modifyheader_test.go │ ├── postprocess.go │ ├── resolve_input_templates.go │ └── resolve_input_templates_test.go └── resolve │ ├── authorization_test.go │ ├── buf_pair.go │ ├── const.go │ ├── context.go │ ├── dataloader.md │ ├── datasource.go │ ├── engine.md │ ├── fetch.go │ ├── inputtemplate.go │ ├── inputtemplate_test.go │ ├── loader.go │ ├── loader_test.go │ ├── node.go │ ├── node_array.go │ ├── node_custom.go │ ├── node_object.go │ ├── node_scalar.go │ ├── resolvable.go │ ├── resolvable_test.go │ ├── resolve.go │ ├── resolve_federation_test.go │ ├── resolve_mock_test.go │ ├── resolve_test.go │ ├── response.go │ ├── simple_resolver.go │ ├── testdata │ ├── defer_1.json │ ├── defer_2.json │ ├── defer_3.json │ ├── posts.json │ ├── response_without_defer.json │ ├── stream_1.json │ ├── stream_2.json │ ├── stream_3.json │ ├── stream_4.json │ ├── stream_5.json │ ├── stream_6.json │ ├── stream_7.json │ ├── stream_8.json │ ├── stream_9.json │ └── users.json │ ├── trace.go │ ├── variables.go │ └── variables_renderer.go ├── fastbuffer ├── fastbuffer.go └── fastbuffer_test.go ├── federation ├── federationdata │ ├── local_type_field_extractor.go │ ├── local_type_field_extractor_test.go │ ├── required_field_extractor.go │ └── required_field_extractor_test.go ├── fixtures │ └── federated_schema.golden ├── schema.go ├── schema_test.go └── sdlmerge │ ├── collect_entities.go │ ├── collect_entities_test.go │ ├── const.go │ ├── enum_type_extending.go │ ├── enum_type_extending_test.go │ ├── input_type_extending.go │ ├── input_type_extending_test.go │ ├── interface_type_extending.go │ ├── interface_type_extending_test.go │ ├── merge_duplicated_fields.go │ ├── object_type_extending.go │ ├── object_type_extending_test.go │ ├── remove_duplicate_fielded_shared_types.go │ ├── remove_duplicate_fielded_shared_types_test.go │ ├── remove_duplicate_fieldless_shared_types.go │ ├── remove_duplicate_fieldless_shared_types_test.go │ ├── remove_empty_object_type_definition.go │ ├── remove_empty_object_type_definition_test.go │ ├── remove_field_definition_by_directive.go │ ├── remove_field_definition_by_directive_test.go │ ├── remove_field_definition_directive.go │ ├── remove_field_definition_directive_test.go │ ├── remove_interface_definition_directive.go │ ├── remove_interface_definition_directive_test.go │ ├── remove_object_type_definition_directive.go │ ├── remove_object_type_definition_directive_test.go │ ├── remove_type_extensions.go │ ├── remove_type_extensions_test.go │ ├── scalar_type_extending.go │ ├── scalar_type_extending_test.go │ ├── sdlmerge.go │ ├── sdlmerge_test.go │ ├── shared_types.go │ ├── testdata │ └── validate-subgraph │ │ ├── lack-definition-non-null.graphqls │ │ ├── lack-definition.graphqls │ │ ├── lack-extend-definition-non-null.graphqls │ │ ├── lack-extend-definition.graphqls │ │ ├── well-defined-non-null.graphqls │ │ └── well-defined.graphqls │ ├── union_type_extending.go │ └── union_type_extending_test.go ├── graphql ├── complexity.go ├── config_factory_federation.go ├── config_factory_federation_test.go ├── config_factory_proxy.go ├── config_factory_proxy_test.go ├── engine_config_v2.go ├── engine_config_v2_test.go ├── errors.go ├── errors_test.go ├── execution_engine_v2.go ├── execution_engine_v2_custom.go ├── execution_engine_v2_custom_test.go ├── execution_engine_v2_helpers_test.go ├── execution_engine_v2_norace_test.go ├── execution_engine_v2_test.go ├── extractor.go ├── extractor_test.go ├── input_validation.go ├── input_validation_test.go ├── lookup.go ├── lookup_test.go ├── normalization.go ├── normalization_test.go ├── request.go ├── request_fields_validator.go ├── request_fields_validator_test.go ├── request_test.go ├── response.go ├── schema.go ├── schema_test.go ├── starwars_helpers_test.go ├── subscription.go ├── types.go ├── validation.go └── validation_test.go ├── graphqlerrors └── location.go ├── graphqljsonschema ├── jsonschema.go └── jsonschema_test.go ├── imports ├── fixtures │ ├── render_result.golden │ ├── render_result_windows.golden │ ├── scanner_regex.golden │ ├── scanner_regex_render.golden │ ├── scanner_regex_windows.golden │ ├── scanner_result.golden │ └── scanner_result_windows.golden ├── graphql_file.go ├── graphql_file_test.go ├── imports.go ├── imports_test.go └── testdata │ ├── cycle │ ├── a │ │ └── a.graphql │ └── b │ │ └── b.graphql │ ├── deep │ └── deeper │ │ ├── custom_types.graphql │ │ └── non_graphql.txt │ ├── import_cycle.graphql │ ├── nested │ └── nested.graphql │ ├── nested2 │ └── nested2.graphql │ ├── regexonly │ ├── flat.graphql │ ├── mutation.graphql │ └── query.graphql │ ├── scalars │ └── json.graphql │ ├── schema.graphql │ └── types │ ├── mutation.graphql │ └── query.graphql ├── introspection ├── converter.go ├── converter_test.go ├── fixtures │ ├── interfaces_implementing_interfaces.golden │ ├── starwars.golden │ └── starwars_introspected.golden ├── generator.go ├── generator_test.go ├── introspection.go ├── introspection_enum.go ├── introspection_test.go └── testdata │ ├── interfaces_implementing_interfaces.graphql │ ├── out_swapi_introspection_response.json │ ├── starwars.schema.graphql │ └── swapi_introspection_response.json ├── lexer ├── fixtures │ └── introspection_lexed.golden ├── identkeyword │ ├── identkeyword.go │ └── identkeyword_string.go ├── keyword │ ├── keyword.go │ └── keyword_string.go ├── lexer.go ├── lexer_test.go ├── literal │ └── literal.go ├── position │ └── position.go ├── runes │ └── runes.go └── token │ └── token.go ├── middleware ├── middleware.go └── operation_complexity │ ├── operation_complexity.go │ └── operation_complexity_test.go ├── operationreport ├── externalerror.go ├── externalerror_test.go ├── operationreport.go └── operationreport_test.go ├── playground ├── files │ ├── favicon.png │ ├── logo.png │ ├── playground.css │ ├── playground.html │ └── playground.js ├── fixtures │ └── handlers.golden ├── playground.go └── playground_test.go ├── pool ├── bytesbuffer.go ├── fastbuffer.go └── hash64.go ├── starwars ├── starwars.go └── testdata │ ├── mutations │ └── create_review.mutation │ ├── queries │ ├── directives_include.query │ ├── directives_skip.query │ ├── droid_with_arg.query │ ├── droid_with_arg_and_var.query │ ├── fragments.query │ ├── hero_with_aliases.query │ ├── hero_with_operation_name.query │ ├── inline_fragments.query │ ├── interface_fragments_on_union.graphql │ ├── introspection.query │ ├── invalid.query │ ├── invalid_fragments.query │ ├── multi_queries.query │ ├── multi_queries_with_arguments.query │ ├── simple_hero.query │ └── union.query │ ├── star_wars.graphql │ └── subscriptions │ └── remaining_jedis.subscription ├── subscription ├── constants.go ├── context.go ├── context_test.go ├── engine.go ├── engine_mock_test.go ├── engine_test.go ├── executor.go ├── executor_mock_test.go ├── executor_v2.go ├── handler.go ├── handler_mock_test.go ├── handler_test.go ├── init.go ├── legacy_handler.go ├── legacy_handler_test.go ├── mock_client_test.go ├── time_out.go ├── time_out_test.go ├── transport_client.go ├── transport_client_mock_test.go └── websocket │ ├── client.go │ ├── client_test.go │ ├── engine_mock_test.go │ ├── handler.go │ ├── handler_test.go │ ├── init.go │ ├── protocol_graphql_transport_ws.go │ ├── protocol_graphql_transport_ws_test.go │ ├── protocol_graphql_ws.go │ └── protocol_graphql_ws_test.go ├── testing ├── federationtesting │ ├── accounts │ │ ├── gqlgen.yml │ │ ├── graph │ │ │ ├── entity.resolvers.go │ │ │ ├── generated │ │ │ │ ├── federation.go │ │ │ │ └── generated.go │ │ │ ├── handler.go │ │ │ ├── histories.go │ │ │ ├── model │ │ │ │ └── models_gen.go │ │ │ ├── resolver.go │ │ │ ├── schema.graphqls │ │ │ ├── schema.resolvers.go │ │ │ └── wallets.go │ │ └── handler.go │ ├── federation_integration_test.go │ ├── gateway │ │ ├── datasource_poller.go │ │ ├── gateway.go │ │ ├── http │ │ │ ├── handler.go │ │ │ ├── http.go │ │ │ └── ws.go │ │ └── main.go │ ├── graphql_client_test.go │ ├── products │ │ ├── gqlgen.yml │ │ ├── graph │ │ │ ├── entity.resolvers.go │ │ │ ├── generated │ │ │ │ ├── federation.go │ │ │ │ └── generated.go │ │ │ ├── handler.go │ │ │ ├── model │ │ │ │ └── models_gen.go │ │ │ ├── products.go │ │ │ ├── resolver.go │ │ │ ├── schema.graphqls │ │ │ ├── schema.resolvers.go │ │ │ └── variables.go │ │ └── handler.go │ ├── reviews │ │ ├── gqlgen.yml │ │ ├── graph │ │ │ ├── attachments.go │ │ │ ├── entity.resolvers.go │ │ │ ├── generated │ │ │ │ ├── federation.go │ │ │ │ └── generated.go │ │ │ ├── handler.go │ │ │ ├── model │ │ │ │ ├── models.go │ │ │ │ └── models_gen.go │ │ │ ├── resolver.go │ │ │ ├── reviews.go │ │ │ ├── schema.graphqls │ │ │ └── schema.resolvers.go │ │ └── handler.go │ ├── testdata │ │ ├── mutations │ │ │ └── mutation_with_variables.query │ │ ├── queries │ │ │ ├── complex_nesting.graphql │ │ │ ├── interface.query │ │ │ ├── interface_fragment_on_object.graphql │ │ │ ├── interface_fragments_on_union.graphql │ │ │ ├── merged_field.graphql │ │ │ ├── multiple_queries.query │ │ │ ├── multiple_queries_with_nested_fragments.query │ │ │ ├── multiple_queries_with_union_return.query │ │ │ ├── multiple_upstream.query │ │ │ ├── object_fragment_on_interface.graphql │ │ │ ├── single_upstream.query │ │ │ └── union.query │ │ └── subscriptions │ │ │ └── subscription.query │ └── util.go ├── flags │ ├── flags.go │ └── flags_win.go ├── goldie │ ├── goldie.go │ ├── goldie_posix.go │ └── goldie_win.go └── subscriptiontesting │ ├── .gqlgen.yml │ ├── chat_test.go │ ├── generated.go │ ├── handler.go │ ├── models_gen.go │ ├── resolvers.go │ ├── schema.graphql │ └── util.go └── variablesvalidation ├── variablesvalidation.go └── variablesvalidation_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | *.out 3 | *.test 4 | .DS_Store 5 | pkg/parser/testdata/lotto.graphql 6 | *node_modules* 7 | *vendor* -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | disable-all: true 3 | enable: 4 | - gofmt 5 | # - bodyclose 6 | - errcheck 7 | - gosimple 8 | - govet 9 | - ineffassign 10 | - staticcheck 11 | - typecheck 12 | # - unused 13 | # - gosec 14 | # - gci 15 | 16 | linters-settings: 17 | gci: 18 | sections: 19 | - standard 20 | - default 21 | - prefix(github.com/wundergraph) 22 | - prefix(github.com/wundergraph/graphql-go-tools) 23 | issues: 24 | exclude: 25 | - "SA1019: subscription.Message is deprecated: Prefer using TransportClient that is based on byte slices instead of this Message struct." 26 | - "SA1019: rand\\.Seed.*" 27 | -------------------------------------------------------------------------------- /examples/chat/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /examples/chat/.gqlgen.yml: -------------------------------------------------------------------------------- 1 | models: 2 | Chatroom: 3 | model: github.com/TykTechnologies/graphql-go-tools/examples/chat.Chatroom 4 | -------------------------------------------------------------------------------- /examples/chat/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/TykTechnologies/graphql-go-tools/examples/chat 2 | 3 | go 1.19 4 | require ( 5 | github.com/99designs/gqlgen v0.17.20 6 | github.com/gorilla/websocket v1.5.0 7 | github.com/rs/cors v1.7.0 8 | github.com/stretchr/testify v1.7.1 9 | github.com/vektah/gqlparser/v2 v2.5.1 10 | ) 11 | -------------------------------------------------------------------------------- /examples/chat/handler.go: -------------------------------------------------------------------------------- 1 | package chat 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "github.com/99designs/gqlgen/graphql/handler" 8 | "github.com/99designs/gqlgen/graphql/handler/extension" 9 | "github.com/99designs/gqlgen/graphql/handler/transport" 10 | "github.com/gorilla/websocket" 11 | ) 12 | 13 | func GraphQLEndpointHandler() http.Handler { 14 | srv := handler.New(NewExecutableSchema(New())) 15 | 16 | srv.AddTransport(transport.POST{}) 17 | srv.AddTransport(transport.Websocket{ 18 | KeepAlivePingInterval: 10 * time.Second, 19 | Upgrader: websocket.Upgrader{ 20 | CheckOrigin: func(r *http.Request) bool { 21 | return true 22 | }, 23 | }, 24 | }) 25 | srv.Use(extension.Introspection{}) 26 | 27 | return srv 28 | } 29 | -------------------------------------------------------------------------------- /examples/chat/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package chat 4 | 5 | import ( 6 | "time" 7 | ) 8 | 9 | type Message struct { 10 | ID string `json:"id"` 11 | Text string `json:"text"` 12 | CreatedBy string `json:"createdBy"` 13 | CreatedAt time.Time `json:"createdAt"` 14 | } 15 | -------------------------------------------------------------------------------- /examples/chat/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chat", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@apollo/client": "^3.2.3", 7 | "@apollo/react-hooks": "^4.0.0", 8 | "apollo-cache-inmemory": "^1.3.11", 9 | "apollo-link-ws": "^1.0.10", 10 | "apollo-utilities": "^1.0.26", 11 | "graphql": "^14.0.2", 12 | "graphql-tag": "^2.10.0", 13 | "react": "^16.6.3", 14 | "react-dom": "^16.6.3", 15 | "react-scripts": "^2.1.1", 16 | "styled-components": "^5.2.0", 17 | "subscriptions-transport-ws": "^0.9.5" 18 | }, 19 | "scripts": { 20 | "start": "cross-env PORT=3080 react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test --env=jsdom", 23 | "eject": "react-scripts eject" 24 | }, 25 | "browserslist": [ 26 | ">0.2%", 27 | "not dead", 28 | "not ie <= 11", 29 | "not op_mini all" 30 | ], 31 | "devDependencies": { 32 | "cross-env": "^7.0.3" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/chat/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React App 8 | 9 | 10 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/chat/readme.md: -------------------------------------------------------------------------------- 1 | # Chat Demo 2 | 3 | ## Getting started 4 | 1. Install go modules & npm dependencies 5 | ```shell 6 | go mod download 7 | npm i 8 | ``` 9 | 2. Start server and start react client 10 | ``` 11 | chmod +x start-server.sh 12 | ./start-server.sh 13 | npm run start 14 | ``` 15 | 16 | Example is forked from: [gqlgen](https://github.com/99designs/gqlgen/tree/master/example/chat) 17 | 18 | ## Example(s) 19 | ```graphql 20 | mutation SendMessage { 21 | post(roomName: "#test", username: "me", text: "hello!") { 22 | ...MessageData 23 | } 24 | } 25 | 26 | query GetMessages { 27 | room(name:"#test") { 28 | name 29 | messages { 30 | ...MessageData 31 | } 32 | } 33 | } 34 | 35 | subscription LiveMessages { 36 | messageAdded(roomName: "#test") { 37 | ...MessageData 38 | } 39 | } 40 | 41 | fragment MessageData on Message{ 42 | id 43 | text 44 | createdBy 45 | createdAt 46 | } 47 | ``` -------------------------------------------------------------------------------- /examples/chat/schema.graphql: -------------------------------------------------------------------------------- 1 | type Chatroom { 2 | name: String! 3 | messages: [Message!]! 4 | } 5 | 6 | type Message { 7 | id: ID! 8 | text: String! 9 | createdBy: String! 10 | createdAt: Time! 11 | } 12 | 13 | type Query { 14 | room(name:String!): Chatroom 15 | } 16 | 17 | type Mutation { 18 | post(text: String!, username: String!, roomName: String!): Message! 19 | } 20 | 21 | type Subscription { 22 | messageAdded(roomName: String!): Message! 23 | } 24 | 25 | scalar Time 26 | 27 | directive @user(username: String!) on SUBSCRIPTION 28 | -------------------------------------------------------------------------------- /examples/chat/server/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/99designs/gqlgen/graphql/playground" 8 | "github.com/rs/cors" 9 | 10 | "github.com/TykTechnologies/graphql-go-tools/examples/chat" 11 | ) 12 | 13 | func main() { 14 | c := cors.New(cors.Options{ 15 | AllowedOrigins: []string{"http://localhost:3080", "http://localhost:3000"}, 16 | AllowCredentials: true, 17 | }) 18 | 19 | http.Handle("/", playground.Handler("Chat", "/query")) 20 | http.Handle("/query", c.Handler(chat.GraphQLEndpointHandler())) 21 | 22 | log.Println("Playground running on: http://localhost:8085") 23 | log.Println("Send operations to: http://localhost:8085/query") 24 | log.Fatal(http.ListenAndServe(":8085", nil)) 25 | } 26 | -------------------------------------------------------------------------------- /examples/chat/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import styled from 'styled-components'; 3 | import { Room } from './Room'; 4 | 5 | const Input = styled.div` 6 | padding: 4px; 7 | margin: 0 0 4px; 8 | 9 | input { 10 | border: 1px solid #ccc; 11 | padding: 2px; 12 | font-size: 14px; 13 | } 14 | `; 15 | 16 | export const App = () => { 17 | const [name, setName] = useState('tester'); 18 | const [channel, setChannel] = useState('#gophers'); 19 | 20 | return ( 21 | <> 22 | 23 | name: setName(e.target.value)} /> 24 | 25 | 26 | channel: setChannel(e.target.value)} /> 27 | 28 | 29 | 30 | 31 | ); 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /examples/chat/start-server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | go build -o /tmp/srv-chat ./server 4 | /tmp/srv-chat 5 | -------------------------------------------------------------------------------- /examples/federation/README.md: -------------------------------------------------------------------------------- 1 | # Federation Demo 2 | 3 | ## Getting started 4 | 1. Install go modules 5 | ```shell 6 | go mod download 7 | ``` 8 | 2. Run start script 9 | ``` 10 | chmod +x start.sh 11 | ./start.sh 12 | ``` -------------------------------------------------------------------------------- /examples/federation/accounts/graph/handler.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/99designs/gqlgen/graphql/handler" 7 | "github.com/99designs/gqlgen/graphql/handler/debug" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/examples/federation/accounts/graph/generated" 10 | ) 11 | 12 | type EndpointOptions struct { 13 | EnableDebug bool 14 | } 15 | 16 | var TestOptions = EndpointOptions{ 17 | EnableDebug: false, 18 | } 19 | 20 | func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { 21 | srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) 22 | if opts.EnableDebug { 23 | srv.Use(&debug.Tracer{}) 24 | } 25 | 26 | return srv 27 | } 28 | -------------------------------------------------------------------------------- /examples/federation/accounts/graph/model/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package model 4 | 5 | type User struct { 6 | ID string `json:"id"` 7 | Username string `json:"username"` 8 | } 9 | 10 | func (User) IsEntity() {} 11 | -------------------------------------------------------------------------------- /examples/federation/accounts/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | type Resolver struct{} 7 | -------------------------------------------------------------------------------- /examples/federation/accounts/graph/schema.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | me: User 3 | } 4 | 5 | type User @key(fields: "id") { 6 | id: ID! 7 | username: String! 8 | } 9 | -------------------------------------------------------------------------------- /examples/federation/accounts/graph/schema.resolvers.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | // This file will be automatically regenerated based on the schema, any resolver implementations 4 | // will be copied through when generating and any unknown code will be moved to the end. 5 | 6 | import ( 7 | "context" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/examples/federation/accounts/graph/generated" 10 | "github.com/TykTechnologies/graphql-go-tools/examples/federation/accounts/graph/model" 11 | ) 12 | 13 | // Me is the resolver for the me field. 14 | func (r *queryResolver) Me(ctx context.Context) (*model.User, error) { 15 | return &model.User{ 16 | ID: "1234", 17 | Username: "Me", 18 | }, nil 19 | } 20 | 21 | // Query returns generated.QueryResolver implementation. 22 | func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } 23 | 24 | type queryResolver struct{ *Resolver } 25 | -------------------------------------------------------------------------------- /examples/federation/accounts/server.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package main 3 | 4 | import ( 5 | "log" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/99designs/gqlgen/graphql/playground" 10 | 11 | "github.com/TykTechnologies/graphql-go-tools/examples/federation/accounts/graph" 12 | ) 13 | 14 | const defaultPort = "4001" 15 | 16 | func main() { 17 | port := os.Getenv("PORT") 18 | if port == "" { 19 | port = defaultPort 20 | } 21 | 22 | http.Handle("/", playground.Handler("GraphQL playground", "/query")) 23 | http.Handle("/query", graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true})) 24 | 25 | log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) 26 | log.Fatal(http.ListenAndServe(":"+port, nil)) 27 | } 28 | -------------------------------------------------------------------------------- /examples/federation/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/TykTechnologies/graphql-go-tools/examples/federation 2 | 3 | go 1.21.0 4 | 5 | toolchain go1.21.6 6 | 7 | require ( 8 | github.com/99designs/gqlgen v0.17.22 9 | github.com/TykTechnologies/graphql-go-tools v1.20.2 10 | github.com/gobwas/ws v1.0.4 11 | github.com/gorilla/websocket v1.5.0 12 | github.com/jensneuse/abstractlogger v0.0.4 13 | github.com/vektah/gqlparser/v2 v2.5.1 14 | go.uber.org/atomic v1.9.0 15 | go.uber.org/zap v1.18.1 16 | ) 17 | 18 | replace github.com/TykTechnologies/graphql-go-tools => ../../ 19 | -------------------------------------------------------------------------------- /examples/federation/products/graph/model/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package model 4 | 5 | type Product struct { 6 | Upc string `json:"upc"` 7 | Name string `json:"name"` 8 | Price int `json:"price"` 9 | InStock int `json:"inStock"` 10 | } 11 | 12 | func (Product) IsEntity() {} 13 | -------------------------------------------------------------------------------- /examples/federation/products/graph/products.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/examples/federation/products/graph/model" 4 | 5 | var hats = []*model.Product{ 6 | { 7 | Upc: "top-1", 8 | Name: "Trilby", 9 | Price: 11, 10 | InStock: 500, 11 | }, 12 | { 13 | Upc: "top-2", 14 | Name: "Fedora", 15 | Price: 22, 16 | InStock: 1200, 17 | }, 18 | { 19 | Upc: "top-3", 20 | Name: "Boater", 21 | Price: 33, 22 | InStock: 850, 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /examples/federation/products/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | type Resolver struct{} 7 | -------------------------------------------------------------------------------- /examples/federation/products/graph/schema.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | topProducts(first: Int = 5): [Product] 3 | } 4 | 5 | extend type Subscription { 6 | updatedPrice: Product! 7 | updateProductPrice(upc: String!): Product! 8 | stock: [Product!] 9 | } 10 | 11 | type Product @key(fields: "upc") { 12 | upc: String! 13 | name: String! 14 | price: Int! 15 | inStock: Int! 16 | } -------------------------------------------------------------------------------- /examples/federation/products/graph/variables.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | var ( 8 | randomnessEnabled = true 9 | minPrice = 10 10 | maxPrice = 1499 11 | currentPrice = minPrice 12 | updateInterval = time.Second 13 | ) 14 | -------------------------------------------------------------------------------- /examples/federation/products/server.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package main 3 | 4 | import ( 5 | "log" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/99designs/gqlgen/graphql/playground" 10 | 11 | "github.com/TykTechnologies/graphql-go-tools/examples/federation/products/graph" 12 | ) 13 | 14 | const defaultPort = "4002" 15 | 16 | func main() { 17 | port := os.Getenv("PORT") 18 | if port == "" { 19 | port = defaultPort 20 | } 21 | 22 | http.Handle("/", playground.Handler("GraphQL playground", "/query")) 23 | http.Handle("/query", graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true, EnableRandomness: true})) 24 | http.HandleFunc("/websocket_connections", graph.WebsocketConnectionsHandler) 25 | 26 | log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) 27 | log.Fatal(http.ListenAndServe(":"+port, nil)) 28 | } 29 | -------------------------------------------------------------------------------- /examples/federation/reviews/graph/handler.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/99designs/gqlgen/graphql/handler" 7 | "github.com/99designs/gqlgen/graphql/handler/debug" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/examples/federation/reviews/graph/generated" 10 | ) 11 | 12 | type EndpointOptions struct { 13 | EnableDebug bool 14 | } 15 | 16 | var TestOptions = EndpointOptions{ 17 | EnableDebug: false, 18 | } 19 | 20 | func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { 21 | srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) 22 | if opts.EnableDebug { 23 | srv.Use(&debug.Tracer{}) 24 | } 25 | 26 | return srv 27 | } 28 | -------------------------------------------------------------------------------- /examples/federation/reviews/graph/model/models.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Product struct { 4 | Upc string `json:"upc"` 5 | } 6 | 7 | func (Product) IsEntity() {} 8 | 9 | type Review struct { 10 | Body string 11 | Author *User 12 | Product *Product 13 | } 14 | 15 | type User struct { 16 | ID string `json:"id"` 17 | } 18 | 19 | func (User) IsEntity() {} 20 | -------------------------------------------------------------------------------- /examples/federation/reviews/graph/model/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package model 4 | -------------------------------------------------------------------------------- /examples/federation/reviews/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | type Resolver struct{} 7 | -------------------------------------------------------------------------------- /examples/federation/reviews/graph/reviews.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/examples/federation/reviews/graph/model" 4 | 5 | var reviews = []*model.Review{ 6 | { 7 | Body: "A highly effective form of birth control.", 8 | Product: &model.Product{Upc: "top-1"}, 9 | Author: &model.User{ID: "1234"}, 10 | }, 11 | { 12 | Body: "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.", 13 | Product: &model.Product{Upc: "top-2"}, 14 | Author: &model.User{ID: "1234"}, 15 | }, 16 | { 17 | Body: "This is the last straw. Hat you will wear. 11/10", 18 | Product: &model.Product{Upc: "top-3"}, 19 | Author: &model.User{ID: "7777"}, 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /examples/federation/reviews/graph/schema.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User! @provides(fields: "username") 4 | product: Product! 5 | } 6 | 7 | extend type User @key(fields: "id") { 8 | id: ID! @external 9 | username: String! @external 10 | reviews: [Review] 11 | } 12 | 13 | extend type Product @key(fields: "upc") { 14 | upc: String! @external 15 | reviews: [Review] 16 | } 17 | -------------------------------------------------------------------------------- /examples/federation/reviews/server.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package main 3 | 4 | import ( 5 | "log" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/99designs/gqlgen/graphql/playground" 10 | 11 | "github.com/TykTechnologies/graphql-go-tools/examples/federation/reviews/graph" 12 | ) 13 | 14 | const defaultPort = "4003" 15 | 16 | func main() { 17 | port := os.Getenv("PORT") 18 | if port == "" { 19 | port = defaultPort 20 | } 21 | 22 | http.Handle("/", playground.Handler("GraphQL playground", "/query")) 23 | http.Handle("/query", graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true})) 24 | 25 | log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) 26 | log.Fatal(http.ListenAndServe(":"+port, nil)) 27 | } 28 | -------------------------------------------------------------------------------- /examples/federation/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function cleanup { 4 | kill "$ACCOUNTS_PID" 5 | kill "$PRODUCTS_PID" 6 | kill "$REVIEWS_PID" 7 | } 8 | trap cleanup EXIT 9 | 10 | go build -o /tmp/srv-accounts ./accounts 11 | go build -o /tmp/srv-products ./products 12 | go build -o /tmp/srv-reviews ./reviews 13 | go build -o /tmp/srv-gateway ./gateway 14 | 15 | /tmp/srv-accounts & 16 | ACCOUNTS_PID=$! 17 | 18 | /tmp/srv-products & 19 | PRODUCTS_PID=$! 20 | 21 | /tmp/srv-reviews & 22 | REVIEWS_PID=$! 23 | 24 | sleep 1 25 | 26 | /tmp/srv-gateway 27 | -------------------------------------------------------------------------------- /examples/kafka_pubsub/kafka_jaas.conf: -------------------------------------------------------------------------------- 1 | KafkaServer { 2 | org.apache.kafka.common.security.plain.PlainLoginModule required 3 | username="admin" 4 | password="admin-secret" 5 | user_admin="admin-secret" 6 | user_alice="alice-secret"; 7 | }; 8 | Client{}; -------------------------------------------------------------------------------- /examples/kafka_pubsub/transactional_producer/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/TykTechnologies/graphql-go-tools/examples/kafka_pubsub/transactional_producer 2 | 3 | go 1.19 4 | 5 | require github.com/confluentinc/confluent-kafka-go v1.8.2 6 | -------------------------------------------------------------------------------- /examples/kafka_pubsub/transactional_producer/go.sum: -------------------------------------------------------------------------------- 1 | github.com/confluentinc/confluent-kafka-go v1.8.2 h1:PBdbvYpyOdFLehj8j+9ba7FL4c4Moxn79gy9cYKxG5E= 2 | github.com/confluentinc/confluent-kafka-go v1.8.2/go.mod h1:u2zNLny2xq+5rWeTQjFHbDzzNuba4P1vo31r9r4uAdg= 3 | -------------------------------------------------------------------------------- /internal/pkg/quotes/quotes.go: -------------------------------------------------------------------------------- 1 | package quotes 2 | 3 | const ( 4 | quoteByte = '"' 5 | quoteStr = string(quoteByte) 6 | ) 7 | 8 | // WrapBytes returns a new slice wrapping the given s 9 | // in quotes (") by making a copy. 10 | func WrapBytes(s []byte) []byte { 11 | cp := make([]byte, len(s)+2) 12 | cp[0] = quoteByte 13 | copy(cp[1:], s) 14 | cp[len(s)+1] = quoteByte 15 | return cp 16 | } 17 | 18 | func WrapString(str string) string { 19 | return quoteStr + str + quoteStr 20 | } 21 | -------------------------------------------------------------------------------- /internal/pkg/quotes/quotes_test.go: -------------------------------------------------------------------------------- 1 | package quotes 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestWrapBytes(t *testing.T) { 10 | testCases := []struct { 11 | s []byte 12 | want []byte 13 | }{ 14 | {nil, []byte(`""`)}, 15 | {[]byte("foo"), []byte(`"foo"`)}, 16 | } 17 | for _, tc := range testCases { 18 | tc := tc 19 | t.Run(string(tc.s), func(t *testing.T) { 20 | r := WrapBytes(tc.s) 21 | assert.Equal(t, tc.want, r) 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /internal/pkg/unsafeprinter/unsafeprinter.go: -------------------------------------------------------------------------------- 1 | package unsafeprinter 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/internal/pkg/unsafeparser" 5 | "github.com/TykTechnologies/graphql-go-tools/pkg/ast" 6 | "github.com/TykTechnologies/graphql-go-tools/pkg/astprinter" 7 | ) 8 | 9 | func Print(document, definition *ast.Document) string { 10 | str, err := astprinter.PrintString(document, definition) 11 | if err != nil { 12 | panic(err) 13 | } 14 | return str 15 | } 16 | 17 | func PrettyPrint(document, definition *ast.Document) string { 18 | str, err := astprinter.PrintStringIndent(document, definition, " ") 19 | if err != nil { 20 | panic(err) 21 | } 22 | return str 23 | } 24 | 25 | func Prettify(document string) string { 26 | doc := unsafeparser.ParseGraphqlDocumentString(document) 27 | return PrettyPrint(&doc, nil) 28 | } 29 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /pkg/ast/ast_node_kind_test.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func TestNodeKindIsAbstractType(t *testing.T) { 9 | t.Run("Interface type returns true", func(t *testing.T) { 10 | assert.Equal(t, NodeKindInterfaceTypeDefinition.IsAbstractType(), true) 11 | }) 12 | 13 | t.Run("Union type returns true", func(t *testing.T) { 14 | assert.Equal(t, NodeKindUnionTypeDefinition.IsAbstractType(), true) 15 | }) 16 | 17 | t.Run("Enum type returns false", func(t *testing.T) { 18 | assert.Equal(t, NodeKindEnumTypeDefinition.IsAbstractType(), false) 19 | }) 20 | 21 | t.Run("Interface type returns false", func(t *testing.T) { 22 | assert.Equal(t, NodeKindObjectTypeDefinition.IsAbstractType(), false) 23 | }) 24 | 25 | t.Run("Scalar type returns false", func(t *testing.T) { 26 | assert.Equal(t, NodeKindScalarTypeDefinition.IsAbstractType(), false) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/ast/ast_schema_extension.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/pkg/lexer/position" 4 | 5 | type SchemaExtension struct { 6 | ExtendLiteral position.Position 7 | SchemaDefinition 8 | } 9 | -------------------------------------------------------------------------------- /pkg/ast/ast_type_test.go: -------------------------------------------------------------------------------- 1 | package ast 2 | -------------------------------------------------------------------------------- /pkg/ast/ast_val_boolean_value.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | // BooleanValues 4 | // one of: true, false 5 | type BooleanValue bool 6 | 7 | func (d *Document) BooleanValue(ref int) BooleanValue { 8 | return d.BooleanValues[ref] 9 | } 10 | 11 | func (d *Document) BooleanValuesAreEqual(left, right int) bool { 12 | return d.BooleanValue(left) == d.BooleanValue(right) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/ast/ast_val_object_value.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/pkg/lexer/position" 4 | 5 | // ObjectValue 6 | // example: 7 | // { lon: 12.43, lat: -53.211 } 8 | type ObjectValue struct { 9 | LBRACE position.Position 10 | Refs []int // ObjectField 11 | RBRACE position.Position 12 | } 13 | 14 | func (d *Document) CopyObjectValue(ref int) int { 15 | refs := d.NewEmptyRefs() 16 | for _, r := range d.ObjectValues[ref].Refs { 17 | refs = append(refs, d.CopyObjectField(r)) 18 | } 19 | return d.AddObjectValue(ObjectValue{ 20 | Refs: refs, 21 | }) 22 | } 23 | 24 | func (d *Document) AddObjectValue(value ObjectValue) (ref int) { 25 | d.ObjectValues = append(d.ObjectValues, value) 26 | return len(d.ObjectValues) - 1 27 | } 28 | 29 | func (d *Document) ImportObjectValue(fieldRefs []int) (ref int) { 30 | return d.AddObjectValue(ObjectValue{ 31 | Refs: fieldRefs, 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/ast/document_pool.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import "sync" 4 | 5 | type documentPool struct { 6 | p sync.Pool 7 | } 8 | 9 | func newDocumentPool() *documentPool { 10 | return &documentPool{ 11 | p: sync.Pool{ 12 | New: func() interface{} { 13 | return newDocumentWithPreAllocation() 14 | }, 15 | }, 16 | } 17 | } 18 | 19 | func (p *documentPool) Put(b *Document) { 20 | b.Reset() 21 | p.p.Put(b) 22 | } 23 | 24 | func (p *documentPool) Get() *Document { 25 | return p.p.Get().(*Document) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/ast/helpers.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | // indexOf - simple helper to find an index of a ref within refs slice 4 | func indexOf(refs []int, ref int) (int, bool) { 5 | for i, j := range refs { 6 | if ref == j { 7 | return i, true 8 | } 9 | } 10 | return -1, false 11 | } 12 | 13 | // deleteRef - is a slice trick to remove an item with preserving items order 14 | // Note: danger modifies pointer to the arr 15 | func deleteRef(refs *[]int, index int) { 16 | *refs = append((*refs)[:index], (*refs)[index+1:]...) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/astnormalization/directive_include_skip_test.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import "testing" 4 | 5 | func TestDirectiveIncludeVisitor(t *testing.T) { 6 | t.Run("remove static include true on inline fragment", func(t *testing.T) { 7 | run(directiveIncludeSkip, testDefinition, ` 8 | { 9 | dog { 10 | name: nickname 11 | ... @include(if: true) { 12 | includeName: name @include(if: true) 13 | notIncludeName: name @include(if: false) 14 | notSkipName: name @skip(if: false) 15 | skipName: name @skip(if: true) 16 | } 17 | } 18 | notInclude: dog @include(if: false) { 19 | name 20 | } 21 | skip: dog @skip(if: true) { 22 | name 23 | } 24 | }`, ` 25 | { 26 | dog { 27 | name: nickname 28 | ... { 29 | includeName: name 30 | notSkipName: name 31 | } 32 | } 33 | }`) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /pkg/astnormalization/fragment_definition_removal.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/pkg/ast" 5 | "github.com/TykTechnologies/graphql-go-tools/pkg/astvisitor" 6 | ) 7 | 8 | type FragmentDefinitionRemoval struct { 9 | } 10 | 11 | func removeFragmentDefinitions(walker *astvisitor.Walker) { 12 | visitor := removeFragmentDefinitionsVisitor{} 13 | walker.RegisterLeaveDocumentVisitor(visitor) 14 | } 15 | 16 | type removeFragmentDefinitionsVisitor struct { 17 | } 18 | 19 | func (r removeFragmentDefinitionsVisitor) LeaveDocument(operation, definition *ast.Document) { 20 | for i := range operation.RootNodes { 21 | if operation.RootNodes[i].Kind == ast.NodeKindFragmentDefinition { 22 | operation.RootNodes[i].Kind = ast.NodeKindUnknown 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pkg/astnormalization/remove_self_aliasing.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/TykTechnologies/graphql-go-tools/pkg/ast" 7 | "github.com/TykTechnologies/graphql-go-tools/pkg/astvisitor" 8 | ) 9 | 10 | func removeSelfAliasing(walker *astvisitor.Walker) { 11 | visitor := removeSelfAliasingVisitor{} 12 | walker.RegisterEnterDocumentVisitor(&visitor) 13 | walker.RegisterEnterFieldVisitor(&visitor) 14 | } 15 | 16 | type removeSelfAliasingVisitor struct { 17 | operation *ast.Document 18 | } 19 | 20 | func (r *removeSelfAliasingVisitor) EnterDocument(operation, definition *ast.Document) { 21 | r.operation = operation 22 | } 23 | 24 | func (r *removeSelfAliasingVisitor) EnterField(ref int) { 25 | if !r.operation.Fields[ref].Alias.IsDefined { 26 | return 27 | } 28 | if !bytes.Equal(r.operation.FieldNameBytes(ref), r.operation.FieldAliasBytes(ref)) { 29 | return 30 | } 31 | r.operation.RemoveFieldAlias(ref) 32 | } 33 | -------------------------------------------------------------------------------- /pkg/astnormalization/remove_self_aliasing_test.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import "testing" 4 | 5 | func TestRemoveSelfAliasing(t *testing.T) { 6 | t.Run("simple", func(t *testing.T) { 7 | run(removeSelfAliasing, testDefinition, ` 8 | {dog: dog}`, 9 | ` 10 | {dog}`) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/astnormalization/remove_type_extensions.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/pkg/ast" 5 | "github.com/TykTechnologies/graphql-go-tools/pkg/astvisitor" 6 | ) 7 | 8 | func removeMergedTypeExtensions(walker *astvisitor.Walker) { 9 | visitor := removeMergedTypeExtensionsVisitor{ 10 | Walker: walker, 11 | } 12 | walker.RegisterLeaveDocumentVisitor(&visitor) 13 | } 14 | 15 | type removeMergedTypeExtensionsVisitor struct { 16 | *astvisitor.Walker 17 | } 18 | 19 | func (r *removeMergedTypeExtensionsVisitor) LeaveDocument(operation, definition *ast.Document) { 20 | operation.RemoveMergedTypeExtensions() 21 | } 22 | -------------------------------------------------------------------------------- /pkg/astnormalization/variables_unused_deletion_test.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestUnusedVariableDeletion(t *testing.T) { 8 | t.Run("delete unused variables", func(t *testing.T) { 9 | runWithDeleteUnusedVariables(t, deleteUnusedVariables, variablesExtractionDefinition, ` 10 | mutation HttpBinPost($a: HttpBinPostInput $b: String){ 11 | httpBinPost(input: $a){ 12 | headers { 13 | userAgent 14 | } 15 | data { 16 | foo 17 | } 18 | } 19 | }`, "HttpBinPost", ` 20 | mutation HttpBinPost($a: HttpBinPostInput){ 21 | httpBinPost(input: $a){ 22 | headers { 23 | userAgent 24 | } 25 | data { 26 | foo 27 | } 28 | } 29 | }`, `{"a":{"foo":"bar"},"b":"bat"}`, `{"a":{"foo":"bar"}}`) 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/astvalidation/definition_validation_test.go: -------------------------------------------------------------------------------- 1 | package astvalidation 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/require" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/pkg/astparser" 10 | "github.com/TykTechnologies/graphql-go-tools/pkg/asttransform" 11 | ) 12 | 13 | func runDefinitionValidation(t *testing.T, definitionInput string, expectation ValidationState, rules ...Rule) { 14 | definition, report := astparser.ParseGraphqlDocumentString(definitionInput) 15 | require.False(t, report.HasErrors()) 16 | 17 | err := asttransform.MergeDefinitionWithBaseSchema(&definition) 18 | require.NoError(t, err) 19 | 20 | validator := &DefinitionValidator{} 21 | for _, rule := range rules { 22 | validator.RegisterRule(rule) 23 | } 24 | 25 | result := validator.Validate(&definition, &report) 26 | assert.Equal(t, expectation, result) 27 | } 28 | -------------------------------------------------------------------------------- /pkg/astvalidation/reference/.gitignore: -------------------------------------------------------------------------------- 1 | __tests__ -------------------------------------------------------------------------------- /pkg/astvalidation/reference/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd testsgo 4 | rm -f *Rule_test.go 5 | cd .. 6 | 7 | go run main.go 8 | gofmt -w testsgo 9 | -------------------------------------------------------------------------------- /pkg/astvalidation/rule.go: -------------------------------------------------------------------------------- 1 | package astvalidation 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/pkg/astvisitor" 5 | ) 6 | 7 | var reservedFieldPrefix = []byte("__") 8 | 9 | // Rule is hook to register callback functions on the Walker 10 | type Rule func(walker *astvisitor.Walker) 11 | -------------------------------------------------------------------------------- /pkg/astvalidation/rule_unique_union_member_types_test.go: -------------------------------------------------------------------------------- 1 | package astvalidation 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestUniqueMemberTypes(t *testing.T) { 8 | t.Run("Definition", func(t *testing.T) { 9 | t.Run("Union with a single member is valid", func(t *testing.T) { 10 | runDefinitionValidation(t, ` 11 | union Foo = Bar 12 | `, Valid, UniqueUnionMemberTypes(), 13 | ) 14 | }) 15 | 16 | t.Run("Union with many members is valid", func(t *testing.T) { 17 | runDefinitionValidation(t, ` 18 | union Foo = Bar | FooBar | BarFoo 19 | `, Valid, UniqueUnionMemberTypes(), 20 | ) 21 | }) 22 | 23 | t.Run("Union with duplicate members is invalid", func(t *testing.T) { 24 | runDefinitionValidation(t, ` 25 | union Foo = Bar | Bar 26 | `, Invalid, UniqueUnionMemberTypes(), 27 | ) 28 | }) 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /pkg/astvalidation/validation_state.go: -------------------------------------------------------------------------------- 1 | //go:generate stringer -type=ValidationState -output validation_state_string.go 2 | 3 | package astvalidation 4 | 5 | // ValidationState is the outcome of a validation 6 | type ValidationState int 7 | 8 | const ( 9 | UnknownState ValidationState = iota 10 | Valid 11 | Invalid 12 | ) 13 | -------------------------------------------------------------------------------- /pkg/astvalidation/validation_state_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=ValidationState -output validation_state_string.go"; DO NOT EDIT. 2 | 3 | package astvalidation 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[UnknownState-0] 12 | _ = x[Valid-1] 13 | _ = x[Invalid-2] 14 | } 15 | 16 | const _ValidationState_name = "UnknownStateValidInvalid" 17 | 18 | var _ValidationState_index = [...]uint8{0, 12, 17, 24} 19 | 20 | func (i ValidationState) String() string { 21 | if i < 0 || i >= ValidationState(len(_ValidationState_index)-1) { 22 | return "ValidationState(" + strconv.FormatInt(int64(i), 10) + ")" 23 | } 24 | return _ValidationState_name[_ValidationState_index[i]:_ValidationState_index[i+1]] 25 | } 26 | -------------------------------------------------------------------------------- /pkg/astvisitor/astvisitor.go: -------------------------------------------------------------------------------- 1 | // Package astvisitor enables efficient and powerful traversal of GraphQL document AST's. 2 | // 3 | // Visitor has more options to configure the behaviour and offers more meta data than SimpleVisitor. 4 | // SimpleVisitor on the other hand is more performant. 5 | // 6 | // If all Nodes should be visited and not much meta data is needed, go with SimpleVisitor. 7 | // If you only need to visit a subset of Nodes or want specific meta data, e.g. TypeDefinitions you should go with Visitor. 8 | package astvisitor 9 | -------------------------------------------------------------------------------- /pkg/astvisitor/fixtures/path.golden: -------------------------------------------------------------------------------- 1 | EnterField: posts, path: [query] 2 | EnterField: id, path: [query,posts] 3 | EnterField: description, path: [query,posts] 4 | EnterField: user, path: [query,posts] 5 | EnterField: id, path: [query,posts,user] 6 | EnterField: name, path: [query,posts,user] 7 | EnterField: posts, path: [query] 8 | EnterField: id, path: [query,posts] 9 | EnterField: description, path: [query,posts] 10 | EnterField: user, path: [query,posts] 11 | EnterField: id, path: [query,posts,user] 12 | EnterField: name, path: [query,posts,user] 13 | EnterField: posts, path: [query,posts,user] 14 | EnterField: id, path: [query,posts,user,posts] 15 | -------------------------------------------------------------------------------- /pkg/astvisitor/fixtures/visitor_skip.golden: -------------------------------------------------------------------------------- 1 | EnterOperationDefinition (PostsUserQuery): ref: 0 2 | EnterSelectionSet(Query): ref: 2 3 | EnterField(posts::Query): ref: 5 4 | EnterSelectionSet(Post): ref: 1 5 | EnterField(id::Post): ref: 0 6 | LeaveField(id::Post): ref: 0 7 | EnterField(description::Post): ref: 1 8 | LeaveField(description::Post): ref: 1 9 | LeaveSelectionSet(Post): ref: 1 10 | LeaveField(posts::Query): ref: 5 11 | LeaveSelectionSet(Query): ref: 2 12 | LeaveOperationDefinition(PostsUserQuery): ref: 0 13 | 14 | -------------------------------------------------------------------------------- /pkg/astvisitor/simplevisitor_test.go: -------------------------------------------------------------------------------- 1 | package astvisitor 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/TykTechnologies/graphql-go-tools/internal/pkg/unsafeparser" 7 | ) 8 | 9 | func BenchmarkSimpleVisitor(b *testing.B) { 10 | 11 | definition := unsafeparser.ParseGraphqlDocumentString(testDefinition) 12 | operation := unsafeparser.ParseGraphqlDocumentString(testOperation) 13 | 14 | visitor := &dummyVisitor{} 15 | 16 | walker := NewSimpleWalker(48) 17 | walker.SetVisitor(visitor) 18 | 19 | b.ResetTimer() 20 | b.ReportAllocs() 21 | 22 | for i := 0; i < b.N; i++ { 23 | must(walker.Walk(&operation, &definition)) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pkg/engine/datasource/introspection_datasource/factory.go: -------------------------------------------------------------------------------- 1 | package introspection_datasource 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/TykTechnologies/graphql-go-tools/pkg/engine/plan" 7 | "github.com/TykTechnologies/graphql-go-tools/pkg/introspection" 8 | ) 9 | 10 | type Factory struct { 11 | introspectionData *introspection.Data 12 | } 13 | 14 | func NewFactory(introspectionData *introspection.Data) *Factory { 15 | return &Factory{introspectionData: introspectionData} 16 | } 17 | 18 | func (f *Factory) Planner(_ context.Context) plan.DataSourcePlanner { 19 | return &Planner{introspectionData: f.introspectionData} 20 | } 21 | -------------------------------------------------------------------------------- /pkg/engine/datasource/introspection_datasource/fixtures/enum_values_with_deprecated.golden: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "NEWHOPE", 4 | "description": "", 5 | "isDeprecated": false, 6 | "deprecationReason": null 7 | }, 8 | { 9 | "name": "EMPIRE", 10 | "description": "", 11 | "isDeprecated": false, 12 | "deprecationReason": null 13 | }, 14 | { 15 | "name": "JEDI", 16 | "description": "", 17 | "isDeprecated": true, 18 | "deprecationReason": "No longer supported" 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /pkg/engine/datasource/introspection_datasource/fixtures/enum_values_without_deprecated.golden: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "NEWHOPE", 4 | "description": "", 5 | "isDeprecated": false, 6 | "deprecationReason": null 7 | }, 8 | { 9 | "name": "EMPIRE", 10 | "description": "", 11 | "isDeprecated": false, 12 | "deprecationReason": null 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /pkg/engine/datasource/introspection_datasource/fixtures/fields_without_deprecated.golden: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "droid", 4 | "description": "", 5 | "args": [ 6 | { 7 | "name": "id", 8 | "description": "", 9 | "type": { 10 | "kind": "NON_NULL", 11 | "name": null, 12 | "ofType": { 13 | "kind": "SCALAR", 14 | "name": "ID", 15 | "ofType": null 16 | } 17 | }, 18 | "defaultValue": null 19 | } 20 | ], 21 | "type": { 22 | "kind": "OBJECT", 23 | "name": "Droid", 24 | "ofType": null 25 | }, 26 | "isDeprecated": false, 27 | "deprecationReason": null 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /pkg/engine/datasource/introspection_datasource/fixtures/not_existing_type.golden: -------------------------------------------------------------------------------- 1 | null -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/defer_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "users": [ 4 | { 5 | "id": 1, 6 | "name": "Leanne Graham", 7 | "posts": null 8 | }, 9 | { 10 | "id": 2, 11 | "name": "Ervin Howell", 12 | "posts": null 13 | } 14 | ] 15 | } 16 | } -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/defer_2.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "replace", 4 | "path": "/data/users/0/posts", 5 | "value": [ 6 | { 7 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 8 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 9 | }, 10 | { 11 | "title": "qui est esse", 12 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 13 | } 14 | ] 15 | } 16 | ] -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/defer_3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "replace", 4 | "path": "/data/users/1/posts", 5 | "value": [ 6 | { 7 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 8 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 9 | }, 10 | { 11 | "title": "qui est esse", 12 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 13 | } 14 | ] 15 | } 16 | ] -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/posts.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "userId": 1, 4 | "id": 1, 5 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 6 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 7 | }, 8 | { 9 | "userId": 1, 10 | "id": 2, 11 | "title": "qui est esse", 12 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 13 | } 14 | ] -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/stream_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "users": [] 4 | } 5 | } -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/stream_2.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "add", 4 | "path": "/data/users/0", 5 | "value": { 6 | "id": 1, 7 | "name": "Leanne Graham" 8 | } 9 | } 10 | ] -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/stream_3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "add", 4 | "path": "/data/users/1", 5 | "value": { 6 | "id": 2, 7 | "name": "Ervin Howell" 8 | } 9 | } 10 | ] -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/stream_4.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "users": [ 4 | { 5 | "id": 1, 6 | "name": "Leanne Graham" 7 | } 8 | ] 9 | } 10 | } -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/stream_5.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "users": [ 4 | { 5 | "id": 1, 6 | "name": "Leanne Graham" 7 | }, 8 | { 9 | "id": 2, 10 | "name": "Ervin Howell" 11 | } 12 | ] 13 | } 14 | } -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/stream_6.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "add", 4 | "path": "/data/users/0", 5 | "value": { 6 | "id": 1, 7 | "name": "Leanne Graham", 8 | "posts": null 9 | } 10 | } 11 | ] -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/stream_7.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "add", 4 | "path": "/data/users/1", 5 | "value": { 6 | "id": 2, 7 | "name": "Ervin Howell", 8 | "posts": null 9 | } 10 | } 11 | ] -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/stream_8.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "replace", 4 | "path": "/data/users/0/posts", 5 | "value": [ 6 | { 7 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 8 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 9 | }, 10 | { 11 | "title": "qui est esse", 12 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 13 | } 14 | ] 15 | } 16 | ] -------------------------------------------------------------------------------- /pkg/engine/resolve/testdata/stream_9.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "replace", 4 | "path": "/data/users/1/posts", 5 | "value": [ 6 | { 7 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 8 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 9 | }, 10 | { 11 | "title": "qui est esse", 12 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 13 | } 14 | ] 15 | } 16 | ] -------------------------------------------------------------------------------- /pkg/escape/bytes.go: -------------------------------------------------------------------------------- 1 | package escape 2 | 3 | func Bytes(in, out []byte) []byte { 4 | 5 | out = out[:0] 6 | 7 | for i := range in { 8 | switch in[i] { 9 | case 9: 10 | out = append(out, 92, 116) // \t 11 | case 10: 12 | out = append(out, 92, 110) // \n 13 | case 34: 14 | if i > 0 && in[i-1] == 92 { 15 | out = append(out, 92, 92, 34) // \\" 16 | } else { 17 | out = append(out, 92, 34) // \" 18 | } 19 | case 92: 20 | // if we have `\\` inside string 21 | if in[i-1] == 92 { 22 | // make 4 in a row 23 | out = append(out, 92, 92, 92) 24 | continue 25 | } 26 | fallthrough 27 | default: 28 | out = append(out, in[i]) 29 | } 30 | } 31 | 32 | return out 33 | } 34 | -------------------------------------------------------------------------------- /pkg/escape/escape.go: -------------------------------------------------------------------------------- 1 | // Package escape enables efficient JSON escaping on byte slices. 2 | package escape 3 | -------------------------------------------------------------------------------- /pkg/execution/datasource/hooks.go: -------------------------------------------------------------------------------- 1 | package datasource 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | type HookContext struct { 8 | TypeName string 9 | FieldName string 10 | } 11 | 12 | type Hooks struct { 13 | PreSendHttpHook PreSendHttpHook 14 | PostReceiveHttpHook PostReceiveHttpHook 15 | } 16 | 17 | type PreSendHttpHook interface { 18 | Execute(ctx HookContext, req *http.Request) 19 | } 20 | 21 | type PostReceiveHttpHook interface { 22 | Execute(ctx HookContext, resp *http.Response, body []byte) 23 | } 24 | -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/directives/graphql_datasource.graphql: -------------------------------------------------------------------------------- 1 | directive @GraphQLDataSource ( 2 | """ 3 | the host of the origin 4 | """ 5 | host: String! 6 | """ 7 | the url of the origin 8 | """ 9 | url: String! 10 | """ 11 | the HTTP method the client should use for the request, defaults to GET 12 | """ 13 | method: HTTP_METHOD = POST 14 | """ 15 | parameters 16 | """ 17 | params: [Parameter] 18 | ) on FIELD_DEFINITION -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/directives/mapping.graphql: -------------------------------------------------------------------------------- 1 | """ 2 | mapping is the directive to define mappings from response objects to GraphQL fields 3 | """ 4 | directive @mapping( 5 | """ 6 | mode defines the operating mode of the mapping 7 | """ 8 | mode: MAPPING_MODE! = PATH_SELECTOR 9 | """ 10 | pathSelector is the optional selector String to customize the mappings 11 | see https://github.com/tidwall/gjson for more information on what syntax is possible 12 | """ 13 | pathSelector: String 14 | ) on FIELD_DEFINITION -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/directives/mqtt_datasource.graphql: -------------------------------------------------------------------------------- 1 | """ 2 | MQTTDataSource 3 | """ 4 | directive @MQTTDataSource ( 5 | brokerAddr: String! 6 | clientID: String! 7 | topic: String! 8 | ) on FIELD_DEFINITION -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/directives/nats_datasource.graphql: -------------------------------------------------------------------------------- 1 | """ 2 | NatsDataSource 3 | """ 4 | directive @NatsDataSource ( 5 | addr: String! 6 | topic: String! 7 | ) on FIELD_DEFINITION -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/directives/static_datasource.graphql: -------------------------------------------------------------------------------- 1 | directive @StaticDataSource ( 2 | data: String 3 | ) on FIELD_DEFINITION -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/directives/transformation.graphql: -------------------------------------------------------------------------------- 1 | directive @transformation( 2 | mode: TRANSFORMATION_MODE = PIPELINE 3 | pipelineConfigFile: String 4 | pipelineConfigString: String 5 | ) on FIELD_DEFINITION -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/directives/wasm_datasource.graphql: -------------------------------------------------------------------------------- 1 | directive @WasmDataSource ( 2 | input: String! 3 | wasmFile: String! 4 | ) on FIELD_DEFINITION -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/enums/http_method.graphql: -------------------------------------------------------------------------------- 1 | enum HTTP_METHOD { 2 | GET 3 | POST 4 | UPDATE 5 | DELETE 6 | } -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/enums/mapping_mode.graphql: -------------------------------------------------------------------------------- 1 | """ 2 | MAPPING_MODE is the enum to define the different mapper modes 3 | """ 4 | enum MAPPING_MODE { 5 | """ 6 | NONE is the mode to skip mappings at all, therefore the parent object will directly get passed to the child 7 | """ 8 | NONE 9 | """ 10 | PATH_SELECTOR is the mode which applies a path selector string on the parent object before passing it to the child 11 | see https://github.com/tidwall/gjson for more information on what syntax is possible 12 | """ 13 | PATH_SELECTOR 14 | } -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/enums/transformation_mode.graphql: -------------------------------------------------------------------------------- 1 | enum TRANSFORMATION_MODE { 2 | PIPELINE 3 | } -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/inputs/header.graphql: -------------------------------------------------------------------------------- 1 | input Header { 2 | key: String! 3 | value: String! 4 | } -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/inputs/parameter.graphql: -------------------------------------------------------------------------------- 1 | """ 2 | Parameter is useful to map variables from various sources into the data source executor. 3 | """ 4 | input Parameter { 5 | """ 6 | this is the name by which the execution engine will access the variable 7 | """ 8 | name: String! 9 | """ 10 | the kind of the parameter source 11 | currently sources: the context, the enclosing object (at execution time), field variables 12 | """ 13 | sourceKind: PARAMETER_SOURCE! 14 | """ 15 | name of the parameter on the source 16 | """ 17 | sourceName: String! 18 | """ 19 | type name of the variable, used to generate a valid GraphQL query for the upstream 20 | """ 21 | variableType: String! 22 | } -------------------------------------------------------------------------------- /pkg/execution/graphql_definitions/inputs/statuscode_typename_mapping.graphql: -------------------------------------------------------------------------------- 1 | input StatusCodeTypeNameMapping { 2 | statusCode: Int! 3 | typeName: String! 4 | } -------------------------------------------------------------------------------- /pkg/execution/jsonvaluetype_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=JSONValueType"; DO NOT EDIT. 2 | 3 | package execution 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[UnknownValueType-0] 12 | _ = x[StringValueType-1] 13 | _ = x[IntegerValueType-2] 14 | _ = x[FloatValueType-3] 15 | _ = x[BooleanValueType-4] 16 | } 17 | 18 | const _JSONValueType_name = "UnknownValueTypeStringValueTypeIntegerValueTypeFloatValueTypeBooleanValueType" 19 | 20 | var _JSONValueType_index = [...]uint8{0, 16, 31, 47, 61, 77} 21 | 22 | func (i JSONValueType) String() string { 23 | if i < 0 || i >= JSONValueType(len(_JSONValueType_index)-1) { 24 | return "JSONValueType(" + strconv.FormatInt(int64(i), 10) + ")" 25 | } 26 | return _JSONValueType_name[_JSONValueType_index[i]:_JSONValueType_index[i+1]] 27 | } 28 | -------------------------------------------------------------------------------- /pkg/execution/testdata/memory.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/graphql-go-tools/a8e1ade2da8ecd5b85065c3e8c9364057d6b173c/pkg/execution/testdata/memory.wasm -------------------------------------------------------------------------------- /pkg/execution/testdata/simple_pipeline.json: -------------------------------------------------------------------------------- 1 | { 2 | "steps": [ 3 | { 4 | "kind": "NOOP" 5 | } 6 | ] 7 | } -------------------------------------------------------------------------------- /pkg/execution/transformation.go: -------------------------------------------------------------------------------- 1 | package execution 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/jensneuse/pipeline/pkg/pipe" 7 | ) 8 | 9 | type Transformation interface { 10 | Transform(input []byte) ([]byte, error) 11 | } 12 | 13 | type PipelineTransformation struct { 14 | pipeline pipe.Pipeline 15 | buf bytes.Buffer 16 | } 17 | 18 | func (p *PipelineTransformation) Transform(input []byte) ([]byte, error) { 19 | p.buf.Reset() 20 | err := p.pipeline.Run(bytes.NewReader(input), &p.buf) 21 | return p.buf.Bytes(), err 22 | } 23 | -------------------------------------------------------------------------------- /pkg/federation/sdlmerge/remove_empty_object_type_definition_test.go: -------------------------------------------------------------------------------- 1 | package sdlmerge 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestRemoveEmptyObjectTypeDefinitionDirective(t *testing.T) { 8 | t.Run("remove object definition without fields", func(t *testing.T) { 9 | run(t, newRemoveEmptyObjectTypeDefinition(), ` 10 | type Query { 11 | } 12 | type Cat { 13 | name: String! 14 | } 15 | `, ` 16 | type Cat { 17 | name: String! 18 | } 19 | `) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /pkg/federation/sdlmerge/remove_field_definition_by_directive_test.go: -------------------------------------------------------------------------------- 1 | package sdlmerge 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestRemoveFieldDirective(t *testing.T) { 8 | t.Run("remove field with specified directive", func(t *testing.T) { 9 | run( 10 | t, newRemoveFieldDefinitions("forDelete"), 11 | ` 12 | type Dog { 13 | name: String @notForDelete 14 | favoriteToy: String @forDelete 15 | barkVolume: Int 16 | isHousetrained(atOtherHomes: Boolean): Boolean! @forDelete 17 | doesKnowCommand(dogCommand: DogCommand!): Boolean! 18 | } 19 | `, 20 | ` 21 | type Dog { 22 | name: String @notForDelete 23 | barkVolume: Int 24 | doesKnowCommand(dogCommand: DogCommand!): Boolean! 25 | } 26 | `) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/federation/sdlmerge/remove_field_definition_directive_test.go: -------------------------------------------------------------------------------- 1 | package sdlmerge 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestRemoveFieldDefinitionDirective(t *testing.T) { 8 | t.Run("remove specified directive from field definition", func(t *testing.T) { 9 | run( 10 | t, 11 | newRemoveFieldDefinitionDirective("requires", "provides"), 12 | ` 13 | type Dog { 14 | name: String! 15 | age: Int! 16 | code: String @requires(fields: "name age") 17 | owner: Owner @provides(fields: "name") 18 | } 19 | `, 20 | ` 21 | type Dog { 22 | name: String! 23 | age: Int! 24 | code: String 25 | owner: Owner 26 | }`, 27 | ) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /pkg/federation/sdlmerge/remove_type_extensions.go: -------------------------------------------------------------------------------- 1 | package sdlmerge 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/pkg/ast" 5 | "github.com/TykTechnologies/graphql-go-tools/pkg/astvisitor" 6 | ) 7 | 8 | func newRemoveMergedTypeExtensions() *removeMergedTypeExtensionsVisitor { 9 | return &removeMergedTypeExtensionsVisitor{} 10 | } 11 | 12 | type removeMergedTypeExtensionsVisitor struct { 13 | } 14 | 15 | func (r *removeMergedTypeExtensionsVisitor) Register(walker *astvisitor.Walker) { 16 | walker.RegisterLeaveDocumentVisitor(r) 17 | } 18 | 19 | func (r *removeMergedTypeExtensionsVisitor) LeaveDocument(operation, definition *ast.Document) { 20 | operation.RemoveMergedTypeExtensions() 21 | } 22 | -------------------------------------------------------------------------------- /pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition-non-null.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User! @provides(fields: "username") 4 | product: Product! 5 | } 6 | 7 | #type User @key(fields: "id") { 8 | # id: ID! @external 9 | # username: String! @external 10 | # reviews: [Review] 11 | #} 12 | 13 | extend type Product @key(fields: "upc") { 14 | upc: String! @external 15 | reviews: [Review] 16 | } 17 | -------------------------------------------------------------------------------- /pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User @provides(fields: "username") 4 | product: Product 5 | } 6 | 7 | #type User @key(fields: "id") { 8 | # id: ID! @external 9 | # username: String! @external 10 | # reviews: [Review] 11 | #} 12 | 13 | extend type Product @key(fields: "upc") { 14 | upc: String! @external 15 | reviews: [Review] 16 | } 17 | -------------------------------------------------------------------------------- /pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition-non-null.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User! @provides(fields: "username") 4 | product: Product! 5 | } 6 | 7 | type User @key(fields: "id") { 8 | id: ID! @external 9 | username: String! @external 10 | reviews: [Review] 11 | } 12 | 13 | #extend type Product @key(fields: "upc") { 14 | # @external 15 | # reviews: [Review] } 16 | #} 17 | -------------------------------------------------------------------------------- /pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User @provides(fields: "username") 4 | product: Product 5 | } 6 | 7 | type User @key(fields: "id") { 8 | id: ID! @external 9 | username: String! @external 10 | reviews: [Review] 11 | } 12 | 13 | #extend type Product @key(fields: "upc") { 14 | # upc: String! @external 15 | # reviews: [Review] 16 | #} 17 | 18 | -------------------------------------------------------------------------------- /pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined-non-null.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User! @provides(fields: "username") 4 | product: Product! 5 | } 6 | 7 | type User @key(fields: "id") { 8 | id: ID! @external 9 | username: String! @external 10 | reviews: [Review] 11 | } 12 | 13 | extend type Product @key(fields: "upc") { 14 | upc: String! @external 15 | reviews: [Review] 16 | } 17 | -------------------------------------------------------------------------------- /pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User @provides(fields: "username") 4 | product: Product 5 | } 6 | 7 | type User @key(fields: "id") { 8 | id: ID! @external 9 | username: String! @external 10 | reviews: [Review] 11 | } 12 | 13 | extend type Product @key(fields: "upc") { 14 | upc: String! @external 15 | reviews: [Review] 16 | } 17 | -------------------------------------------------------------------------------- /pkg/graphql/lookup.go: -------------------------------------------------------------------------------- 1 | package graphql 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type TypeFieldLookupKey string 8 | 9 | func CreateTypeFieldLookupKey(typeName string, fieldName string) TypeFieldLookupKey { 10 | return TypeFieldLookupKey(fmt.Sprintf("%s.%s", typeName, fieldName)) 11 | } 12 | 13 | func CreateTypeFieldArgumentsLookupMap(typeFieldArgs []TypeFieldArguments) map[TypeFieldLookupKey]TypeFieldArguments { 14 | if len(typeFieldArgs) == 0 { 15 | return nil 16 | } 17 | 18 | lookupMap := make(map[TypeFieldLookupKey]TypeFieldArguments) 19 | for _, currentTypeFieldArgs := range typeFieldArgs { 20 | lookupMap[CreateTypeFieldLookupKey(currentTypeFieldArgs.TypeName, currentTypeFieldArgs.FieldName)] = currentTypeFieldArgs 21 | } 22 | 23 | return lookupMap 24 | } 25 | -------------------------------------------------------------------------------- /pkg/graphql/response.go: -------------------------------------------------------------------------------- 1 | package graphql 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type Response struct { 8 | Errors Errors `json:"errors,omitempty"` 9 | // TODO: Data 10 | // TODO: Extensions 11 | } 12 | 13 | func (r Response) Marshal() ([]byte, error) { 14 | return json.Marshal(r) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/graphql/subscription.go: -------------------------------------------------------------------------------- 1 | package graphql 2 | 3 | type SubscriptionType int 4 | 5 | const ( 6 | // SubscriptionTypeUnknown is for unknown or undefined subscriptions. 7 | SubscriptionTypeUnknown = iota 8 | // SubscriptionTypeSSE is for Server-Sent Events (SSE) subscriptions. 9 | SubscriptionTypeSSE 10 | // SubscriptionTypeGraphQLWS is for subscriptions using a WebSocket connection with 11 | // 'graphql-ws' as protocol. 12 | SubscriptionTypeGraphQLWS 13 | // SubscriptionTypeGraphQLTransportWS is for subscriptions using a WebSocket connection with 14 | // 'graphql-transport-ws' as protocol. 15 | SubscriptionTypeGraphQLTransportWS 16 | ) 17 | -------------------------------------------------------------------------------- /pkg/graphql/types.go: -------------------------------------------------------------------------------- 1 | package graphql 2 | 3 | type ( 4 | Type struct { 5 | Name string `json:"name"` 6 | Fields []string `json:"fields"` 7 | } 8 | 9 | RequestFields map[string]struct{} 10 | RequestTypes map[string]RequestFields 11 | ) 12 | -------------------------------------------------------------------------------- /pkg/graphqlerrors/location.go: -------------------------------------------------------------------------------- 1 | package graphqlerrors 2 | 3 | type Location struct { 4 | Line uint32 `json:"line"` 5 | Column uint32 `json:"column"` 6 | } 7 | -------------------------------------------------------------------------------- /pkg/http/ws_connection_init.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "connection_init", 3 | "payload": {} 4 | } -------------------------------------------------------------------------------- /pkg/http/ws_start.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "1", 3 | "type": "start", 4 | "payload": { 5 | "variables": {}, 6 | "extensions": {}, 7 | "operationName": "stream", 8 | "query": "subscription stream {n stream {n datetimen timezonen abbreviationn }n}n" 9 | } 10 | } -------------------------------------------------------------------------------- /pkg/imports/fixtures/render_result.golden: -------------------------------------------------------------------------------- 1 | #file: testdata/schema.graphql 2 | 3 | 4 | schema { 5 | query: Query 6 | mutation: Mutation 7 | } 8 | 9 | 10 | #file: testdata/scalars/json.graphql 11 | 12 | scalar JSON 13 | 14 | 15 | #file: testdata/types/query.graphql 16 | 17 | type Query { 18 | foo: Foo 19 | } 20 | 21 | 22 | #file: testdata/nested/nested.graphql 23 | 24 | 25 | type Bar { 26 | baz: Int 27 | } 28 | 29 | 30 | #file: testdata/nested2/nested2.graphql 31 | 32 | type Bat { 33 | bar: String 34 | } 35 | 36 | 37 | #file: testdata/deep/deeper/custom_types.graphql 38 | 39 | type Foo { 40 | field: String 41 | } 42 | -------------------------------------------------------------------------------- /pkg/imports/fixtures/scanner_regex.golden: -------------------------------------------------------------------------------- 1 | { 2 | "RelativePath": "", 3 | "Imports": [ 4 | { 5 | "RelativePath": "testdata/regexonly/flat.graphql", 6 | "Imports": null 7 | }, 8 | { 9 | "RelativePath": "testdata/regexonly/mutation.graphql", 10 | "Imports": null 11 | }, 12 | { 13 | "RelativePath": "testdata/regexonly/query.graphql", 14 | "Imports": null 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /pkg/imports/fixtures/scanner_regex_render.golden: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | mutation: Mutation 4 | } 5 | type Mutation { 6 | bar: String 7 | } 8 | type Query { 9 | foo: String 10 | } 11 | -------------------------------------------------------------------------------- /pkg/imports/fixtures/scanner_result.golden: -------------------------------------------------------------------------------- 1 | { 2 | "RelativePath": "testdata/schema.graphql", 3 | "Imports": [ 4 | { 5 | "RelativePath": "testdata/scalars/json.graphql", 6 | "Imports": null 7 | }, 8 | { 9 | "RelativePath": "testdata/types/query.graphql", 10 | "Imports": null 11 | }, 12 | { 13 | "RelativePath": "testdata/nested/nested.graphql", 14 | "Imports": [ 15 | { 16 | "RelativePath": "testdata/nested2/nested2.graphql", 17 | "Imports": null 18 | } 19 | ] 20 | }, 21 | { 22 | "RelativePath": "testdata/deep/deeper/custom_types.graphql", 23 | "Imports": null 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /pkg/imports/graphql_file_test.go: -------------------------------------------------------------------------------- 1 | package imports 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | "testing" 7 | 8 | "github.com/jensneuse/diffview" 9 | 10 | "github.com/TykTechnologies/graphql-go-tools/pkg/testing/goldie" 11 | ) 12 | 13 | func TestGraphQLFile_Render(t *testing.T) { 14 | scanner := Scanner{} 15 | file, err := scanner.ScanFile("testdata/schema.graphql") 16 | if err != nil { 17 | t.Fatal(err) 18 | } 19 | 20 | out := bytes.Buffer{} 21 | err = file.Render(true, &out) 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | 26 | dump := out.Bytes() 27 | 28 | goldie.Assert(t, "render_result", dump, true) 29 | if t.Failed() { 30 | fixture, err := os.ReadFile("./fixtures/render_result.golden") 31 | if err != nil { 32 | t.Fatal(err) 33 | } 34 | 35 | diffview.NewGoland().DiffViewBytes("render_result", fixture, dump) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pkg/imports/testdata/cycle/a/a.graphql: -------------------------------------------------------------------------------- 1 | #import "../b/b.graphql" -------------------------------------------------------------------------------- /pkg/imports/testdata/cycle/b/b.graphql: -------------------------------------------------------------------------------- 1 | #import "../a/a.graphql" -------------------------------------------------------------------------------- /pkg/imports/testdata/deep/deeper/custom_types.graphql: -------------------------------------------------------------------------------- 1 | type Foo { 2 | field: String 3 | } -------------------------------------------------------------------------------- /pkg/imports/testdata/deep/deeper/non_graphql.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/graphql-go-tools/a8e1ade2da8ecd5b85065c3e8c9364057d6b173c/pkg/imports/testdata/deep/deeper/non_graphql.txt -------------------------------------------------------------------------------- /pkg/imports/testdata/import_cycle.graphql: -------------------------------------------------------------------------------- 1 | #import "cycle/a/a.graphql" -------------------------------------------------------------------------------- /pkg/imports/testdata/nested/nested.graphql: -------------------------------------------------------------------------------- 1 | #import "../nested2/nested2.graphql" 2 | 3 | type Bar { 4 | baz: Int 5 | } -------------------------------------------------------------------------------- /pkg/imports/testdata/nested2/nested2.graphql: -------------------------------------------------------------------------------- 1 | type Bat { 2 | bar: String 3 | } -------------------------------------------------------------------------------- /pkg/imports/testdata/regexonly/flat.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | mutation: Mutation 4 | } -------------------------------------------------------------------------------- /pkg/imports/testdata/regexonly/mutation.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | bar: String 3 | } -------------------------------------------------------------------------------- /pkg/imports/testdata/regexonly/query.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | foo: String 3 | } -------------------------------------------------------------------------------- /pkg/imports/testdata/scalars/json.graphql: -------------------------------------------------------------------------------- 1 | scalar JSON -------------------------------------------------------------------------------- /pkg/imports/testdata/schema.graphql: -------------------------------------------------------------------------------- 1 | #import "scalars/*.graphql" 2 | #import "types/query.graphql" 3 | #import "nested/nested.graphql" 4 | #import "deep/**/*.graphql" 5 | 6 | schema { 7 | query: Query 8 | mutation: Mutation 9 | } -------------------------------------------------------------------------------- /pkg/imports/testdata/types/mutation.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | mutateFoo: Foo 3 | } -------------------------------------------------------------------------------- /pkg/imports/testdata/types/query.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | foo: Foo 3 | } -------------------------------------------------------------------------------- /pkg/introspection/introspection_test.go: -------------------------------------------------------------------------------- 1 | package introspection 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | func TestIntrospectionSerialization(t *testing.T) { 10 | inputData, err := os.ReadFile("./testdata/swapi_introspection_response.json") 11 | if err != nil { 12 | panic(err) 13 | } 14 | 15 | var data Data 16 | 17 | err = json.Unmarshal(inputData, &data) 18 | if err != nil { 19 | panic(err) 20 | } 21 | 22 | outputData, err := json.MarshalIndent(data, "", " ") 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | err = os.WriteFile("./testdata/out_swapi_introspection_response.json", outputData, os.ModePerm) 28 | if err != nil { 29 | panic(err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pkg/introspection/testdata/interfaces_implementing_interfaces.graphql: -------------------------------------------------------------------------------- 1 | interface BaseInterface { 2 | fieldOne: String! 3 | } 4 | 5 | interface SecondInterface implements BaseInterface { 6 | fieldOne: String! 7 | fieldTwo: String! 8 | } 9 | 10 | interface ThirdInterface implements SecondInterface & BaseInterface { 11 | fieldOne: String! 12 | fieldTwo: String! 13 | fieldThree: String! 14 | } 15 | 16 | interface IDType { 17 | id: ID! 18 | } 19 | 20 | interface SoftDelete { 21 | deleted: Boolean! 22 | } 23 | 24 | extend interface SoftDelete implements IDType { 25 | id: ID! 26 | } 27 | 28 | interface Record { 29 | data: String! 30 | } 31 | 32 | extend interface Record implements SoftDelete & IDType { 33 | id: ID! 34 | deleted: Boolean! 35 | } 36 | -------------------------------------------------------------------------------- /pkg/lexer/keyword/keyword.go: -------------------------------------------------------------------------------- 1 | //go:generate stringer -type=Keyword 2 | 3 | // Package keyword contains all possible GraphQL keywords 4 | package keyword 5 | 6 | type Keyword int 7 | 8 | const ( 9 | UNDEFINED Keyword = iota 10 | IDENT 11 | COMMENT 12 | EOF 13 | 14 | COLON 15 | BANG 16 | LT 17 | TAB 18 | SPACE 19 | COMMA 20 | AT 21 | DOT 22 | SPREAD 23 | PIPE 24 | SLASH 25 | EQUALS 26 | SUB 27 | AND 28 | QUOTE 29 | 30 | DOLLAR 31 | STRING 32 | BLOCKSTRING 33 | INTEGER 34 | FLOAT 35 | 36 | LPAREN 37 | RPAREN 38 | LBRACK 39 | RBRACK 40 | LBRACE 41 | RBRACE 42 | ) 43 | -------------------------------------------------------------------------------- /pkg/lexer/runes/runes.go: -------------------------------------------------------------------------------- 1 | // Package runes contains all possible 'special' runes in a GraphQL document 2 | package runes 3 | 4 | const ( 5 | EOF = 0 6 | COLON = ':' 7 | BANG = '!' 8 | CARRIAGERETURN = '\r' 9 | LINETERMINATOR = '\n' 10 | TAB = '\t' 11 | SPACE = ' ' 12 | COMMA = ',' 13 | HASHTAG = '#' 14 | QUOTE = '"' 15 | BACKSLASH = '\\' 16 | DOT = '.' 17 | EXPONENT_LOWER = 'e' 18 | EXPONENT_UPPER = 'E' 19 | AT = '@' 20 | DOLLAR = '$' 21 | PIPE = '|' 22 | SLASH = '/' 23 | EQUALS = '=' 24 | SUB = '-' 25 | ADD = '+' 26 | AND = '&' 27 | UNDERSCORE = '_' 28 | 29 | LPAREN = '(' 30 | RPAREN = ')' 31 | LBRACK = '[' 32 | RBRACK = ']' 33 | LBRACE = '{' 34 | RBRACE = '}' 35 | ) 36 | -------------------------------------------------------------------------------- /pkg/middleware/middleware.go: -------------------------------------------------------------------------------- 1 | // Package middleware contains useful middleware components for GraphQL services, e.g. for complexity analysis. 2 | package middleware 3 | -------------------------------------------------------------------------------- /pkg/playground/files/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/graphql-go-tools/a8e1ade2da8ecd5b85065c3e8c9364057d6b173c/pkg/playground/files/favicon.png -------------------------------------------------------------------------------- /pkg/playground/files/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/graphql-go-tools/a8e1ade2da8ecd5b85065c3e8c9364057d6b173c/pkg/playground/files/logo.png -------------------------------------------------------------------------------- /pkg/playground/files/playground.css: -------------------------------------------------------------------------------- 1 | body{margin:0;padding:0;font-family:sans-serif;overflow:hidden}#root{height:100%}body{font-family:Open Sans,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:rgba(0,0,0,.8);line-height:1.5;height:100vh;letter-spacing:.53px;margin-right:-1px!important}a,body,code,h1,h2,h3,h4,html,p,pre,ul{margin:0;padding:0;color:inherit}a:active,a:focus,button:focus,input:focus{outline:none}button,input,submit{border:none}button,input,pre{font-family:Open Sans,sans-serif}code{font-family:Consolas,monospace} -------------------------------------------------------------------------------- /pkg/playground/fixtures/handlers.golden: -------------------------------------------------------------------------------- 1 | (playground.Handlers) (len=5 cap=5) { 2 | (playground.HandlerConfig) { 3 | Path: (string) (len=11) "/playground", 4 | Handler: (http.HandlerFunc) 5 | }, 6 | (playground.HandlerConfig) { 7 | Path: (string) (len=26) "/playground/playground.css", 8 | Handler: (http.HandlerFunc) 9 | }, 10 | (playground.HandlerConfig) { 11 | Path: (string) (len=25) "/playground/playground.js", 12 | Handler: (http.HandlerFunc) 13 | }, 14 | (playground.HandlerConfig) { 15 | Path: (string) (len=23) "/playground/favicon.png", 16 | Handler: (http.HandlerFunc) 17 | }, 18 | (playground.HandlerConfig) { 19 | Path: (string) (len=20) "/playground/logo.png", 20 | Handler: (http.HandlerFunc) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pkg/pool/bytesbuffer.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import ( 4 | "bytes" 5 | "sync" 6 | ) 7 | 8 | var ( 9 | BytesBuffer = bytesBufferPool{ 10 | pool: sync.Pool{ 11 | New: func() interface{} { 12 | return bytes.NewBuffer(make([]byte, 0, 1024)) 13 | }, 14 | }, 15 | } 16 | ) 17 | 18 | type bytesBufferPool struct { 19 | pool sync.Pool 20 | } 21 | 22 | func (b *bytesBufferPool) Get() *bytes.Buffer { 23 | return b.pool.Get().(*bytes.Buffer) 24 | } 25 | 26 | func (b *bytesBufferPool) Put(buf *bytes.Buffer) { 27 | buf.Reset() 28 | b.pool.Put(buf) 29 | } 30 | -------------------------------------------------------------------------------- /pkg/pool/fastbuffer.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/TykTechnologies/graphql-go-tools/pkg/fastbuffer" 7 | ) 8 | 9 | var FastBuffer = fastBufferPool{ 10 | pool: sync.Pool{ 11 | New: func() interface{} { 12 | return fastbuffer.New() 13 | }, 14 | }, 15 | } 16 | 17 | type fastBufferPool struct { 18 | pool sync.Pool 19 | } 20 | 21 | func (f *fastBufferPool) Get() *fastbuffer.FastBuffer { 22 | return f.pool.Get().(*fastbuffer.FastBuffer) 23 | } 24 | 25 | func (f *fastBufferPool) Put(buf *fastbuffer.FastBuffer) { 26 | buf.Reset() 27 | f.pool.Put(buf) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/pool/hash64.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import ( 4 | "hash" 5 | "sync" 6 | 7 | "github.com/cespare/xxhash/v2" 8 | ) 9 | 10 | var ( 11 | Hash64 = hash64Pool{ 12 | pool: sync.Pool{ 13 | New: func() interface{} { 14 | return xxhash.New() 15 | }, 16 | }, 17 | } 18 | ) 19 | 20 | type hash64Pool struct { 21 | pool sync.Pool 22 | } 23 | 24 | func (b *hash64Pool) Get() hash.Hash64 { 25 | return b.pool.Get().(hash.Hash64) 26 | } 27 | 28 | func (b *hash64Pool) Put(hash64 hash.Hash64) { 29 | hash64.Reset() 30 | b.pool.Put(hash64) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/repair/repair.go: -------------------------------------------------------------------------------- 1 | // Package repair helps fixing problems in GraphQL documents 2 | package repair 3 | -------------------------------------------------------------------------------- /pkg/starwars/testdata/mutations/create_review.mutation: -------------------------------------------------------------------------------- 1 | mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { 2 | createReview(episode: $ep, review: $review) { 3 | id 4 | stars 5 | commentary 6 | } 7 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/directives_include.query: -------------------------------------------------------------------------------- 1 | query Hero($withFriends: Boolean!) { 2 | hero { 3 | name 4 | friends @include(if: $withFriends) { 5 | name 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/directives_skip.query: -------------------------------------------------------------------------------- 1 | query Hero($skipFriends: Boolean!) { 2 | hero { 3 | name 4 | friends @skip(if: $skipFriends) { 5 | name 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/droid_with_arg.query: -------------------------------------------------------------------------------- 1 | { 2 | droid(id: "R2D2") { 3 | name 4 | } 5 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/droid_with_arg_and_var.query: -------------------------------------------------------------------------------- 1 | query Droid($droidID: ID!) { 2 | droid(id: $droidID) { 3 | name 4 | } 5 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/fragments.query: -------------------------------------------------------------------------------- 1 | query Fragments($droidID: ID!){ 2 | hero { 3 | ...characterFields 4 | } 5 | droid(id: $droidID) { 6 | ...characterFields 7 | } 8 | } 9 | 10 | fragment characterFields on Character { 11 | name 12 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/hero_with_aliases.query: -------------------------------------------------------------------------------- 1 | { 2 | empireHero: hero { 3 | name 4 | } 5 | jediHero: hero { 6 | name 7 | } 8 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/hero_with_operation_name.query: -------------------------------------------------------------------------------- 1 | query Hero { 2 | hero { 3 | name 4 | } 5 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/inline_fragments.query: -------------------------------------------------------------------------------- 1 | { 2 | hero { 3 | friends { 4 | ...on Droid { 5 | name 6 | primaryFunction 7 | } 8 | ...on Human { 9 | name 10 | height 11 | } 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/interface_fragments_on_union.graphql: -------------------------------------------------------------------------------- 1 | query SearchResults { 2 | searchResults { 3 | ...on Character { 4 | name 5 | } 6 | ...on Vehicle { 7 | length 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/invalid.query: -------------------------------------------------------------------------------- 1 | { 2 | hero { 3 | invalid 4 | } 5 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/invalid_fragments.query: -------------------------------------------------------------------------------- 1 | query Fragments($droidID: ID!){ 2 | droid(id: $droidID) { 3 | ...reviewFields 4 | } 5 | } 6 | 7 | fragment reviewFields on Review { 8 | id 9 | stars 10 | commentary 11 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/multi_queries.query: -------------------------------------------------------------------------------- 1 | query MultiHeroes { 2 | empireHero: hero { 3 | name 4 | } 5 | jediHero: hero { 6 | name 7 | } 8 | } 9 | 10 | query SingleHero { 11 | hero { 12 | name 13 | } 14 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/multi_queries_with_arguments.query: -------------------------------------------------------------------------------- 1 | query GetDroid { 2 | droid(id: "1") { 3 | name 4 | } 5 | } 6 | 7 | query Search { 8 | search(name: "C3PO") { 9 | ...on Droid { 10 | name 11 | primaryFunction 12 | } 13 | ...on Human { 14 | name 15 | height 16 | } 17 | ...on Starship { 18 | name 19 | length 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/simple_hero.query: -------------------------------------------------------------------------------- 1 | { 2 | hero { 3 | name 4 | } 5 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/queries/union.query: -------------------------------------------------------------------------------- 1 | query Search($name: String!) { 2 | search(name: $name) { 3 | ...on Droid { 4 | name 5 | primaryFunction 6 | } 7 | ...on Human { 8 | name 9 | height 10 | } 11 | ...on Starship { 12 | name 13 | length 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /pkg/starwars/testdata/subscriptions/remaining_jedis.subscription: -------------------------------------------------------------------------------- 1 | subscription { 2 | remainingJedis 3 | } -------------------------------------------------------------------------------- /pkg/subscription/constants.go: -------------------------------------------------------------------------------- 1 | package subscription 2 | 3 | const ( 4 | DefaultKeepAliveInterval = "15s" 5 | DefaultSubscriptionUpdateInterval = "1s" 6 | DefaultReadErrorTimeOut = "5s" 7 | DefaultSubscriptionExecutionTries = 5 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/subscription/executor.go: -------------------------------------------------------------------------------- 1 | package subscription 2 | 3 | //go:generate mockgen -destination=executor_mock_test.go -package=subscription . Executor,ExecutorPool 4 | 5 | import ( 6 | "context" 7 | 8 | "github.com/TykTechnologies/graphql-go-tools/pkg/ast" 9 | "github.com/TykTechnologies/graphql-go-tools/pkg/engine/resolve" 10 | ) 11 | 12 | // Executor is an abstraction for executing a GraphQL engine 13 | type Executor interface { 14 | Execute(writer resolve.FlushWriter) error 15 | OperationType() ast.OperationType 16 | SetContext(context context.Context) 17 | Reset() 18 | } 19 | 20 | // ExecutorPool is an abstraction for creating executors 21 | type ExecutorPool interface { 22 | Get(payload []byte) (Executor, error) 23 | Put(executor Executor) error 24 | } 25 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/accounts/graph/handler.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/99designs/gqlgen/graphql/handler" 7 | "github.com/99designs/gqlgen/graphql/handler/debug" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/generated" 10 | ) 11 | 12 | type EndpointOptions struct { 13 | EnableDebug bool 14 | } 15 | 16 | var TestOptions = EndpointOptions{ 17 | EnableDebug: false, 18 | } 19 | 20 | func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { 21 | srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) 22 | if opts.EnableDebug { 23 | srv.Use(&debug.Tracer{}) 24 | } 25 | 26 | return srv 27 | } 28 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/accounts/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | type Resolver struct{} 7 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/accounts/graph/wallets.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/model" 4 | 5 | var walletOne = &model.WalletType1{ 6 | Currency: "USD", 7 | Amount: 123, 8 | SpecialField1: "some special value 1", 9 | } 10 | 11 | var walletTwo = &model.WalletType2{ 12 | Currency: "USD", 13 | Amount: 123, 14 | SpecialField2: "some special value 2", 15 | } 16 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/accounts/handler.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package accounts 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/TykTechnologies/graphql-go-tools/pkg/testing/federationtesting/accounts/graph" 8 | ) 9 | 10 | func Handler() http.Handler { 11 | return graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true}) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/products/graph/model/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package model 4 | 5 | type Product struct { 6 | Upc string `json:"upc"` 7 | Name string `json:"name"` 8 | Price int `json:"price"` 9 | InStock int `json:"inStock"` 10 | } 11 | 12 | func (Product) IsEntity() {} 13 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/products/graph/products.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/pkg/testing/federationtesting/products/graph/model" 5 | ) 6 | 7 | var hats []*model.Product 8 | 9 | func Reset() { 10 | hats = []*model.Product{ 11 | { 12 | Upc: "top-1", 13 | Name: "Trilby", 14 | Price: 11, 15 | InStock: 500, 16 | }, 17 | { 18 | Upc: "top-2", 19 | Name: "Fedora", 20 | Price: 22, 21 | InStock: 1200, 22 | }, 23 | { 24 | Upc: "top-3", 25 | Name: "Boater", 26 | Price: 33, 27 | InStock: 850, 28 | }, 29 | } 30 | } 31 | 32 | func init() { 33 | Reset() 34 | } 35 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/products/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | import ( 7 | "time" 8 | ) 9 | 10 | type Resolver struct { 11 | updateInterval time.Duration 12 | } 13 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/products/graph/schema.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | topProducts(first: Int = 5): [Product] 3 | } 4 | 5 | extend type Subscription { 6 | updatedPrice: Product! 7 | updateProductPrice(upc: String!): Product! 8 | } 9 | 10 | type Product @key(fields: "upc") { 11 | upc: String! 12 | name: String! 13 | price: Int! 14 | inStock: Int! 15 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/products/graph/variables.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | var ( 8 | randomnessEnabled = true 9 | minPrice = 10 10 | maxPrice = 1499 11 | currentPrice = minPrice 12 | updateInterval = time.Second 13 | ) 14 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/products/handler.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package products 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/TykTechnologies/graphql-go-tools/pkg/testing/federationtesting/products/graph" 8 | ) 9 | 10 | func Handler() http.Handler { 11 | mux := http.NewServeMux() 12 | 13 | mux.Handle("/", graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true})) 14 | mux.HandleFunc("/websocket_connections", graph.WebsocketConnectionsHandler) 15 | 16 | return mux 17 | } 18 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/reviews/graph/attachments.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/model" 4 | 5 | var attachments = []model.Attachment{ 6 | model.Question{ 7 | Upc: "top-1", 8 | Body: "How do I turn it on?", 9 | }, 10 | model.Question{ 11 | Upc: "top-3", 12 | Body: "Any recommendations for other teacosies?", 13 | }, 14 | model.Rating{ 15 | Upc: "top-2", 16 | Body: "The best hat I have ever bought in my life.", 17 | Score: 5, 18 | }, 19 | model.Rating{ 20 | Upc: "top-3", 21 | Body: "Terrible teacosy!!!", 22 | Score: 0, 23 | }, 24 | model.Video{ 25 | Upc: "top-2", 26 | Size: 13.37, 27 | }, 28 | model.Video{ 29 | Upc: "top-3", 30 | Size: 4.20, 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/reviews/graph/handler.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/99designs/gqlgen/graphql/handler" 7 | "github.com/99designs/gqlgen/graphql/handler/debug" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/generated" 10 | ) 11 | 12 | type EndpointOptions struct { 13 | EnableDebug bool 14 | } 15 | 16 | var TestOptions = EndpointOptions{ 17 | EnableDebug: false, 18 | } 19 | 20 | func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { 21 | srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) 22 | if opts.EnableDebug { 23 | srv.Use(&debug.Tracer{}) 24 | } 25 | 26 | return srv 27 | } 28 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/reviews/graph/model/models.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Product struct { 4 | Upc string `json:"upc"` 5 | } 6 | 7 | func (Product) IsEntity() {} 8 | 9 | type Review struct { 10 | Body string 11 | Author *User 12 | Product *Product 13 | } 14 | 15 | type User struct { 16 | ID string `json:"id"` 17 | } 18 | 19 | func (User) IsEntity() {} 20 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/reviews/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | type Resolver struct{} 7 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/reviews/graph/reviews.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/model" 5 | ) 6 | 7 | var reviews = []*model.Review{ 8 | { 9 | Body: "A highly effective form of birth control.", 10 | Product: &model.Product{Upc: "top-1"}, 11 | Author: &model.User{ID: "1234"}, 12 | }, 13 | { 14 | Body: "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.", 15 | Product: &model.Product{Upc: "top-2"}, 16 | Author: &model.User{ID: "1234"}, 17 | }, 18 | { 19 | Body: "This is the last straw. Hat you will wear. 11/10", 20 | Product: &model.Product{Upc: "top-3"}, 21 | Author: &model.User{ID: "7777"}, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/reviews/handler.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package reviews 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/TykTechnologies/graphql-go-tools/pkg/testing/federationtesting/reviews/graph" 8 | ) 9 | 10 | func Handler() http.Handler { 11 | return graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true}) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/mutations/mutation_with_variables.query: -------------------------------------------------------------------------------- 1 | mutation AddReview($authorID: String!, $upc: String!, $review: String!) { 2 | addReview(authorID: $authorID upc: $upc, review: $review) { 3 | body 4 | author { 5 | username 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/interface.query: -------------------------------------------------------------------------------- 1 | query MyHistory { 2 | me { 3 | username 4 | history { 5 | ... on Purchase { 6 | wallet { 7 | amount 8 | ... on WalletType1 { 9 | specialField1 10 | } 11 | ... on WalletType2 { 12 | specialField2 13 | } 14 | } 15 | } 16 | ... on Sale { 17 | rating 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/interface_fragment_on_object.graphql: -------------------------------------------------------------------------------- 1 | query InterfaceFragment { 2 | me { 3 | ... on Identifiable { 4 | id 5 | } 6 | ... on User { 7 | username 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/interface_fragments_on_union.graphql: -------------------------------------------------------------------------------- 1 | query InterfaceFragmentsOnUnion { 2 | histories { 3 | ... on Store { 4 | __typename 5 | location 6 | } 7 | ... on Info { 8 | __typename 9 | quantity 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/merged_field.graphql: -------------------------------------------------------------------------------- 1 | query MergedField { 2 | cat { 3 | name 4 | } 5 | me { 6 | id 7 | username 8 | realName 9 | reviews { 10 | body 11 | } 12 | history { 13 | ... on Sale { 14 | rating 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/multiple_queries.query: -------------------------------------------------------------------------------- 1 | query { 2 | topProducts { 3 | __typename 4 | price 5 | upc 6 | } 7 | me { 8 | __typename 9 | id 10 | username 11 | } 12 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/multiple_queries_with_nested_fragments.query: -------------------------------------------------------------------------------- 1 | fragment ProductFragment on Product { 2 | __typename 3 | price 4 | upc 5 | } 6 | 7 | fragment ReviewFragment on Review { 8 | __typename 9 | product { 10 | ...ProductFragment 11 | } 12 | } 13 | 14 | fragment UserFragment on User { 15 | __typename 16 | id 17 | username 18 | reviews { 19 | ...ReviewFragment 20 | } 21 | } 22 | 23 | query { 24 | topProducts { 25 | ...ProductFragment 26 | } 27 | me { 28 | ...UserFragment 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/multiple_queries_with_union_return.query: -------------------------------------------------------------------------------- 1 | query Histories { 2 | me { 3 | __typename 4 | id 5 | username 6 | } 7 | histories { 8 | __typename 9 | ... on Sale { 10 | product { 11 | __typename 12 | upc 13 | } 14 | rating 15 | } 16 | ... on Purchase { 17 | product { 18 | __typename 19 | upc 20 | } 21 | wallet { 22 | __typename 23 | currency 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/multiple_upstream.query: -------------------------------------------------------------------------------- 1 | query MultipleServers { 2 | topProducts { 3 | name 4 | reviews { 5 | body 6 | author { 7 | username 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/object_fragment_on_interface.graphql: -------------------------------------------------------------------------------- 1 | query InterfaceResponse { 2 | identifiable { 3 | __typename 4 | id 5 | ... on User { 6 | username 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/single_upstream.query: -------------------------------------------------------------------------------- 1 | query Me { 2 | me { 3 | id 4 | username 5 | } 6 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/queries/union.query: -------------------------------------------------------------------------------- 1 | query MyHistory { 2 | me { 3 | username 4 | history { 5 | __typename 6 | ... on Purchase { 7 | wallet { 8 | amount 9 | } 10 | } 11 | ... on Sale { 12 | rating 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /pkg/testing/federationtesting/testdata/subscriptions/subscription.query: -------------------------------------------------------------------------------- 1 | subscription UpdatePrice($upc: String!) { 2 | updateProductPrice(upc: $upc) { 3 | upc 4 | name 5 | price 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /pkg/testing/goldie/goldie.go: -------------------------------------------------------------------------------- 1 | package goldie 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sebdah/goldie/v2" 7 | ) 8 | 9 | // New creates a new instance of Goldie. 10 | func New(t *testing.T) *goldie.Goldie { 11 | return goldie.New(t, goldie.WithFixtureDir("fixtures")) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/testing/goldie/goldie_posix.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | // +build !windows 3 | 4 | package goldie 5 | 6 | import ( 7 | "testing" 8 | ) 9 | 10 | func Assert(t *testing.T, name string, actual []byte, _ ...bool) { 11 | t.Helper() 12 | 13 | New(t).Assert(t, name, actual) 14 | } 15 | 16 | func Update(t *testing.T, name string, actual []byte) { 17 | t.Helper() 18 | 19 | _ = New(t).Update(t, name, actual) 20 | } 21 | -------------------------------------------------------------------------------- /pkg/testing/goldie/goldie_win.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package goldie 5 | 6 | import ( 7 | "testing" 8 | ) 9 | 10 | func Assert(t *testing.T, name string, actual []byte, useOSSuffix ...bool) { 11 | t.Helper() 12 | 13 | if len(useOSSuffix) == 1 && useOSSuffix[0] { 14 | name = name + "_windows" 15 | } 16 | 17 | New(t).Assert(t, name, actual) 18 | } 19 | 20 | func Update(t *testing.T, name string, actual []byte) { 21 | t.Helper() 22 | t.Fatalf("golden files should not be updated on windows") 23 | } 24 | -------------------------------------------------------------------------------- /pkg/testing/subscriptiontesting/.gqlgen.yml: -------------------------------------------------------------------------------- 1 | models: 2 | Chatroom: 3 | model: github.com/TykTechnologies/graphql-go-tools/pkg/testing/subscriptiontesting.Chatroom 4 | -------------------------------------------------------------------------------- /pkg/testing/subscriptiontesting/handler.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package subscriptiontesting 3 | 4 | import ( 5 | "net/http" 6 | "time" 7 | 8 | "github.com/99designs/gqlgen/graphql/handler" 9 | "github.com/99designs/gqlgen/graphql/handler/extension" 10 | "github.com/99designs/gqlgen/graphql/handler/transport" 11 | "github.com/gorilla/websocket" 12 | ) 13 | 14 | func ChatGraphQLEndpointHandler() http.Handler { 15 | srv := handler.New(NewExecutableSchema(New())) 16 | 17 | srv.AddTransport(transport.POST{}) 18 | srv.AddTransport(transport.Websocket{ 19 | KeepAlivePingInterval: 10 * time.Second, 20 | Upgrader: websocket.Upgrader{ 21 | CheckOrigin: func(r *http.Request) bool { 22 | return true 23 | }, 24 | }, 25 | }) 26 | srv.Use(extension.Introspection{}) 27 | 28 | return srv 29 | } 30 | -------------------------------------------------------------------------------- /pkg/testing/subscriptiontesting/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package subscriptiontesting 4 | 5 | import ( 6 | "time" 7 | ) 8 | 9 | type Message struct { 10 | ID string `json:"id"` 11 | Text string `json:"text"` 12 | CreatedBy string `json:"createdBy"` 13 | CreatedAt time.Time `json:"createdAt"` 14 | } 15 | -------------------------------------------------------------------------------- /pkg/testing/subscriptiontesting/schema.graphql: -------------------------------------------------------------------------------- 1 | type Chatroom { 2 | name: String! 3 | messages: [Message!]! 4 | } 5 | 6 | type Message { 7 | id: ID! 8 | text: String! 9 | createdBy: String! 10 | createdAt: Time! 11 | } 12 | 13 | type Query { 14 | room(name:String!): Chatroom 15 | } 16 | 17 | type Mutation { 18 | post(text: String!, username: String!, roomName: String!): Message! 19 | } 20 | 21 | type Subscription { 22 | messageAdded(roomName: String!): Message! 23 | } 24 | 25 | scalar Time 26 | 27 | directive @user(username: String!) on SUBSCRIPTION 28 | -------------------------------------------------------------------------------- /v2/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/graphql-go-tools/a8e1ade2da8ecd5b85065c3e8c9364057d6b173c/v2/assets/logo.png -------------------------------------------------------------------------------- /v2/examples/chat/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /v2/examples/chat/.gqlgen.yml: -------------------------------------------------------------------------------- 1 | models: 2 | Chatroom: 3 | model: github.com/TykTechnologies/graphql-go-tools/v2/examples/chat.Chatroom 4 | -------------------------------------------------------------------------------- /v2/examples/chat/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/TykTechnologies/graphql-go-tools/v2/examples/chat 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/99designs/gqlgen v0.13.0 7 | github.com/gorilla/websocket v1.4.2 8 | github.com/rs/cors v1.7.0 9 | github.com/stretchr/testify v1.7.0 10 | github.com/vektah/gqlparser/v2 v2.2.0 11 | ) 12 | 13 | require ( 14 | github.com/agnivade/levenshtein v1.0.3 // indirect 15 | github.com/davecgh/go-spew v1.1.1 // indirect 16 | github.com/hashicorp/golang-lru v0.5.0 // indirect 17 | github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 // indirect 18 | github.com/pmezard/go-difflib v1.0.0 // indirect 19 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /v2/examples/chat/handler.go: -------------------------------------------------------------------------------- 1 | package chat 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "github.com/99designs/gqlgen/graphql/handler" 8 | "github.com/99designs/gqlgen/graphql/handler/extension" 9 | "github.com/99designs/gqlgen/graphql/handler/transport" 10 | "github.com/gorilla/websocket" 11 | ) 12 | 13 | func GraphQLEndpointHandler() http.Handler { 14 | srv := handler.New(NewExecutableSchema(New())) 15 | 16 | srv.AddTransport(transport.POST{}) 17 | srv.AddTransport(transport.Websocket{ 18 | KeepAlivePingInterval: 10 * time.Second, 19 | Upgrader: websocket.Upgrader{ 20 | CheckOrigin: func(r *http.Request) bool { 21 | return true 22 | }, 23 | }, 24 | }) 25 | srv.Use(extension.Introspection{}) 26 | 27 | return srv 28 | } 29 | -------------------------------------------------------------------------------- /v2/examples/chat/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package chat 4 | 5 | import ( 6 | "time" 7 | ) 8 | 9 | type Message struct { 10 | ID string `json:"id"` 11 | Text string `json:"text"` 12 | CreatedBy string `json:"createdBy"` 13 | CreatedAt time.Time `json:"createdAt"` 14 | } 15 | -------------------------------------------------------------------------------- /v2/examples/chat/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React App 8 | 9 | 10 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /v2/examples/chat/readme.md: -------------------------------------------------------------------------------- 1 | # Chat Demo 2 | 3 | ## Getting started 4 | 1. Install go modules & npm dependencies 5 | ```shell 6 | go mod download 7 | npm i 8 | ``` 9 | 2. Start server and start react client 10 | ``` 11 | chmod +x start-server.sh 12 | ./start-server.sh 13 | npm run start 14 | ``` 15 | 16 | Example is forked from: [gqlgen](https://github.com/99designs/gqlgen/tree/master/example/chat) 17 | 18 | ## Example(s) 19 | ```graphql 20 | mutation SendMessage { 21 | post(roomName: "#test", username: "me", text: "hello!") { 22 | ...MessageData 23 | } 24 | } 25 | 26 | query GetMessages { 27 | room(name:"#test") { 28 | name 29 | messages { 30 | ...MessageData 31 | } 32 | } 33 | } 34 | 35 | subscription LiveMessages { 36 | messageAdded(roomName: "#test") { 37 | ...MessageData 38 | } 39 | } 40 | 41 | fragment MessageData on Message{ 42 | id 43 | text 44 | createdBy 45 | createdAt 46 | } 47 | ``` -------------------------------------------------------------------------------- /v2/examples/chat/schema.graphql: -------------------------------------------------------------------------------- 1 | type Chatroom { 2 | name: String! 3 | messages: [Message!]! 4 | } 5 | 6 | type Message { 7 | id: ID! 8 | text: String! 9 | createdBy: String! 10 | createdAt: Time! 11 | } 12 | 13 | type Query { 14 | room(name:String!): Chatroom 15 | } 16 | 17 | type Mutation { 18 | post(text: String!, username: String!, roomName: String!): Message! 19 | } 20 | 21 | type Subscription { 22 | messageAdded(roomName: String!): Message! 23 | } 24 | 25 | scalar Time 26 | 27 | directive @user(username: String!) on SUBSCRIPTION 28 | -------------------------------------------------------------------------------- /v2/examples/chat/server/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/99designs/gqlgen/graphql/playground" 8 | "github.com/rs/cors" 9 | 10 | "github.com/TykTechnologies/graphql-go-tools/v2/examples/chat" 11 | ) 12 | 13 | func main() { 14 | c := cors.New(cors.Options{ 15 | AllowedOrigins: []string{"http://localhost:3080", "http://localhost:3000"}, 16 | AllowCredentials: true, 17 | }) 18 | 19 | http.Handle("/", playground.Handler("Chat", "/query")) 20 | http.Handle("/query", c.Handler(chat.GraphQLEndpointHandler())) 21 | 22 | log.Println("Playground running on: http://localhost:8085") 23 | log.Println("Send operations to: http://localhost:8085/query") 24 | log.Fatal(http.ListenAndServe(":8085", nil)) 25 | } 26 | -------------------------------------------------------------------------------- /v2/examples/chat/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import styled from 'styled-components'; 3 | import { Room } from './Room'; 4 | 5 | const Input = styled.div` 6 | padding: 4px; 7 | margin: 0 0 4px; 8 | 9 | input { 10 | border: 1px solid #ccc; 11 | padding: 2px; 12 | font-size: 14px; 13 | } 14 | `; 15 | 16 | export const App = () => { 17 | const [name, setName] = useState('tester'); 18 | const [channel, setChannel] = useState('#gophers'); 19 | 20 | return ( 21 | <> 22 | 23 | name: setName(e.target.value)} /> 24 | 25 | 26 | channel: setChannel(e.target.value)} /> 27 | 28 | 29 | 30 | 31 | ); 32 | 33 | }; 34 | -------------------------------------------------------------------------------- /v2/examples/chat/start-server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | go build -o /tmp/srv-chat ./server 4 | /tmp/srv-chat 5 | -------------------------------------------------------------------------------- /v2/examples/federation/README.md: -------------------------------------------------------------------------------- 1 | # Federation Demo 2 | 3 | ## Getting started 4 | 1. Install go modules 5 | ```shell 6 | go mod download 7 | ``` 8 | 2. Run start script 9 | ``` 10 | chmod +x start.sh 11 | ./start.sh 12 | ``` -------------------------------------------------------------------------------- /v2/examples/federation/accounts/graph/handler.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/99designs/gqlgen/graphql/handler" 7 | "github.com/99designs/gqlgen/graphql/handler/debug" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/v2/examples/federation/accounts/graph/generated" 10 | ) 11 | 12 | type EndpointOptions struct { 13 | EnableDebug bool 14 | } 15 | 16 | var TestOptions = EndpointOptions{ 17 | EnableDebug: false, 18 | } 19 | 20 | func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { 21 | srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) 22 | if opts.EnableDebug { 23 | srv.Use(&debug.Tracer{}) 24 | } 25 | 26 | return srv 27 | } 28 | -------------------------------------------------------------------------------- /v2/examples/federation/accounts/graph/model/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package model 4 | 5 | type User struct { 6 | ID string `json:"id"` 7 | Username string `json:"username"` 8 | } 9 | 10 | func (User) IsEntity() {} 11 | -------------------------------------------------------------------------------- /v2/examples/federation/accounts/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | type Resolver struct{} 7 | -------------------------------------------------------------------------------- /v2/examples/federation/accounts/graph/schema.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | me: User 3 | } 4 | 5 | type User @key(fields: "id") { 6 | id: ID! 7 | username: String! 8 | } 9 | -------------------------------------------------------------------------------- /v2/examples/federation/accounts/server.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package main 3 | 4 | import ( 5 | "log" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/99designs/gqlgen/graphql/playground" 10 | 11 | "github.com/TykTechnologies/graphql-go-tools/v2/examples/federation/accounts/graph" 12 | ) 13 | 14 | const defaultPort = "4001" 15 | 16 | func main() { 17 | port := os.Getenv("PORT") 18 | if port == "" { 19 | port = defaultPort 20 | } 21 | 22 | http.Handle("/", playground.Handler("GraphQL playground", "/query")) 23 | http.Handle("/query", graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true})) 24 | 25 | log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) 26 | log.Fatal(http.ListenAndServe(":"+port, nil)) 27 | } 28 | -------------------------------------------------------------------------------- /v2/examples/federation/products/graph/model/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package model 4 | 5 | type Product struct { 6 | Upc string `json:"upc"` 7 | Name string `json:"name"` 8 | Price int `json:"price"` 9 | InStock int `json:"inStock"` 10 | } 11 | 12 | func (Product) IsEntity() {} 13 | -------------------------------------------------------------------------------- /v2/examples/federation/products/graph/products.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/v2/examples/federation/products/graph/model" 4 | 5 | var hats = []*model.Product{ 6 | { 7 | Upc: "top-1", 8 | Name: "Trilby", 9 | Price: 11, 10 | InStock: 500, 11 | }, 12 | { 13 | Upc: "top-2", 14 | Name: "Fedora", 15 | Price: 22, 16 | InStock: 1200, 17 | }, 18 | { 19 | Upc: "top-3", 20 | Name: "Boater", 21 | Price: 33, 22 | InStock: 850, 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /v2/examples/federation/products/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | type Resolver struct{} 7 | -------------------------------------------------------------------------------- /v2/examples/federation/products/graph/schema.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | topProducts(first: Int = 5): [Product] 3 | } 4 | 5 | extend type Subscription { 6 | updatedPrice: Product! 7 | updateProductPrice(upc: String!): Product! 8 | stock: [Product!] 9 | } 10 | 11 | type Product @key(fields: "upc") { 12 | upc: String! 13 | name: String! 14 | price: Int! 15 | inStock: Int! 16 | } -------------------------------------------------------------------------------- /v2/examples/federation/products/graph/variables.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | var ( 8 | randomnessEnabled = true 9 | minPrice = 10 10 | maxPrice = 1499 11 | currentPrice = minPrice 12 | updateInterval = time.Second 13 | ) 14 | -------------------------------------------------------------------------------- /v2/examples/federation/products/server.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package main 3 | 4 | import ( 5 | "log" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/99designs/gqlgen/graphql/playground" 10 | 11 | "github.com/TykTechnologies/graphql-go-tools/v2/examples/federation/products/graph" 12 | ) 13 | 14 | const defaultPort = "4002" 15 | 16 | func main() { 17 | port := os.Getenv("PORT") 18 | if port == "" { 19 | port = defaultPort 20 | } 21 | 22 | http.Handle("/", playground.Handler("GraphQL playground", "/query")) 23 | http.Handle("/query", graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true, EnableRandomness: true})) 24 | http.HandleFunc("/websocket_connections", graph.WebsocketConnectionsHandler) 25 | 26 | log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) 27 | log.Fatal(http.ListenAndServe(":"+port, nil)) 28 | } 29 | -------------------------------------------------------------------------------- /v2/examples/federation/reviews/graph/handler.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/99designs/gqlgen/graphql/handler" 7 | "github.com/99designs/gqlgen/graphql/handler/debug" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/v2/examples/federation/reviews/graph/generated" 10 | ) 11 | 12 | type EndpointOptions struct { 13 | EnableDebug bool 14 | } 15 | 16 | var TestOptions = EndpointOptions{ 17 | EnableDebug: false, 18 | } 19 | 20 | func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { 21 | srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) 22 | if opts.EnableDebug { 23 | srv.Use(&debug.Tracer{}) 24 | } 25 | 26 | return srv 27 | } 28 | -------------------------------------------------------------------------------- /v2/examples/federation/reviews/graph/model/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package model 4 | 5 | type Product struct { 6 | Upc string `json:"upc"` 7 | Reviews []*Review `json:"reviews"` 8 | } 9 | 10 | func (Product) IsEntity() {} 11 | 12 | type Review struct { 13 | Body string `json:"body"` 14 | Author *User `json:"author"` 15 | Product *Product `json:"product"` 16 | } 17 | 18 | type User struct { 19 | ID string `json:"id"` 20 | Username string `json:"username"` 21 | Reviews []*Review `json:"reviews"` 22 | } 23 | 24 | func (User) IsEntity() {} 25 | -------------------------------------------------------------------------------- /v2/examples/federation/reviews/graph/resolver.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | // This file will not be regenerated automatically. 4 | // 5 | // It serves as dependency injection for your app, add any dependencies you require here. 6 | 7 | type Resolver struct{} 8 | -------------------------------------------------------------------------------- /v2/examples/federation/reviews/graph/reviews.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/v2/examples/federation/reviews/graph/model" 4 | 5 | var reviews = []*model.Review{ 6 | { 7 | Body: "A highly effective form of birth control.", 8 | Product: &model.Product{Upc: "top-1"}, 9 | Author: &model.User{ID: "1234"}, 10 | }, 11 | { 12 | Body: "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.", 13 | Product: &model.Product{Upc: "top-2"}, 14 | Author: &model.User{ID: "1234"}, 15 | }, 16 | { 17 | Body: "This is the last straw. Hat you will wear. 11/10", 18 | Product: &model.Product{Upc: "top-3"}, 19 | Author: &model.User{ID: "7777"}, 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /v2/examples/federation/reviews/graph/schema.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User! @provides(fields: "username") 4 | product: Product! 5 | } 6 | 7 | extend type User @key(fields: "id") { 8 | id: ID! @external 9 | username: String! @external 10 | reviews: [Review] 11 | } 12 | 13 | extend type Product @key(fields: "upc") { 14 | upc: String! @external 15 | reviews: [Review] 16 | } 17 | -------------------------------------------------------------------------------- /v2/examples/federation/reviews/server.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package main 3 | 4 | import ( 5 | "log" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/99designs/gqlgen/graphql/playground" 10 | 11 | "github.com/TykTechnologies/graphql-go-tools/v2/examples/federation/reviews/graph" 12 | ) 13 | 14 | const defaultPort = "4003" 15 | 16 | func main() { 17 | port := os.Getenv("PORT") 18 | if port == "" { 19 | port = defaultPort 20 | } 21 | 22 | http.Handle("/", playground.Handler("GraphQL playground", "/query")) 23 | http.Handle("/query", graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true})) 24 | 25 | log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) 26 | log.Fatal(http.ListenAndServe(":"+port, nil)) 27 | } 28 | -------------------------------------------------------------------------------- /v2/examples/federation/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function cleanup { 4 | kill "$ACCOUNTS_PID" 5 | kill "$PRODUCTS_PID" 6 | kill "$REVIEWS_PID" 7 | } 8 | trap cleanup EXIT 9 | 10 | go build -o /tmp/srv-accounts ./accounts 11 | go build -o /tmp/srv-products ./products 12 | go build -o /tmp/srv-reviews ./reviews 13 | go build -o /tmp/srv-gateway ./gateway 14 | 15 | /tmp/srv-accounts & 16 | ACCOUNTS_PID=$! 17 | 18 | /tmp/srv-products & 19 | PRODUCTS_PID=$! 20 | 21 | /tmp/srv-reviews & 22 | REVIEWS_PID=$! 23 | 24 | sleep 1 25 | 26 | /tmp/srv-gateway 27 | -------------------------------------------------------------------------------- /v2/examples/federation/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | package tools 5 | 6 | import ( 7 | _ "github.com/99designs/gqlgen" 8 | _ "github.com/99designs/gqlgen/graphql/introspection" 9 | ) 10 | -------------------------------------------------------------------------------- /v2/examples/kafka_pubsub/example_field_configs.json: -------------------------------------------------------------------------------- 1 | { 2 | "type_name": "Query", 3 | "field_name": "topProducts", 4 | "disable_default_mapping": false, 5 | "path": [ 6 | "topProducts" 7 | ] 8 | }, 9 | { 10 | "type_name": "Subscription", 11 | "field_name": "stock", 12 | "disable_default_mapping": false, 13 | "path": [ 14 | "stock" 15 | ] 16 | } 17 | ] 18 | -------------------------------------------------------------------------------- /v2/examples/kafka_pubsub/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/TykTechnologies/graphql-go-tools/v2/examples/kafka_pubsub 2 | 3 | go 1.15 4 | 5 | require github.com/Shopify/sarama v1.29.1 6 | -------------------------------------------------------------------------------- /v2/examples/kafka_pubsub/kafka_jaas.conf: -------------------------------------------------------------------------------- 1 | KafkaServer { 2 | org.apache.kafka.common.security.plain.PlainLoginModule required 3 | username="admin" 4 | password="admin-secret" 5 | user_admin="admin-secret" 6 | user_alice="alice-secret"; 7 | }; 8 | Client{}; -------------------------------------------------------------------------------- /v2/examples/kafka_pubsub/schema.graphql: -------------------------------------------------------------------------------- 1 | type Product { 2 | name: String! 3 | price: Int! 4 | in_stock: Int! 5 | } 6 | 7 | type Query { 8 | topProducts(first: Int): [Product] 9 | } 10 | 11 | type Subscription { 12 | stock(name: String): Product! 13 | } 14 | -------------------------------------------------------------------------------- /v2/examples/kafka_pubsub/transactional_producer/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/TykTechnologies/graphql-go-tools/v2/examples/kafka_pubsub/transactional_producer 2 | 3 | go 1.18 4 | 5 | require github.com/confluentinc/confluent-kafka-go v1.8.2 6 | -------------------------------------------------------------------------------- /v2/examples/kafka_pubsub/transactional_producer/go.sum: -------------------------------------------------------------------------------- 1 | github.com/confluentinc/confluent-kafka-go v1.8.2 h1:PBdbvYpyOdFLehj8j+9ba7FL4c4Moxn79gy9cYKxG5E= 2 | github.com/confluentinc/confluent-kafka-go v1.8.2/go.mod h1:u2zNLny2xq+5rWeTQjFHbDzzNuba4P1vo31r9r4uAdg= 3 | -------------------------------------------------------------------------------- /v2/internal/pkg/gocompat/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/graphql-go-tools/a8e1ade2da8ecd5b85065c3e8c9364057d6b173c/v2/internal/pkg/gocompat/.gitkeep -------------------------------------------------------------------------------- /v2/internal/pkg/quotes/quotes.go: -------------------------------------------------------------------------------- 1 | package quotes 2 | 3 | const ( 4 | quoteByte = '"' 5 | quoteStr = string(quoteByte) 6 | ) 7 | 8 | // WrapBytes returns a new slice wrapping the given s 9 | // in quotes (") by making a copy. 10 | func WrapBytes(s []byte) []byte { 11 | cp := make([]byte, len(s)+2) 12 | cp[0] = quoteByte 13 | copy(cp[1:], s) 14 | cp[len(s)+1] = quoteByte 15 | return cp 16 | } 17 | 18 | func WrapString(str string) string { 19 | return quoteStr + str + quoteStr 20 | } 21 | -------------------------------------------------------------------------------- /v2/internal/pkg/quotes/quotes_test.go: -------------------------------------------------------------------------------- 1 | package quotes 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestWrapBytes(t *testing.T) { 10 | testCases := []struct { 11 | s []byte 12 | want []byte 13 | }{ 14 | {nil, []byte(`""`)}, 15 | {[]byte("foo"), []byte(`"foo"`)}, 16 | } 17 | for _, tc := range testCases { 18 | tc := tc 19 | t.Run(string(tc.s), func(t *testing.T) { 20 | r := WrapBytes(tc.s) 21 | assert.Equal(t, tc.want, r) 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /v2/internal/pkg/unsafeprinter/unsafeprinter.go: -------------------------------------------------------------------------------- 1 | package unsafeprinter 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/v2/internal/pkg/unsafeparser" 5 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/ast" 6 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/astprinter" 7 | ) 8 | 9 | func Print(document, definition *ast.Document) string { 10 | str, err := astprinter.PrintString(document, definition) 11 | if err != nil { 12 | panic(err) 13 | } 14 | return str 15 | } 16 | 17 | func PrettyPrint(document, definition *ast.Document) string { 18 | str, err := astprinter.PrintStringIndent(document, definition, " ") 19 | if err != nil { 20 | panic(err) 21 | } 22 | return str 23 | } 24 | 25 | func Prettify(document string) string { 26 | doc := unsafeparser.ParseGraphqlDocumentString(document) 27 | return PrettyPrint(&doc, nil) 28 | } 29 | -------------------------------------------------------------------------------- /v2/pkg/ast/ast_node_kind_test.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestNodeKindIsAbstractType(t *testing.T) { 10 | t.Run("Interface type returns true", func(t *testing.T) { 11 | assert.Equal(t, NodeKindInterfaceTypeDefinition.IsAbstractType(), true) 12 | }) 13 | 14 | t.Run("Union type returns true", func(t *testing.T) { 15 | assert.Equal(t, NodeKindUnionTypeDefinition.IsAbstractType(), true) 16 | }) 17 | 18 | t.Run("Enum type returns false", func(t *testing.T) { 19 | assert.Equal(t, NodeKindEnumTypeDefinition.IsAbstractType(), false) 20 | }) 21 | 22 | t.Run("Interface type returns false", func(t *testing.T) { 23 | assert.Equal(t, NodeKindObjectTypeDefinition.IsAbstractType(), false) 24 | }) 25 | 26 | t.Run("Scalar type returns false", func(t *testing.T) { 27 | assert.Equal(t, NodeKindScalarTypeDefinition.IsAbstractType(), false) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /v2/pkg/ast/ast_schema_extension.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/v2/pkg/lexer/position" 4 | 5 | type SchemaExtension struct { 6 | ExtendLiteral position.Position 7 | SchemaDefinition 8 | } 9 | -------------------------------------------------------------------------------- /v2/pkg/ast/ast_type_test.go: -------------------------------------------------------------------------------- 1 | package ast 2 | -------------------------------------------------------------------------------- /v2/pkg/ast/ast_val_boolean_value.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | // BooleanValues 4 | // one of: true, false 5 | type BooleanValue bool 6 | 7 | func (d *Document) BooleanValue(ref int) BooleanValue { 8 | return d.BooleanValues[ref] 9 | } 10 | 11 | func (d *Document) BooleanValuesAreEqual(left, right int) bool { 12 | return d.BooleanValue(left) == d.BooleanValue(right) 13 | } 14 | -------------------------------------------------------------------------------- /v2/pkg/ast/ast_val_object_value.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/v2/pkg/lexer/position" 4 | 5 | // ObjectValue 6 | // example: 7 | // { lon: 12.43, lat: -53.211 } 8 | type ObjectValue struct { 9 | LBRACE position.Position 10 | Refs []int // ObjectField 11 | RBRACE position.Position 12 | } 13 | 14 | func (d *Document) CopyObjectValue(ref int) int { 15 | refs := d.NewEmptyRefs() 16 | for _, r := range d.ObjectValues[ref].Refs { 17 | refs = append(refs, d.CopyObjectField(r)) 18 | } 19 | return d.AddObjectValue(ObjectValue{ 20 | Refs: refs, 21 | }) 22 | } 23 | 24 | func (d *Document) AddObjectValue(value ObjectValue) (ref int) { 25 | d.ObjectValues = append(d.ObjectValues, value) 26 | return len(d.ObjectValues) - 1 27 | } 28 | 29 | func (d *Document) ImportObjectValue(fieldRefs []int) (ref int) { 30 | return d.AddObjectValue(ObjectValue{ 31 | Refs: fieldRefs, 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /v2/pkg/ast/helpers.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | // indexOf - simple helper to find an index of a ref within refs slice 4 | func indexOf(refs []int, ref int) (int, bool) { 5 | for i, j := range refs { 6 | if ref == j { 7 | return i, true 8 | } 9 | } 10 | return -1, false 11 | } 12 | 13 | // deleteRef - is a slice trick to remove an item with preserving items order 14 | // Note: danger modifies pointer to the arr 15 | func deleteRef(refs *[]int, index int) { 16 | *refs = append((*refs)[:index], (*refs)[index+1:]...) 17 | } 18 | -------------------------------------------------------------------------------- /v2/pkg/astnormalization/fragment_definition_removal.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/ast" 5 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/astvisitor" 6 | ) 7 | 8 | type FragmentDefinitionRemoval struct { 9 | } 10 | 11 | func removeFragmentDefinitions(walker *astvisitor.Walker) { 12 | visitor := removeFragmentDefinitionsVisitor{} 13 | walker.RegisterLeaveDocumentVisitor(visitor) 14 | } 15 | 16 | type removeFragmentDefinitionsVisitor struct { 17 | } 18 | 19 | func (r removeFragmentDefinitionsVisitor) LeaveDocument(operation, definition *ast.Document) { 20 | for i := range operation.RootNodes { 21 | if operation.RootNodes[i].Kind == ast.NodeKindFragmentDefinition { 22 | operation.RootNodes[i].Kind = ast.NodeKindUnknown 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /v2/pkg/astnormalization/remove_self_aliasing.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/ast" 7 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/astvisitor" 8 | ) 9 | 10 | func removeSelfAliasing(walker *astvisitor.Walker) { 11 | visitor := removeSelfAliasingVisitor{} 12 | walker.RegisterEnterDocumentVisitor(&visitor) 13 | walker.RegisterEnterFieldVisitor(&visitor) 14 | } 15 | 16 | type removeSelfAliasingVisitor struct { 17 | operation *ast.Document 18 | } 19 | 20 | func (r *removeSelfAliasingVisitor) EnterDocument(operation, definition *ast.Document) { 21 | r.operation = operation 22 | } 23 | 24 | func (r *removeSelfAliasingVisitor) EnterField(ref int) { 25 | if !r.operation.Fields[ref].Alias.IsDefined { 26 | return 27 | } 28 | if !bytes.Equal(r.operation.FieldNameBytes(ref), r.operation.FieldAliasBytes(ref)) { 29 | return 30 | } 31 | r.operation.RemoveFieldAlias(ref) 32 | } 33 | -------------------------------------------------------------------------------- /v2/pkg/astnormalization/remove_self_aliasing_test.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import "testing" 4 | 5 | func TestRemoveSelfAliasing(t *testing.T) { 6 | t.Run("simple", func(t *testing.T) { 7 | run(t, removeSelfAliasing, testDefinition, ` 8 | {dog: dog}`, 9 | ` 10 | {dog}`) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /v2/pkg/astnormalization/remove_type_extensions.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/astvisitor" 5 | 6 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/ast" 7 | ) 8 | 9 | func removeMergedTypeExtensions(walker *astvisitor.Walker) { 10 | visitor := removeMergedTypeExtensionsVisitor{ 11 | Walker: walker, 12 | } 13 | walker.RegisterLeaveDocumentVisitor(&visitor) 14 | } 15 | 16 | type removeMergedTypeExtensionsVisitor struct { 17 | *astvisitor.Walker 18 | } 19 | 20 | func (r *removeMergedTypeExtensionsVisitor) LeaveDocument(operation, definition *ast.Document) { 21 | operation.RemoveMergedTypeExtensions() 22 | } 23 | -------------------------------------------------------------------------------- /v2/pkg/astnormalization/variables_unused_deletion_test.go: -------------------------------------------------------------------------------- 1 | package astnormalization 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestUnusedVariableDeletion(t *testing.T) { 8 | t.Run("delete unused variables", func(t *testing.T) { 9 | runWithDeleteUnusedVariables(t, deleteUnusedVariables, variablesExtractionDefinition, ` 10 | mutation HttpBinPost($a: HttpBinPostInput $b: String){ 11 | httpBinPost(input: $a){ 12 | headers { 13 | userAgent 14 | } 15 | data { 16 | foo 17 | } 18 | } 19 | }`, "HttpBinPost", ` 20 | mutation HttpBinPost($a: HttpBinPostInput){ 21 | httpBinPost(input: $a){ 22 | headers { 23 | userAgent 24 | } 25 | data { 26 | foo 27 | } 28 | } 29 | }`, `{"a":{"foo":"bar"},"b":"bat"}`, `{"a":{"foo":"bar"}}`) 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /v2/pkg/astvalidation/definition_validation_test.go: -------------------------------------------------------------------------------- 1 | package astvalidation 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/require" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/astparser" 10 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/asttransform" 11 | ) 12 | 13 | func runDefinitionValidation(t *testing.T, definitionInput string, expectation ValidationState, rules ...Rule) { 14 | definition, report := astparser.ParseGraphqlDocumentString(definitionInput) 15 | require.False(t, report.HasErrors()) 16 | 17 | err := asttransform.MergeDefinitionWithBaseSchema(&definition) 18 | require.NoError(t, err) 19 | 20 | validator := &DefinitionValidator{} 21 | for _, rule := range rules { 22 | validator.RegisterRule(rule) 23 | } 24 | 25 | result := validator.Validate(&definition, &report) 26 | assert.Equal(t, expectation, result) 27 | } 28 | -------------------------------------------------------------------------------- /v2/pkg/astvalidation/reference/.gitignore: -------------------------------------------------------------------------------- 1 | __tests__ -------------------------------------------------------------------------------- /v2/pkg/astvalidation/reference/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd testsgo 4 | rm -f *Rule_test.go 5 | cd .. 6 | 7 | go run main.go 8 | gofmt -w testsgo 9 | -------------------------------------------------------------------------------- /v2/pkg/astvalidation/rule.go: -------------------------------------------------------------------------------- 1 | package astvalidation 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/astvisitor" 5 | ) 6 | 7 | var reservedFieldPrefix = []byte("__") 8 | 9 | // Rule is hook to register callback functions on the Walker 10 | type Rule func(walker *astvisitor.Walker) 11 | -------------------------------------------------------------------------------- /v2/pkg/astvalidation/rule_unique_union_member_types_test.go: -------------------------------------------------------------------------------- 1 | package astvalidation 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestUniqueMemberTypes(t *testing.T) { 8 | t.Run("Definition", func(t *testing.T) { 9 | t.Run("Union with a single member is valid", func(t *testing.T) { 10 | runDefinitionValidation(t, ` 11 | union Foo = Bar 12 | `, Valid, UniqueUnionMemberTypes(), 13 | ) 14 | }) 15 | 16 | t.Run("Union with many members is valid", func(t *testing.T) { 17 | runDefinitionValidation(t, ` 18 | union Foo = Bar | FooBar | BarFoo 19 | `, Valid, UniqueUnionMemberTypes(), 20 | ) 21 | }) 22 | 23 | t.Run("Union with duplicate members is invalid", func(t *testing.T) { 24 | runDefinitionValidation(t, ` 25 | union Foo = Bar | Bar 26 | `, Invalid, UniqueUnionMemberTypes(), 27 | ) 28 | }) 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /v2/pkg/astvalidation/validation_state.go: -------------------------------------------------------------------------------- 1 | //go:generate stringer -type=ValidationState -output validation_state_string.go 2 | 3 | package astvalidation 4 | 5 | // ValidationState is the outcome of a validation 6 | type ValidationState int 7 | 8 | const ( 9 | UnknownState ValidationState = iota 10 | Valid 11 | Invalid 12 | ) 13 | -------------------------------------------------------------------------------- /v2/pkg/astvalidation/validation_state_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=ValidationState -output validation_state_string.go"; DO NOT EDIT. 2 | 3 | package astvalidation 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[UnknownState-0] 12 | _ = x[Valid-1] 13 | _ = x[Invalid-2] 14 | } 15 | 16 | const _ValidationState_name = "UnknownStateValidInvalid" 17 | 18 | var _ValidationState_index = [...]uint8{0, 12, 17, 24} 19 | 20 | func (i ValidationState) String() string { 21 | if i < 0 || i >= ValidationState(len(_ValidationState_index)-1) { 22 | return "ValidationState(" + strconv.FormatInt(int64(i), 10) + ")" 23 | } 24 | return _ValidationState_name[_ValidationState_index[i]:_ValidationState_index[i+1]] 25 | } 26 | -------------------------------------------------------------------------------- /v2/pkg/astvisitor/astvisitor.go: -------------------------------------------------------------------------------- 1 | // Package astvisitor enables efficient and powerful traversal of GraphQL document AST's. 2 | // 3 | // Visitor has more options to configure the behaviour and offers more meta data than SimpleVisitor. 4 | // SimpleVisitor on the other hand is more performant. 5 | // 6 | // If all Nodes should be visited and not much meta data is needed, go with SimpleVisitor. 7 | // If you only need to visit a subset of Nodes or want specific meta data, e.g. TypeDefinitions you should go with Visitor. 8 | package astvisitor 9 | -------------------------------------------------------------------------------- /v2/pkg/astvisitor/fixtures/path.golden: -------------------------------------------------------------------------------- 1 | EnterField: posts, path: [query] 2 | EnterField: id, path: [query,posts] 3 | EnterField: description, path: [query,posts] 4 | EnterField: user, path: [query,posts] 5 | EnterField: id, path: [query,posts,user] 6 | EnterField: name, path: [query,posts,user] 7 | EnterField: posts, path: [query] 8 | EnterField: id, path: [query,posts] 9 | EnterField: description, path: [query,posts] 10 | EnterField: user, path: [query,posts] 11 | EnterField: id, path: [query,posts,user] 12 | EnterField: name, path: [query,posts,user] 13 | EnterField: posts, path: [query,posts,user] 14 | EnterField: id, path: [query,posts,user,posts] 15 | -------------------------------------------------------------------------------- /v2/pkg/astvisitor/fixtures/visitor_skip.golden: -------------------------------------------------------------------------------- 1 | EnterOperationDefinition (PostsUserQuery): ref: 0 2 | EnterSelectionSet(Query): ref: 2 3 | EnterField(posts::Query): ref: 5 4 | EnterSelectionSet(Post): ref: 1 5 | EnterField(id::Post): ref: 0 6 | LeaveField(id::Post): ref: 0 7 | EnterField(description::Post): ref: 1 8 | LeaveField(description::Post): ref: 1 9 | LeaveSelectionSet(Post): ref: 1 10 | LeaveField(posts::Query): ref: 5 11 | LeaveSelectionSet(Query): ref: 2 12 | LeaveOperationDefinition(PostsUserQuery): ref: 0 13 | 14 | -------------------------------------------------------------------------------- /v2/pkg/astvisitor/simplevisitor_test.go: -------------------------------------------------------------------------------- 1 | package astvisitor_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/TykTechnologies/graphql-go-tools/v2/internal/pkg/unsafeparser" 7 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/astvisitor" 8 | ) 9 | 10 | func BenchmarkSimpleVisitor(b *testing.B) { 11 | 12 | definition := unsafeparser.ParseGraphqlDocumentString(testDefinition) 13 | operation := unsafeparser.ParseGraphqlDocumentString(testOperation) 14 | 15 | visitor := &dummyVisitor{} 16 | 17 | walker := astvisitor.NewSimpleWalker(48) 18 | walker.SetVisitor(visitor) 19 | 20 | b.ResetTimer() 21 | b.ReportAllocs() 22 | 23 | for i := 0; i < b.N; i++ { 24 | must(walker.Walk(&operation, &definition)) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /v2/pkg/engine/datasource/introspection_datasource/factory.go: -------------------------------------------------------------------------------- 1 | package introspection_datasource 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/engine/plan" 7 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/introspection" 8 | ) 9 | 10 | type Factory struct { 11 | introspectionData *introspection.Data 12 | } 13 | 14 | func NewFactory(introspectionData *introspection.Data) *Factory { 15 | return &Factory{introspectionData: introspectionData} 16 | } 17 | 18 | func (f *Factory) Planner(_ context.Context) plan.DataSourcePlanner { 19 | return &Planner{introspectionData: f.introspectionData} 20 | } 21 | -------------------------------------------------------------------------------- /v2/pkg/engine/datasource/introspection_datasource/fixtures/enum_values_with_deprecated.golden: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "NEWHOPE", 4 | "description": "", 5 | "isDeprecated": false, 6 | "deprecationReason": null 7 | }, 8 | { 9 | "name": "EMPIRE", 10 | "description": "", 11 | "isDeprecated": false, 12 | "deprecationReason": null 13 | }, 14 | { 15 | "name": "JEDI", 16 | "description": "", 17 | "isDeprecated": true, 18 | "deprecationReason": "No longer supported" 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /v2/pkg/engine/datasource/introspection_datasource/fixtures/enum_values_without_deprecated.golden: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "NEWHOPE", 4 | "description": "", 5 | "isDeprecated": false, 6 | "deprecationReason": null 7 | }, 8 | { 9 | "name": "EMPIRE", 10 | "description": "", 11 | "isDeprecated": false, 12 | "deprecationReason": null 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /v2/pkg/engine/datasource/introspection_datasource/fixtures/fields_without_deprecated.golden: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "droid", 4 | "description": "", 5 | "args": [ 6 | { 7 | "name": "id", 8 | "description": "", 9 | "type": { 10 | "kind": "NON_NULL", 11 | "name": null, 12 | "ofType": { 13 | "kind": "SCALAR", 14 | "name": "ID", 15 | "ofType": null 16 | } 17 | }, 18 | "defaultValue": null 19 | } 20 | ], 21 | "type": { 22 | "kind": "OBJECT", 23 | "name": "Droid", 24 | "ofType": null 25 | }, 26 | "isDeprecated": false, 27 | "deprecationReason": null 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /v2/pkg/engine/datasource/introspection_datasource/fixtures/not_existing_type.golden: -------------------------------------------------------------------------------- 1 | null -------------------------------------------------------------------------------- /v2/pkg/engine/datasource/introspection_datasource/fixtures/type_introspection.golden: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "OBJECT", 3 | "name": "Query", 4 | "description": "", 5 | "inputFields": [], 6 | "interfaces": [], 7 | "possibleTypes": [] 8 | } 9 | -------------------------------------------------------------------------------- /v2/pkg/engine/plan/type_field.go: -------------------------------------------------------------------------------- 1 | package plan 2 | 3 | type TypeField struct { 4 | TypeName string 5 | FieldNames []string 6 | } 7 | 8 | type TypeFields []TypeField 9 | 10 | func (f TypeFields) HasNode(typeName, fieldName string) bool { 11 | for i := range f { 12 | if typeName != f[i].TypeName { 13 | continue 14 | } 15 | for j := range f[i].FieldNames { 16 | if fieldName == f[i].FieldNames[j] { 17 | return true 18 | } 19 | } 20 | } 21 | return false 22 | } 23 | 24 | func (f TypeFields) HasNodeWithTypename(typeName string) bool { 25 | for i := range f { 26 | if typeName != f[i].TypeName { 27 | continue 28 | } 29 | return true 30 | } 31 | return false 32 | } 33 | -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/datasource.go: -------------------------------------------------------------------------------- 1 | package resolve 2 | 3 | import ( 4 | "context" 5 | "io" 6 | 7 | "github.com/cespare/xxhash/v2" 8 | ) 9 | 10 | type DataSource interface { 11 | Load(ctx context.Context, input []byte, w io.Writer) (err error) 12 | } 13 | 14 | type SubscriptionDataSource interface { 15 | Start(ctx *Context, input []byte, updater SubscriptionUpdater) error 16 | UniqueRequestID(ctx *Context, input []byte, xxh *xxhash.Digest) (err error) 17 | } 18 | -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/node.go: -------------------------------------------------------------------------------- 1 | package resolve 2 | 3 | const ( 4 | NodeKindObject NodeKind = iota + 1 5 | NodeKindEmptyObject 6 | NodeKindArray 7 | NodeKindEmptyArray 8 | NodeKindNull 9 | NodeKindString 10 | NodeKindBoolean 11 | NodeKindInteger 12 | NodeKindFloat 13 | NodeKindBigInt 14 | NodeKindCustom 15 | NodeKindScalar 16 | NodeKindStaticString 17 | ) 18 | 19 | type Node interface { 20 | NodeKind() NodeKind 21 | NodePath() []string 22 | NodeNullable() bool 23 | } 24 | 25 | type NodeKind int 26 | -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/node_custom.go: -------------------------------------------------------------------------------- 1 | package resolve 2 | 3 | type CustomResolve interface { 4 | Resolve(value []byte) ([]byte, error) 5 | } 6 | 7 | type CustomNode struct { 8 | CustomResolve 9 | Nullable bool 10 | Path []string 11 | } 12 | 13 | func (_ *CustomNode) NodeKind() NodeKind { 14 | return NodeKindCustom 15 | } 16 | 17 | func (c *CustomNode) NodePath() []string { 18 | return c.Path 19 | } 20 | 21 | func (c *CustomNode) NodeNullable() bool { 22 | return c.Nullable 23 | } 24 | -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/defer_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "users": [ 4 | { 5 | "id": 1, 6 | "name": "Leanne Graham", 7 | "posts": null 8 | }, 9 | { 10 | "id": 2, 11 | "name": "Ervin Howell", 12 | "posts": null 13 | } 14 | ] 15 | } 16 | } -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/defer_2.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "replace", 4 | "path": "/data/users/0/posts", 5 | "value": [ 6 | { 7 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 8 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 9 | }, 10 | { 11 | "title": "qui est esse", 12 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 13 | } 14 | ] 15 | } 16 | ] -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/defer_3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "replace", 4 | "path": "/data/users/1/posts", 5 | "value": [ 6 | { 7 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 8 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 9 | }, 10 | { 11 | "title": "qui est esse", 12 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 13 | } 14 | ] 15 | } 16 | ] -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/posts.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "userId": 1, 4 | "id": 1, 5 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 6 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 7 | }, 8 | { 9 | "userId": 1, 10 | "id": 2, 11 | "title": "qui est esse", 12 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 13 | } 14 | ] -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/stream_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "users": [] 4 | } 5 | } -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/stream_2.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "add", 4 | "path": "/data/users/0", 5 | "value": { 6 | "id": 1, 7 | "name": "Leanne Graham" 8 | } 9 | } 10 | ] -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/stream_3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "add", 4 | "path": "/data/users/1", 5 | "value": { 6 | "id": 2, 7 | "name": "Ervin Howell" 8 | } 9 | } 10 | ] -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/stream_4.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "users": [ 4 | { 5 | "id": 1, 6 | "name": "Leanne Graham" 7 | } 8 | ] 9 | } 10 | } -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/stream_5.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "users": [ 4 | { 5 | "id": 1, 6 | "name": "Leanne Graham" 7 | }, 8 | { 9 | "id": 2, 10 | "name": "Ervin Howell" 11 | } 12 | ] 13 | } 14 | } -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/stream_6.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "add", 4 | "path": "/data/users/0", 5 | "value": { 6 | "id": 1, 7 | "name": "Leanne Graham", 8 | "posts": null 9 | } 10 | } 11 | ] -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/stream_7.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "add", 4 | "path": "/data/users/1", 5 | "value": { 6 | "id": 2, 7 | "name": "Ervin Howell", 8 | "posts": null 9 | } 10 | } 11 | ] -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/stream_8.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "replace", 4 | "path": "/data/users/0/posts", 5 | "value": [ 6 | { 7 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 8 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 9 | }, 10 | { 11 | "title": "qui est esse", 12 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 13 | } 14 | ] 15 | } 16 | ] -------------------------------------------------------------------------------- /v2/pkg/engine/resolve/testdata/stream_9.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "op": "replace", 4 | "path": "/data/users/1/posts", 5 | "value": [ 6 | { 7 | "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", 8 | "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" 9 | }, 10 | { 11 | "title": "qui est esse", 12 | "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" 13 | } 14 | ] 15 | } 16 | ] -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/const.go: -------------------------------------------------------------------------------- 1 | package sdlmerge 2 | 3 | const ( 4 | KeyDirectiveName = "key" 5 | RequireDirectiveName = "requires" 6 | ProvidesDirectiveName = "provides" 7 | ExternalDirectiveName = "external" 8 | ) 9 | -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/remove_empty_object_type_definition_test.go: -------------------------------------------------------------------------------- 1 | package sdlmerge 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestRemoveEmptyObjectTypeDefinitionDirective(t *testing.T) { 8 | t.Run("remove object definition without fields", func(t *testing.T) { 9 | run(t, newRemoveEmptyObjectTypeDefinition(), ` 10 | type Query { 11 | } 12 | type Cat { 13 | name: String! 14 | } 15 | `, ` 16 | type Cat { 17 | name: String! 18 | } 19 | `) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/remove_field_definition_by_directive_test.go: -------------------------------------------------------------------------------- 1 | package sdlmerge 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestRemoveFieldDirective(t *testing.T) { 8 | t.Run("remove field with specified directive", func(t *testing.T) { 9 | run( 10 | t, newRemoveFieldDefinitions("forDelete"), 11 | ` 12 | type Dog { 13 | name: String @notForDelete 14 | favoriteToy: String @forDelete 15 | barkVolume: Int 16 | isHousetrained(atOtherHomes: Boolean): Boolean! @forDelete 17 | doesKnowCommand(dogCommand: DogCommand!): Boolean! 18 | } 19 | `, 20 | ` 21 | type Dog { 22 | name: String @notForDelete 23 | barkVolume: Int 24 | doesKnowCommand(dogCommand: DogCommand!): Boolean! 25 | } 26 | `) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/remove_field_definition_directive_test.go: -------------------------------------------------------------------------------- 1 | package sdlmerge 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestRemoveFieldDefinitionDirective(t *testing.T) { 8 | t.Run("remove specified directive from field definition", func(t *testing.T) { 9 | run( 10 | t, 11 | newRemoveFieldDefinitionDirective("requires", "provides"), 12 | ` 13 | type Dog { 14 | name: String! 15 | age: Int! 16 | code: String @requires(fields: "name age") 17 | owner: Owner @provides(fields: "name") 18 | } 19 | `, 20 | ` 21 | type Dog { 22 | name: String! 23 | age: Int! 24 | code: String 25 | owner: Owner 26 | }`, 27 | ) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/remove_type_extensions.go: -------------------------------------------------------------------------------- 1 | package sdlmerge 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/ast" 5 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/astvisitor" 6 | ) 7 | 8 | func newRemoveMergedTypeExtensions() *removeMergedTypeExtensionsVisitor { 9 | return &removeMergedTypeExtensionsVisitor{} 10 | } 11 | 12 | type removeMergedTypeExtensionsVisitor struct { 13 | } 14 | 15 | func (r *removeMergedTypeExtensionsVisitor) Register(walker *astvisitor.Walker) { 16 | walker.RegisterLeaveDocumentVisitor(r) 17 | } 18 | 19 | func (r *removeMergedTypeExtensionsVisitor) LeaveDocument(operation, definition *ast.Document) { 20 | operation.RemoveMergedTypeExtensions() 21 | } 22 | -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition-non-null.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User! @provides(fields: "username") 4 | product: Product! 5 | } 6 | 7 | #type User @key(fields: "id") { 8 | # id: ID! @external 9 | # username: String! @external 10 | # reviews: [Review] 11 | #} 12 | 13 | extend type Product @key(fields: "upc") { 14 | upc: String! @external 15 | reviews: [Review] 16 | } 17 | -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User @provides(fields: "username") 4 | product: Product 5 | } 6 | 7 | #type User @key(fields: "id") { 8 | # id: ID! @external 9 | # username: String! @external 10 | # reviews: [Review] 11 | #} 12 | 13 | extend type Product @key(fields: "upc") { 14 | upc: String! @external 15 | reviews: [Review] 16 | } 17 | -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition-non-null.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User! @provides(fields: "username") 4 | product: Product! 5 | } 6 | 7 | type User @key(fields: "id") { 8 | id: ID! @external 9 | username: String! @external 10 | reviews: [Review] 11 | } 12 | 13 | #extend type Product @key(fields: "upc") { 14 | # @external 15 | # reviews: [Review] } 16 | #} 17 | -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User @provides(fields: "username") 4 | product: Product 5 | } 6 | 7 | type User @key(fields: "id") { 8 | id: ID! @external 9 | username: String! @external 10 | reviews: [Review] 11 | } 12 | 13 | #extend type Product @key(fields: "upc") { 14 | # upc: String! @external 15 | # reviews: [Review] 16 | #} 17 | 18 | -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined-non-null.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User! @provides(fields: "username") 4 | product: Product! 5 | } 6 | 7 | type User @key(fields: "id") { 8 | id: ID! @external 9 | username: String! @external 10 | reviews: [Review] 11 | } 12 | 13 | extend type Product @key(fields: "upc") { 14 | upc: String! @external 15 | reviews: [Review] 16 | } 17 | -------------------------------------------------------------------------------- /v2/pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined.graphqls: -------------------------------------------------------------------------------- 1 | type Review { 2 | body: String! 3 | author: User @provides(fields: "username") 4 | product: Product 5 | } 6 | 7 | type User @key(fields: "id") { 8 | id: ID! @external 9 | username: String! @external 10 | reviews: [Review] 11 | } 12 | 13 | extend type Product @key(fields: "upc") { 14 | upc: String! @external 15 | reviews: [Review] 16 | } 17 | -------------------------------------------------------------------------------- /v2/pkg/graphql/lookup.go: -------------------------------------------------------------------------------- 1 | package graphql 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type TypeFieldLookupKey string 8 | 9 | func CreateTypeFieldLookupKey(typeName string, fieldName string) TypeFieldLookupKey { 10 | return TypeFieldLookupKey(fmt.Sprintf("%s.%s", typeName, fieldName)) 11 | } 12 | 13 | func CreateTypeFieldArgumentsLookupMap(typeFieldArgs []TypeFieldArguments) map[TypeFieldLookupKey]TypeFieldArguments { 14 | if len(typeFieldArgs) == 0 { 15 | return nil 16 | } 17 | 18 | lookupMap := make(map[TypeFieldLookupKey]TypeFieldArguments) 19 | for _, currentTypeFieldArgs := range typeFieldArgs { 20 | lookupMap[CreateTypeFieldLookupKey(currentTypeFieldArgs.TypeName, currentTypeFieldArgs.FieldName)] = currentTypeFieldArgs 21 | } 22 | 23 | return lookupMap 24 | } 25 | -------------------------------------------------------------------------------- /v2/pkg/graphql/response.go: -------------------------------------------------------------------------------- 1 | package graphql 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type Response struct { 8 | Errors Errors `json:"errors,omitempty"` 9 | Data any `json:"data"` // we add this here to ensure that "data":null is added to an error response 10 | } 11 | 12 | func (r Response) Marshal() ([]byte, error) { 13 | return json.Marshal(r) 14 | } 15 | -------------------------------------------------------------------------------- /v2/pkg/graphql/subscription.go: -------------------------------------------------------------------------------- 1 | package graphql 2 | 3 | type SubscriptionType int 4 | 5 | const ( 6 | // SubscriptionTypeUnknown is for unknown or undefined subscriptions. 7 | SubscriptionTypeUnknown = iota 8 | // SubscriptionTypeSSE is for Server-Sent Events (SSE) subscriptions. 9 | SubscriptionTypeSSE 10 | // SubscriptionTypeGraphQLWS is for subscriptions using a WebSocket connection with 11 | // 'graphql-ws' as protocol. 12 | SubscriptionTypeGraphQLWS 13 | // SubscriptionTypeGraphQLTransportWS is for subscriptions using a WebSocket connection with 14 | // 'graphql-transport-ws' as protocol. 15 | SubscriptionTypeGraphQLTransportWS 16 | ) 17 | -------------------------------------------------------------------------------- /v2/pkg/graphql/types.go: -------------------------------------------------------------------------------- 1 | package graphql 2 | 3 | type ( 4 | Type struct { 5 | Name string `json:"name"` 6 | Fields []string `json:"fields"` 7 | } 8 | 9 | RequestFields map[string]struct{} 10 | RequestTypes map[string]RequestFields 11 | ) 12 | -------------------------------------------------------------------------------- /v2/pkg/graphqlerrors/location.go: -------------------------------------------------------------------------------- 1 | package graphqlerrors 2 | 3 | type Location struct { 4 | Line uint32 `json:"line"` 5 | Column uint32 `json:"column"` 6 | } 7 | -------------------------------------------------------------------------------- /v2/pkg/imports/fixtures/render_result.golden: -------------------------------------------------------------------------------- 1 | #file: testdata/schema.graphql 2 | 3 | 4 | schema { 5 | query: Query 6 | mutation: Mutation 7 | } 8 | 9 | 10 | #file: testdata/scalars/json.graphql 11 | 12 | scalar JSON 13 | 14 | 15 | #file: testdata/types/query.graphql 16 | 17 | type Query { 18 | foo: Foo 19 | } 20 | 21 | 22 | #file: testdata/nested/nested.graphql 23 | 24 | 25 | type Bar { 26 | baz: Int 27 | } 28 | 29 | 30 | #file: testdata/nested2/nested2.graphql 31 | 32 | type Bat { 33 | bar: String 34 | } 35 | 36 | 37 | #file: testdata/deep/deeper/custom_types.graphql 38 | 39 | type Foo { 40 | field: String 41 | } 42 | -------------------------------------------------------------------------------- /v2/pkg/imports/fixtures/render_result_windows.golden: -------------------------------------------------------------------------------- 1 | #file: testdata\schema.graphql 2 | 3 | 4 | schema { 5 | query: Query 6 | mutation: Mutation 7 | } 8 | 9 | 10 | #file: testdata\scalars\json.graphql 11 | 12 | scalar JSON 13 | 14 | 15 | #file: testdata\types\query.graphql 16 | 17 | type Query { 18 | foo: Foo 19 | } 20 | 21 | 22 | #file: testdata\nested\nested.graphql 23 | 24 | 25 | type Bar { 26 | baz: Int 27 | } 28 | 29 | 30 | #file: testdata\nested2\nested2.graphql 31 | 32 | type Bat { 33 | bar: String 34 | } 35 | 36 | 37 | #file: testdata\deep\deeper\custom_types.graphql 38 | 39 | type Foo { 40 | field: String 41 | } 42 | -------------------------------------------------------------------------------- /v2/pkg/imports/fixtures/scanner_regex.golden: -------------------------------------------------------------------------------- 1 | { 2 | "RelativePath": "", 3 | "Imports": [ 4 | { 5 | "RelativePath": "testdata/regexonly/flat.graphql", 6 | "Imports": null 7 | }, 8 | { 9 | "RelativePath": "testdata/regexonly/mutation.graphql", 10 | "Imports": null 11 | }, 12 | { 13 | "RelativePath": "testdata/regexonly/query.graphql", 14 | "Imports": null 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /v2/pkg/imports/fixtures/scanner_regex_render.golden: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | mutation: Mutation 4 | } 5 | type Mutation { 6 | bar: String 7 | } 8 | type Query { 9 | foo: String 10 | } 11 | -------------------------------------------------------------------------------- /v2/pkg/imports/fixtures/scanner_regex_windows.golden: -------------------------------------------------------------------------------- 1 | { 2 | "RelativePath": "", 3 | "Imports": [ 4 | { 5 | "RelativePath": "testdata\\regexonly\\flat.graphql", 6 | "Imports": null 7 | }, 8 | { 9 | "RelativePath": "testdata\\regexonly\\mutation.graphql", 10 | "Imports": null 11 | }, 12 | { 13 | "RelativePath": "testdata\\regexonly\\query.graphql", 14 | "Imports": null 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /v2/pkg/imports/fixtures/scanner_result.golden: -------------------------------------------------------------------------------- 1 | { 2 | "RelativePath": "testdata/schema.graphql", 3 | "Imports": [ 4 | { 5 | "RelativePath": "testdata/scalars/json.graphql", 6 | "Imports": null 7 | }, 8 | { 9 | "RelativePath": "testdata/types/query.graphql", 10 | "Imports": null 11 | }, 12 | { 13 | "RelativePath": "testdata/nested/nested.graphql", 14 | "Imports": [ 15 | { 16 | "RelativePath": "testdata/nested2/nested2.graphql", 17 | "Imports": null 18 | } 19 | ] 20 | }, 21 | { 22 | "RelativePath": "testdata/deep/deeper/custom_types.graphql", 23 | "Imports": null 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /v2/pkg/imports/fixtures/scanner_result_windows.golden: -------------------------------------------------------------------------------- 1 | { 2 | "RelativePath": "testdata\\schema.graphql", 3 | "Imports": [ 4 | { 5 | "RelativePath": "testdata\\scalars\\json.graphql", 6 | "Imports": null 7 | }, 8 | { 9 | "RelativePath": "testdata\\types\\query.graphql", 10 | "Imports": null 11 | }, 12 | { 13 | "RelativePath": "testdata\\nested\\nested.graphql", 14 | "Imports": [ 15 | { 16 | "RelativePath": "testdata\\nested2\\nested2.graphql", 17 | "Imports": null 18 | } 19 | ] 20 | }, 21 | { 22 | "RelativePath": "testdata\\deep\\deeper\\custom_types.graphql", 23 | "Imports": null 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /v2/pkg/imports/graphql_file_test.go: -------------------------------------------------------------------------------- 1 | package imports 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | "testing" 7 | 8 | "github.com/jensneuse/diffview" 9 | 10 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/goldie" 11 | ) 12 | 13 | func TestGraphQLFile_Render(t *testing.T) { 14 | scanner := Scanner{} 15 | file, err := scanner.ScanFile("testdata/schema.graphql") 16 | if err != nil { 17 | t.Fatal(err) 18 | } 19 | 20 | out := bytes.Buffer{} 21 | err = file.Render(true, &out) 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | 26 | dump := out.Bytes() 27 | 28 | goldie.Assert(t, "render_result", dump, true) 29 | if t.Failed() { 30 | fixture, err := os.ReadFile("./fixtures/render_result.golden") 31 | if err != nil { 32 | t.Fatal(err) 33 | } 34 | 35 | diffview.NewGoland().DiffViewBytes("render_result", fixture, dump) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/cycle/a/a.graphql: -------------------------------------------------------------------------------- 1 | #import "../b/b.graphql" -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/cycle/b/b.graphql: -------------------------------------------------------------------------------- 1 | #import "../a/a.graphql" -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/deep/deeper/custom_types.graphql: -------------------------------------------------------------------------------- 1 | type Foo { 2 | field: String 3 | } -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/deep/deeper/non_graphql.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/graphql-go-tools/a8e1ade2da8ecd5b85065c3e8c9364057d6b173c/v2/pkg/imports/testdata/deep/deeper/non_graphql.txt -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/import_cycle.graphql: -------------------------------------------------------------------------------- 1 | #import "cycle/a/a.graphql" -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/nested/nested.graphql: -------------------------------------------------------------------------------- 1 | #import "../nested2/nested2.graphql" 2 | 3 | type Bar { 4 | baz: Int 5 | } -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/nested2/nested2.graphql: -------------------------------------------------------------------------------- 1 | type Bat { 2 | bar: String 3 | } -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/regexonly/flat.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | mutation: Mutation 4 | } -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/regexonly/mutation.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | bar: String 3 | } -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/regexonly/query.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | foo: String 3 | } -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/scalars/json.graphql: -------------------------------------------------------------------------------- 1 | scalar JSON -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/schema.graphql: -------------------------------------------------------------------------------- 1 | #import "scalars/*.graphql" 2 | #import "types/query.graphql" 3 | #import "nested/nested.graphql" 4 | #import "deep/**/*.graphql" 5 | 6 | schema { 7 | query: Query 8 | mutation: Mutation 9 | } -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/types/mutation.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | mutateFoo: Foo 3 | } -------------------------------------------------------------------------------- /v2/pkg/imports/testdata/types/query.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | foo: Foo 3 | } -------------------------------------------------------------------------------- /v2/pkg/introspection/introspection_test.go: -------------------------------------------------------------------------------- 1 | package introspection 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | func TestIntrospectionSerialization(t *testing.T) { 10 | inputData, err := os.ReadFile("./testdata/swapi_introspection_response.json") 11 | if err != nil { 12 | panic(err) 13 | } 14 | 15 | var data Data 16 | 17 | err = json.Unmarshal(inputData, &data) 18 | if err != nil { 19 | panic(err) 20 | } 21 | 22 | outputData, err := json.MarshalIndent(data, "", " ") 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | err = os.WriteFile("./testdata/out_swapi_introspection_response.json", outputData, os.ModePerm) 28 | if err != nil { 29 | panic(err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /v2/pkg/introspection/testdata/interfaces_implementing_interfaces.graphql: -------------------------------------------------------------------------------- 1 | interface BaseInterface { 2 | fieldOne: String! 3 | } 4 | 5 | interface SecondInterface implements BaseInterface { 6 | fieldOne: String! 7 | fieldTwo: String! 8 | } 9 | 10 | interface ThirdInterface implements SecondInterface & BaseInterface { 11 | fieldOne: String! 12 | fieldTwo: String! 13 | fieldThree: String! 14 | } 15 | 16 | interface IDType { 17 | id: ID! 18 | } 19 | 20 | interface SoftDelete { 21 | deleted: Boolean! 22 | } 23 | 24 | extend interface SoftDelete implements IDType { 25 | id: ID! 26 | } 27 | 28 | interface Record { 29 | data: String! 30 | } 31 | 32 | extend interface Record implements SoftDelete & IDType { 33 | id: ID! 34 | deleted: Boolean! 35 | } 36 | -------------------------------------------------------------------------------- /v2/pkg/lexer/keyword/keyword.go: -------------------------------------------------------------------------------- 1 | //go:generate stringer -type=Keyword 2 | 3 | // Package keyword contains all possible GraphQL keywords 4 | package keyword 5 | 6 | type Keyword int 7 | 8 | const ( 9 | UNDEFINED Keyword = iota 10 | IDENT 11 | COMMENT 12 | EOF 13 | 14 | COLON 15 | BANG 16 | LT 17 | TAB 18 | SPACE 19 | COMMA 20 | AT 21 | DOT 22 | SPREAD 23 | PIPE 24 | SLASH 25 | EQUALS 26 | SUB 27 | AND 28 | QUOTE 29 | 30 | DOLLAR 31 | STRING 32 | BLOCKSTRING 33 | INTEGER 34 | FLOAT 35 | 36 | LPAREN 37 | RPAREN 38 | LBRACK 39 | RBRACK 40 | LBRACE 41 | RBRACE 42 | ) 43 | -------------------------------------------------------------------------------- /v2/pkg/lexer/runes/runes.go: -------------------------------------------------------------------------------- 1 | // Package runes contains all possible 'special' runes in a GraphQL document 2 | package runes 3 | 4 | const ( 5 | EOF = 0 6 | COLON = ':' 7 | BANG = '!' 8 | CARRIAGERETURN = '\r' 9 | LINETERMINATOR = '\n' 10 | TAB = '\t' 11 | SPACE = ' ' 12 | COMMA = ',' 13 | HASHTAG = '#' 14 | QUOTE = '"' 15 | BACKSLASH = '\\' 16 | DOT = '.' 17 | EXPONENT_LOWER = 'e' 18 | EXPONENT_UPPER = 'E' 19 | AT = '@' 20 | DOLLAR = '$' 21 | PIPE = '|' 22 | SLASH = '/' 23 | EQUALS = '=' 24 | SUB = '-' 25 | ADD = '+' 26 | AND = '&' 27 | UNDERSCORE = '_' 28 | 29 | LPAREN = '(' 30 | RPAREN = ')' 31 | LBRACK = '[' 32 | RBRACK = ']' 33 | LBRACE = '{' 34 | RBRACE = '}' 35 | ) 36 | -------------------------------------------------------------------------------- /v2/pkg/middleware/middleware.go: -------------------------------------------------------------------------------- 1 | // Package middleware contains useful middleware components for GraphQL services, e.g. for complexity analysis. 2 | package middleware 3 | -------------------------------------------------------------------------------- /v2/pkg/playground/files/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/graphql-go-tools/a8e1ade2da8ecd5b85065c3e8c9364057d6b173c/v2/pkg/playground/files/favicon.png -------------------------------------------------------------------------------- /v2/pkg/playground/files/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/graphql-go-tools/a8e1ade2da8ecd5b85065c3e8c9364057d6b173c/v2/pkg/playground/files/logo.png -------------------------------------------------------------------------------- /v2/pkg/playground/files/playground.css: -------------------------------------------------------------------------------- 1 | body{margin:0;padding:0;font-family:sans-serif;overflow:hidden}#root{height:100%}body{font-family:Open Sans,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:rgba(0,0,0,.8);line-height:1.5;height:100vh;letter-spacing:.53px;margin-right:-1px!important}a,body,code,h1,h2,h3,h4,html,p,pre,ul{margin:0;padding:0;color:inherit}a:active,a:focus,button:focus,input:focus{outline:none}button,input,submit{border:none}button,input,pre{font-family:Open Sans,sans-serif}code{font-family:Consolas,monospace} -------------------------------------------------------------------------------- /v2/pkg/playground/fixtures/handlers.golden: -------------------------------------------------------------------------------- 1 | (playground.Handlers) (len=5 cap=5) { 2 | (playground.HandlerConfig) { 3 | Path: (string) (len=11) "/playground", 4 | Handler: (http.HandlerFunc) 5 | }, 6 | (playground.HandlerConfig) { 7 | Path: (string) (len=26) "/playground/playground.css", 8 | Handler: (http.HandlerFunc) 9 | }, 10 | (playground.HandlerConfig) { 11 | Path: (string) (len=25) "/playground/playground.js", 12 | Handler: (http.HandlerFunc) 13 | }, 14 | (playground.HandlerConfig) { 15 | Path: (string) (len=23) "/playground/favicon.png", 16 | Handler: (http.HandlerFunc) 17 | }, 18 | (playground.HandlerConfig) { 19 | Path: (string) (len=20) "/playground/logo.png", 20 | Handler: (http.HandlerFunc) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /v2/pkg/pool/bytesbuffer.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import ( 4 | "bytes" 5 | "sync" 6 | ) 7 | 8 | var ( 9 | BytesBuffer = bytesBufferPool{ 10 | pool: sync.Pool{ 11 | New: func() interface{} { 12 | return bytes.NewBuffer(make([]byte, 0, 1024)) 13 | }, 14 | }, 15 | } 16 | ) 17 | 18 | type bytesBufferPool struct { 19 | pool sync.Pool 20 | } 21 | 22 | func (b *bytesBufferPool) Get() *bytes.Buffer { 23 | return b.pool.Get().(*bytes.Buffer) 24 | } 25 | 26 | func (b *bytesBufferPool) Put(buf *bytes.Buffer) { 27 | buf.Reset() 28 | b.pool.Put(buf) 29 | } 30 | -------------------------------------------------------------------------------- /v2/pkg/pool/fastbuffer.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/fastbuffer" 7 | ) 8 | 9 | var FastBuffer = fastBufferPool{ 10 | pool: sync.Pool{ 11 | New: func() interface{} { 12 | return fastbuffer.New() 13 | }, 14 | }, 15 | } 16 | 17 | type fastBufferPool struct { 18 | pool sync.Pool 19 | } 20 | 21 | func (f *fastBufferPool) Get() *fastbuffer.FastBuffer { 22 | return f.pool.Get().(*fastbuffer.FastBuffer) 23 | } 24 | 25 | func (f *fastBufferPool) Put(buf *fastbuffer.FastBuffer) { 26 | buf.Reset() 27 | f.pool.Put(buf) 28 | } 29 | -------------------------------------------------------------------------------- /v2/pkg/pool/hash64.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/cespare/xxhash/v2" 7 | ) 8 | 9 | var ( 10 | Hash64 = hash64Pool{ 11 | pool: sync.Pool{ 12 | New: func() interface{} { 13 | return xxhash.New() 14 | }, 15 | }, 16 | } 17 | ) 18 | 19 | type hash64Pool struct { 20 | pool sync.Pool 21 | } 22 | 23 | func (b *hash64Pool) Get() *xxhash.Digest { 24 | xxh := b.pool.Get().(*xxhash.Digest) 25 | xxh.Reset() 26 | return xxh 27 | } 28 | 29 | func (b *hash64Pool) Put(xxh *xxhash.Digest) { 30 | b.pool.Put(xxh) 31 | } 32 | -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/mutations/create_review.mutation: -------------------------------------------------------------------------------- 1 | mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { 2 | createReview(episode: $ep, review: $review) { 3 | id 4 | stars 5 | commentary 6 | } 7 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/directives_include.query: -------------------------------------------------------------------------------- 1 | query Hero($withFriends: Boolean!) { 2 | hero { 3 | name 4 | friends @include(if: $withFriends) { 5 | name 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/directives_skip.query: -------------------------------------------------------------------------------- 1 | query Hero($skipFriends: Boolean!) { 2 | hero { 3 | name 4 | friends @skip(if: $skipFriends) { 5 | name 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/droid_with_arg.query: -------------------------------------------------------------------------------- 1 | { 2 | droid(id: "R2D2") { 3 | name 4 | } 5 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/droid_with_arg_and_var.query: -------------------------------------------------------------------------------- 1 | query Droid($droidID: ID!) { 2 | droid(id: $droidID) { 3 | name 4 | } 5 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/fragments.query: -------------------------------------------------------------------------------- 1 | query Fragments($droidID: ID!){ 2 | hero { 3 | ...characterFields 4 | } 5 | droid(id: $droidID) { 6 | ...characterFields 7 | } 8 | } 9 | 10 | fragment characterFields on Character { 11 | name 12 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/hero_with_aliases.query: -------------------------------------------------------------------------------- 1 | { 2 | empireHero: hero { 3 | name 4 | } 5 | jediHero: hero { 6 | name 7 | } 8 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/hero_with_operation_name.query: -------------------------------------------------------------------------------- 1 | query Hero { 2 | hero { 3 | name 4 | } 5 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/inline_fragments.query: -------------------------------------------------------------------------------- 1 | { 2 | hero { 3 | friends { 4 | ...on Droid { 5 | name 6 | primaryFunction 7 | } 8 | ...on Human { 9 | name 10 | height 11 | } 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/interface_fragments_on_union.graphql: -------------------------------------------------------------------------------- 1 | query SearchResults { 2 | searchResults { 3 | ...on Character { 4 | name 5 | } 6 | ...on Vehicle { 7 | length 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/invalid.query: -------------------------------------------------------------------------------- 1 | { 2 | hero { 3 | invalid 4 | } 5 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/invalid_fragments.query: -------------------------------------------------------------------------------- 1 | query Fragments($droidID: ID!){ 2 | droid(id: $droidID) { 3 | ...reviewFields 4 | } 5 | } 6 | 7 | fragment reviewFields on Review { 8 | id 9 | stars 10 | commentary 11 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/multi_queries.query: -------------------------------------------------------------------------------- 1 | query MultiHeroes { 2 | empireHero: hero { 3 | name 4 | } 5 | jediHero: hero { 6 | name 7 | } 8 | } 9 | 10 | query SingleHero { 11 | hero { 12 | name 13 | } 14 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/multi_queries_with_arguments.query: -------------------------------------------------------------------------------- 1 | query GetDroid { 2 | droid(id: "1") { 3 | name 4 | } 5 | } 6 | 7 | query Search { 8 | search(name: "C3PO") { 9 | ...on Droid { 10 | name 11 | primaryFunction 12 | } 13 | ...on Human { 14 | name 15 | height 16 | } 17 | ...on Starship { 18 | name 19 | length 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/simple_hero.query: -------------------------------------------------------------------------------- 1 | { 2 | hero { 3 | name 4 | } 5 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/queries/union.query: -------------------------------------------------------------------------------- 1 | query Search($name: String!) { 2 | search(name: $name) { 3 | ...on Droid { 4 | name 5 | primaryFunction 6 | } 7 | ...on Human { 8 | name 9 | height 10 | } 11 | ...on Starship { 12 | name 13 | length 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /v2/pkg/starwars/testdata/subscriptions/remaining_jedis.subscription: -------------------------------------------------------------------------------- 1 | subscription { 2 | remainingJedis 3 | } -------------------------------------------------------------------------------- /v2/pkg/subscription/constants.go: -------------------------------------------------------------------------------- 1 | package subscription 2 | 3 | const ( 4 | DefaultKeepAliveInterval = "15s" 5 | DefaultSubscriptionUpdateInterval = "1s" 6 | DefaultReadErrorTimeOut = "5s" 7 | DefaultSubscriptionExecutionTries = 5 8 | ) 9 | -------------------------------------------------------------------------------- /v2/pkg/subscription/executor.go: -------------------------------------------------------------------------------- 1 | package subscription 2 | 3 | //go:generate mockgen -destination=executor_mock_test.go -package=subscription . Executor,ExecutorPool 4 | 5 | import ( 6 | "context" 7 | 8 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/ast" 9 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/engine/resolve" 10 | ) 11 | 12 | // Executor is an abstraction for executing a GraphQL engine 13 | type Executor interface { 14 | Execute(writer resolve.SubscriptionResponseWriter) error 15 | OperationType() ast.OperationType 16 | SetContext(context context.Context) 17 | Reset() 18 | } 19 | 20 | // ExecutorPool is an abstraction for creating executors 21 | type ExecutorPool interface { 22 | Get(payload []byte) (Executor, error) 23 | Put(executor Executor) error 24 | } 25 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/accounts/graph/handler.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/99designs/gqlgen/graphql/handler" 7 | "github.com/99designs/gqlgen/graphql/handler/debug" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/federationtesting/accounts/graph/generated" 10 | ) 11 | 12 | type EndpointOptions struct { 13 | EnableDebug bool 14 | } 15 | 16 | var TestOptions = EndpointOptions{ 17 | EnableDebug: false, 18 | } 19 | 20 | func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { 21 | srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) 22 | if opts.EnableDebug { 23 | srv.Use(&debug.Tracer{}) 24 | } 25 | 26 | return srv 27 | } 28 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/accounts/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | type Resolver struct{} 7 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/accounts/graph/wallets.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/federationtesting/accounts/graph/model" 4 | 5 | var walletOne = &model.WalletType1{ 6 | Currency: "USD", 7 | Amount: 123, 8 | SpecialField1: "some special value 1", 9 | } 10 | 11 | var walletTwo = &model.WalletType2{ 12 | Currency: "USD", 13 | Amount: 123, 14 | SpecialField2: "some special value 2", 15 | } 16 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/accounts/handler.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package accounts 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/federationtesting/accounts/graph" 8 | ) 9 | 10 | func Handler() http.Handler { 11 | return graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true}) 12 | } 13 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/products/graph/model/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package model 4 | 5 | type Product struct { 6 | Upc string `json:"upc"` 7 | Name string `json:"name"` 8 | Price int `json:"price"` 9 | InStock int `json:"inStock"` 10 | } 11 | 12 | func (Product) IsEntity() {} 13 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/products/graph/products.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/federationtesting/products/graph/model" 5 | ) 6 | 7 | var hats []*model.Product 8 | 9 | func Reset() { 10 | hats = []*model.Product{ 11 | { 12 | Upc: "top-1", 13 | Name: "Trilby", 14 | Price: 11, 15 | InStock: 500, 16 | }, 17 | { 18 | Upc: "top-2", 19 | Name: "Fedora", 20 | Price: 22, 21 | InStock: 1200, 22 | }, 23 | { 24 | Upc: "top-3", 25 | Name: "Boater", 26 | Price: 33, 27 | InStock: 850, 28 | }, 29 | } 30 | } 31 | 32 | func init() { 33 | Reset() 34 | } 35 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/products/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | type Resolver struct{} 7 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/products/graph/schema.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | topProducts(first: Int = 5): [Product] 3 | } 4 | 5 | extend type Mutation { 6 | setPrice(upc: String!, price: Int!): Product 7 | } 8 | 9 | extend type Subscription { 10 | updatedPrice: Product! 11 | updateProductPrice(upc: String!): Product! 12 | } 13 | 14 | type Product @key(fields: "upc") { 15 | upc: String! 16 | name: String! 17 | price: Int! 18 | inStock: Int! 19 | } 20 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/products/graph/variables.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | var ( 8 | randomnessEnabled = true 9 | minPrice = 10 10 | maxPrice = 1499 11 | currentPrice = minPrice 12 | updateInterval = time.Second 13 | ) 14 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/products/handler.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package products 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/federationtesting/products/graph" 8 | ) 9 | 10 | func Handler() http.Handler { 11 | mux := http.NewServeMux() 12 | 13 | mux.Handle("/", graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true})) 14 | mux.HandleFunc("/websocket_connections", graph.WebsocketConnectionsHandler) 15 | 16 | return mux 17 | } 18 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/reviews/graph/attachments.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import "github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/federationtesting/reviews/graph/model" 4 | 5 | var attachments = []model.Attachment{ 6 | model.Question{ 7 | Upc: "top-1", 8 | Body: "How do I turn it on?", 9 | }, 10 | model.Question{ 11 | Upc: "top-3", 12 | Body: "Any recommendations for other teacosies?", 13 | }, 14 | model.Rating{ 15 | Upc: "top-2", 16 | Body: "The best hat I have ever bought in my life.", 17 | Score: 5, 18 | }, 19 | model.Rating{ 20 | Upc: "top-3", 21 | Body: "Terrible teacosy!!!", 22 | Score: 0, 23 | }, 24 | model.Video{ 25 | Upc: "top-2", 26 | Size: 13.37, 27 | }, 28 | model.Video{ 29 | Upc: "top-3", 30 | Size: 4.20, 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/reviews/graph/handler.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/99designs/gqlgen/graphql/handler" 7 | "github.com/99designs/gqlgen/graphql/handler/debug" 8 | 9 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/federationtesting/reviews/graph/generated" 10 | ) 11 | 12 | type EndpointOptions struct { 13 | EnableDebug bool 14 | } 15 | 16 | var TestOptions = EndpointOptions{ 17 | EnableDebug: false, 18 | } 19 | 20 | func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { 21 | srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) 22 | if opts.EnableDebug { 23 | srv.Use(&debug.Tracer{}) 24 | } 25 | 26 | return srv 27 | } 28 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/reviews/graph/model/models.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Product struct { 4 | Upc string `json:"upc"` 5 | } 6 | 7 | func (Product) IsEntity() {} 8 | 9 | type Review struct { 10 | Body string 11 | Author *User 12 | Product *Product 13 | } 14 | 15 | type User struct { 16 | ID string `json:"id"` 17 | } 18 | 19 | func (User) IsEntity() {} 20 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/reviews/graph/resolver.go: -------------------------------------------------------------------------------- 1 | // This file will not be regenerated automatically. 2 | // 3 | // It serves as dependency injection for your app, add any dependencies you require here. 4 | package graph 5 | 6 | type Resolver struct{} 7 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/reviews/graph/reviews.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/federationtesting/reviews/graph/model" 5 | ) 6 | 7 | var reviews = []*model.Review{ 8 | { 9 | Body: "A highly effective form of birth control.", 10 | Product: &model.Product{Upc: "top-1"}, 11 | Author: &model.User{ID: "1234"}, 12 | }, 13 | { 14 | Body: "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.", 15 | Product: &model.Product{Upc: "top-2"}, 16 | Author: &model.User{ID: "1234"}, 17 | }, 18 | { 19 | Body: "This is the last straw. Hat you will wear. 11/10", 20 | Product: &model.Product{Upc: "top-3"}, 21 | Author: &model.User{ID: "7777"}, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/reviews/handler.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package reviews 3 | 4 | import ( 5 | "net/http" 6 | 7 | "github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/federationtesting/reviews/graph" 8 | ) 9 | 10 | func Handler() http.Handler { 11 | return graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true}) 12 | } 13 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/mutations/mutation_with_variables.query: -------------------------------------------------------------------------------- 1 | mutation AddReview($authorID: String!, $upc: String!, $review: String!) { 2 | addReview(authorID: $authorID upc: $upc, review: $review) { 3 | body 4 | author { 5 | username 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/interface.query: -------------------------------------------------------------------------------- 1 | query MyHistory { 2 | me { 3 | username 4 | history { 5 | ... on Purchase { 6 | wallet { 7 | amount 8 | ... on WalletType1 { 9 | specialField1 10 | } 11 | ... on WalletType2 { 12 | specialField2 13 | } 14 | } 15 | } 16 | ... on Sale { 17 | rating 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/interface_fragment_on_object.graphql: -------------------------------------------------------------------------------- 1 | query InterfaceFragment { 2 | me { 3 | ... on Identifiable { 4 | id 5 | } 6 | ... on User { 7 | username 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/interface_fragments_on_union.graphql: -------------------------------------------------------------------------------- 1 | query InterfaceFragmentsOnUnion { 2 | histories { 3 | ... on Store { 4 | __typename 5 | location 6 | } 7 | ... on Info { 8 | __typename 9 | quantity 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/merged_field.graphql: -------------------------------------------------------------------------------- 1 | query MergedField { 2 | cat { 3 | name 4 | } 5 | me { 6 | id 7 | username 8 | realName 9 | reviews { 10 | body 11 | } 12 | history { 13 | ... on Sale { 14 | rating 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/multiple_queries.query: -------------------------------------------------------------------------------- 1 | query { 2 | topProducts { 3 | __typename 4 | price 5 | upc 6 | } 7 | me { 8 | __typename 9 | id 10 | username 11 | } 12 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/multiple_queries_with_nested_fragments.query: -------------------------------------------------------------------------------- 1 | fragment ProductFragment on Product { 2 | __typename 3 | price 4 | upc 5 | } 6 | 7 | fragment ReviewFragment on Review { 8 | __typename 9 | product { 10 | ...ProductFragment 11 | } 12 | } 13 | 14 | fragment UserFragment on User { 15 | __typename 16 | id 17 | username 18 | reviews { 19 | ...ReviewFragment 20 | } 21 | } 22 | 23 | query { 24 | topProducts { 25 | ...ProductFragment 26 | } 27 | me { 28 | ...UserFragment 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/multiple_queries_with_union_return.query: -------------------------------------------------------------------------------- 1 | query Histories { 2 | me { 3 | __typename 4 | id 5 | username 6 | } 7 | histories { 8 | __typename 9 | ... on Sale { 10 | product { 11 | __typename 12 | upc 13 | } 14 | rating 15 | } 16 | ... on Purchase { 17 | product { 18 | __typename 19 | upc 20 | } 21 | wallet { 22 | __typename 23 | currency 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/multiple_upstream.query: -------------------------------------------------------------------------------- 1 | query MultipleServers { 2 | topProducts { 3 | name 4 | reviews { 5 | body 6 | author { 7 | username 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/object_fragment_on_interface.graphql: -------------------------------------------------------------------------------- 1 | query InterfaceResponse { 2 | identifiable { 3 | __typename 4 | id 5 | ... on User { 6 | username 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/single_upstream.query: -------------------------------------------------------------------------------- 1 | query Me { 2 | me { 3 | id 4 | username 5 | } 6 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/queries/union.query: -------------------------------------------------------------------------------- 1 | query MyHistory { 2 | me { 3 | username 4 | history { 5 | __typename 6 | ... on Purchase { 7 | wallet { 8 | amount 9 | } 10 | } 11 | ... on Sale { 12 | rating 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /v2/pkg/testing/federationtesting/testdata/subscriptions/subscription.query: -------------------------------------------------------------------------------- 1 | subscription UpdatePrice($upc: String!) { 2 | updateProductPrice(upc: $upc) { 3 | upc 4 | name 5 | price 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /v2/pkg/testing/flags/flags.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | 3 | package flags 4 | 5 | const IsWindows = false 6 | -------------------------------------------------------------------------------- /v2/pkg/testing/flags/flags_win.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | package flags 4 | 5 | const IsWindows = true 6 | -------------------------------------------------------------------------------- /v2/pkg/testing/goldie/goldie.go: -------------------------------------------------------------------------------- 1 | package goldie 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sebdah/goldie/v2" 7 | ) 8 | 9 | // New creates a new instance of Goldie. 10 | func New(t *testing.T) *goldie.Goldie { 11 | return goldie.New(t, goldie.WithFixtureDir("fixtures")) 12 | } 13 | -------------------------------------------------------------------------------- /v2/pkg/testing/goldie/goldie_posix.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | 3 | package goldie 4 | 5 | import ( 6 | "testing" 7 | ) 8 | 9 | func Assert(t *testing.T, name string, actual []byte, _ ...bool) { 10 | t.Helper() 11 | 12 | New(t).Assert(t, name, actual) 13 | } 14 | 15 | func Update(t *testing.T, name string, actual []byte) { 16 | t.Helper() 17 | 18 | _ = New(t).Update(t, name, actual) 19 | } 20 | -------------------------------------------------------------------------------- /v2/pkg/testing/goldie/goldie_win.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | package goldie 4 | 5 | import ( 6 | "testing" 7 | ) 8 | 9 | func Assert(t *testing.T, name string, actual []byte, useOSSuffix ...bool) { 10 | t.Helper() 11 | 12 | if len(useOSSuffix) == 1 && useOSSuffix[0] { 13 | name = name + "_windows" 14 | } 15 | 16 | New(t).Assert(t, name, actual) 17 | } 18 | 19 | func Update(t *testing.T, name string, actual []byte) { 20 | t.Helper() 21 | t.Fatalf("golden files should not be updated on windows") 22 | } 23 | -------------------------------------------------------------------------------- /v2/pkg/testing/subscriptiontesting/.gqlgen.yml: -------------------------------------------------------------------------------- 1 | models: 2 | Chatroom: 3 | model: github.com/TykTechnologies/graphql-go-tools/v2/pkg/testing/subscriptiontesting.Chatroom 4 | -------------------------------------------------------------------------------- /v2/pkg/testing/subscriptiontesting/handler.go: -------------------------------------------------------------------------------- 1 | //go:generate go run -mod=mod github.com/99designs/gqlgen 2 | package subscriptiontesting 3 | 4 | import ( 5 | "net/http" 6 | "time" 7 | 8 | "github.com/99designs/gqlgen/graphql/handler" 9 | "github.com/99designs/gqlgen/graphql/handler/extension" 10 | "github.com/99designs/gqlgen/graphql/handler/transport" 11 | "github.com/gorilla/websocket" 12 | ) 13 | 14 | func ChatGraphQLEndpointHandler() http.Handler { 15 | srv := handler.New(NewExecutableSchema(New())) 16 | 17 | srv.AddTransport(transport.POST{}) 18 | srv.AddTransport(transport.Websocket{ 19 | KeepAlivePingInterval: 10 * time.Second, 20 | Upgrader: websocket.Upgrader{ 21 | CheckOrigin: func(r *http.Request) bool { 22 | return true 23 | }, 24 | }, 25 | }) 26 | srv.Use(extension.Introspection{}) 27 | 28 | return srv 29 | } 30 | -------------------------------------------------------------------------------- /v2/pkg/testing/subscriptiontesting/models_gen.go: -------------------------------------------------------------------------------- 1 | // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. 2 | 3 | package subscriptiontesting 4 | 5 | import ( 6 | "time" 7 | ) 8 | 9 | type Message struct { 10 | ID string `json:"id"` 11 | Text string `json:"text"` 12 | CreatedBy string `json:"createdBy"` 13 | CreatedAt time.Time `json:"createdAt"` 14 | } 15 | -------------------------------------------------------------------------------- /v2/pkg/testing/subscriptiontesting/schema.graphql: -------------------------------------------------------------------------------- 1 | type Chatroom { 2 | name: String! 3 | messages: [Message!]! 4 | } 5 | 6 | type Message { 7 | id: ID! 8 | text: String! 9 | createdBy: String! 10 | createdAt: Time! 11 | } 12 | 13 | type Query { 14 | room(name:String!): Chatroom 15 | } 16 | 17 | type Mutation { 18 | post(text: String!, username: String!, roomName: String!): Message! 19 | } 20 | 21 | type Subscription { 22 | messageAdded(roomName: String!): Message! 23 | } 24 | 25 | scalar Time 26 | 27 | directive @user(username: String!) on SUBSCRIPTION 28 | --------------------------------------------------------------------------------