Class: ElasticGraph::QueryRegistry::Registry
- Inherits:
-
Object
- Object
- ElasticGraph::QueryRegistry::Registry
- Defined in:
- lib/elastic_graph/query_registry/registry.rb
Overview
An abstraction that implements a registry of GraphQL queries. Callers should use ‘build_and_validate_query` to get `GraphQL::Query` objects so that clients are properly limited in what queries we execute on their behalf.
Note that this class is designed to be as efficient as possible:
-
Registered GraphQL queries are only parsed once, and then the parsed form is used each time that query is submitted. In our benchmarking, parsing of large queries can be significant, taking ~10ms or so.
-
We delay parsing a registered client’s queries until the first time that client sends us a query. That way, we don’t have to pay any parsing cost for queries that were registered by an old client that no longer sends us requests.
-
Likewise, we defer reading a client’s registered query strings off of disk until the first time it submits a request.
In addition, it’s worth noting that we support some basic “fuzzy” matching of query strings, based on the query canonicalization performed by the GraphQL gem. Semantically insignificant changes to the query string from a registered query (such as whitespace differences, or comments) are tolerated.
Class Method Summary collapse
-
.build_from_directory(schema, directory, allow_unregistered_clients:, allow_any_query_for_clients:) ⇒ Object
Public factory method, which builds a ‘Registry` instance from the given directory.
Instance Method Summary collapse
-
#build_and_validate_query(query_string, client:, variables: {}, operation_name: nil, context: {}) ⇒ Object
Builds a ‘GraphQL::Query` object for the given query string, and validates that it is an allowed query.
Class Method Details
.build_from_directory(schema, directory, allow_unregistered_clients:, allow_any_query_for_clients:) ⇒ Object
Public factory method, which builds a ‘Registry` instance from the given directory. Subdirectories are treated as client names, and the files in them are treated as individually registered queries.
39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/elastic_graph/query_registry/registry.rb', line 39 def self.build_from_directory(schema, directory, allow_unregistered_clients:, allow_any_query_for_clients:) directory = Pathname.new(directory) new( schema, client_names: directory.children.map { |client_dir| client_dir.basename.to_s }, allow_unregistered_clients: allow_unregistered_clients, allow_any_query_for_clients: allow_any_query_for_clients ) do |client_name| # Lazily read queries off of disk when we need to for a given client. (directory / client_name).glob("*.graphql").map { |file| ::File.read(file.to_s) } end end |
Instance Method Details
#build_and_validate_query(query_string, client:, variables: {}, operation_name: nil, context: {}) ⇒ Object
Builds a ‘GraphQL::Query` object for the given query string, and validates that it is an allowed query. Returns a list of registry validation errors in addition to the built query object. The list of validation errors will be empty if the query should be allowed. A query can be allowed either by virtue of being registered for usage by the given clent, or by being for a completely unregistered client (if `allow_unregistered_clients` is `true`).
This is also tolerant of some minimal differences in the query string (such as comments and whitespace). If the query differs in a significant way from a registered query, it will not be recognized as registered.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/elastic_graph/query_registry/registry.rb', line 62 def build_and_validate_query(query_string, client:, variables: {}, operation_name: nil, context: {}) validator = if @registered_client_validator.applies_to?(client) @registered_client_validator else @unregistered_client_validator end validator.build_and_validate_query(query_string, client: client, variables: variables, operation_name: operation_name, context: context) do @schema.new_graphql_query( query_string, variables: variables, operation_name: operation_name, context: context ) end end |