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
@@ -772,6 +782,24 @@ def apply_supergraph_directives(schema, resolvers_by_type_name, locations_by_typ
772782
773783 schema_directives . each_value { |directive_class | schema . directive ( directive_class ) }
774784 end
785+
786+ def apply_authorization_directives ( schema , authorizations_by_type_and_field )
787+ return if authorizations_by_type_and_field . empty?
788+
789+ schema . types . each_value do |type |
790+ authorizations_by_field = authorizations_by_type_and_field [ type . graphql_name ]
791+ next if authorizations_by_field . nil? || !type . kind . fields?
792+
793+ type . fields . each_value do |field |
794+ scopes = authorizations_by_field [ field . graphql_name ]
795+ next if scopes . nil?
796+
797+ field . directive ( Directives ::Authorization , scopes : scopes )
798+ end
799+ end
800+
801+ schema . directive ( Directives ::Authorization )
802+ end
775803 end
776804 end
777805end
0 commit comments