44require_relative "composer/validate_interfaces"
55require_relative "composer/validate_type_resolvers"
66require_relative "composer/type_resolver_config"
7+ require_relative "composer/authorization"
78
89module GraphQL
910 module Stitching
1011 # Composer receives many individual `GraphQL::Schema` instances
1112 # representing various graph locations and merges them into one
1213 # combined Supergraph that is validated for integrity.
1314 class Composer
15+ include Authorization
16+
1417 # @api private
1518 NO_DEFAULT_VALUE = begin
1619 t = Class . new ( GraphQL ::Schema ::Object ) do
@@ -74,6 +77,7 @@ def initialize(
7477 @resolver_configs = { }
7578 @mapped_type_names = { }
7679 @visibility_profiles = Set . new ( visibility_profiles )
80+ @authorizations_by_type_and_field = { }
7781 @subgraph_directives_by_name_and_location = nil
7882 @subgraph_types_by_name_and_location = nil
7983 @schema_directives = nil
@@ -88,6 +92,7 @@ def perform(locations_input)
8892
8993 directives_to_omit = [
9094 GraphQL ::Stitching . stitch_directive ,
95+ GraphQL ::Stitching . authorization_directive ,
9196 Directives ::SupergraphKey . graphql_name ,
9297 Directives ::SupergraphResolver . graphql_name ,
9398 Directives ::SupergraphSource . graphql_name ,
@@ -183,6 +188,7 @@ def perform(locations_input)
183188 select_root_field_locations ( schema )
184189 expand_abstract_resolvers ( schema , schemas )
185190 apply_supergraph_directives ( schema , @resolver_map , @field_map )
191+ apply_authorization_directives ( schema , @authorizations_by_type_and_field )
186192
187193 if ( visibility_def = schema . directives [ GraphQL ::Stitching . visibility_directive ] )
188194 visibility_def . get_argument ( "profiles" ) . default_value ( @visibility_profiles . to_a . sort )
@@ -215,6 +221,10 @@ def prepare_locations_input(locations_input)
215221 @resolver_configs . merge! ( TypeResolverConfig . extract_directive_assignments ( schema , location , input [ :stitch ] ) )
216222 @resolver_configs . merge! ( TypeResolverConfig . extract_federation_entities ( schema , location ) )
217223
224+ if schema . directives [ GraphQL ::Stitching . authorization_directive ]
225+ SubgraphAuthorization . new ( schema ) . reverse_merge! ( @authorizations_by_type_and_field )
226+ end
227+
218228 schemas [ location . to_s ] = schema
219229 executables [ location . to_s ] = input [ :executable ] || schema
220230 end
@@ -774,6 +784,24 @@ def apply_supergraph_directives(schema, resolvers_by_type_name, locations_by_typ
774784
775785 schema_directives . each_value { |directive_class | schema . directive ( directive_class ) }
776786 end
787+
788+ def apply_authorization_directives ( schema , authorizations_by_type_and_field )
789+ return if authorizations_by_type_and_field . empty?
790+
791+ schema . types . each_value do |type |
792+ authorizations_by_field = authorizations_by_type_and_field [ type . graphql_name ]
793+ next if authorizations_by_field . nil? || !type . kind . fields?
794+
795+ type . fields . each_value do |field |
796+ scopes = authorizations_by_field [ field . graphql_name ]
797+ next if scopes . nil?
798+
799+ field . directive ( Directives ::Authorization , scopes : scopes )
800+ end
801+ end
802+
803+ schema . directive ( Directives ::Authorization )
804+ end
777805 end
778806 end
779807end
0 commit comments