# Federated Entity Data Fetcher implementation (Spring for GraphQL users)

**URL:** <https://community.apollographql.com/t/federated-entity-data-fetcher-implementation-spring-for-graphql-users/6364>\
**Category:** About the Community\
**Tags:** server, federation\
**Created:** [June 14, 2023, 7:15am UTC](https://community.apollographql.com/t/federated-entity-data-fetcher-implementation-spring-for-graphql-users/6364 "2023-06-14T07:15:45Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![ravi.ponduru.syncron](https://avatars.discourse-cdn.com/v4/letter/r/77aa72/32.png) [@ravi.ponduru.syncron](https://community.apollographql.com/u/ravi.ponduru.syncron)\
**Post date:** [June 14, 2023, 7:15am UTC](https://community.apollographql.com/t/federated-entity-data-fetcher-implementation-spring-for-graphql-users/6364/1 "2023-06-14T07:15:46Z")

</div>

**Problem statement:** Need to write more code for implementing federated entity Data Fetcher using Spring for GraphQL framework.

**Apollo-federation-jvm-spring-example:** [Spring GraphQL Federation Example](https://github.com/apollographql/federation-jvm-spring-example)

**Expectation:** New mapping annotation like @SchemaMapping to handle federated entity Data Fetcher

**Our Custom Approach:** To separate Data Fetchers based on cencerns, we followed the below approach. With this approach,

- Teams can concentrate on their business logic.
- Improve developer experience as the GraphQlConfig implementation can be done once in a common lib

1. Create an Interface

```auto
public interface EntityDataFetcher {
	
	public static final String TYP_NAME = "__typename";
	
	public String getTypeName();
	public Class<?> getTypeClass();
	public Object fetch(@NotNull Map<String, Object> reference);

}

```

1. Sample entity DataFetcher implementation

```auto
@Component
public class SampleDataFetcher implements EntityDataFetcher {
     
    public static final String SCHEMA_TYP_NM = "Sample";
     
    @Autowired
    private SampleService sampleService;
 
    @Override
    public String getTypeName() {
        return SCHEMA_TYP_NM; // Graph type, defined in schema
    }
 
    @Override
    public Class<?> getTypeClass() {
        return SampleResponseDTO.class; // Return object class, return by the data fetcher
    }
 
    @Override
    public Object fetch(@NotNull Map<String, Object> reference) {
        // Business logic to retrieve Sample entity
    }
 
}

```

1. GraphQlConfig implementation to register DataFetchers

```auto
@Configuration
public class GraphQlConfig {
	
	@Autowired(required=false)
	private List<EntityDataFetcher> dataFetchers;
	
	@Bean
	public GraphQlSourceBuilderCustomizer federationTransform() {
		return builder -> builder.schemaFactory((registry, wiring) ->
	        Federation.transform(registry, wiring)
                .fetchEntities(getEntityDataFetchers())
                .resolveEntityType(getClassNameTypeResolver())
                .build()
			);
	}
	
	private DataFetcher<?> getEntityDataFetchers() {
		Map<String, EntityDataFetcher> map = getEntityDataFetchersMap();

		DataFetcher<?> entityDataFetcher = env -> {
			List<Map<String, Object>> representations = env.getArgument(_Entity.argumentName);
			return representations.stream().map(representation -> {
				final String typeName = (String) representation.get(EntityDataFetcher.TYP_NAME);
				if (map.containsKey(typeName)) {
					return map.get(typeName).fetch(representation);
				} else {
					return null;
				}
			}).collect(Collectors.toList());
		};
		return entityDataFetcher;
	}
	
	private ClassNameTypeResolver getClassNameTypeResolver() {
		ClassNameTypeResolver classNameTypeResolver = new ClassNameTypeResolver();
		if (dataFetchers != null) {
			dataFetchers.stream().forEach(d -> {			
				classNameTypeResolver.addMapping(d.getTypeClass(), d.getTypeName());
			});
		}
		return classNameTypeResolver;
	}
	
	private Map<String, EntityDataFetcher> getEntityDataFetchersMap() {
		Map<String, EntityDataFetcher> map = null;
		if (dataFetchers != null) {
			map = dataFetchers.stream().collect(Collectors.toMap(EntityDataFetcher::getTypeName, d -> d));
		} else {
			map = Collections.emptyMap();
		}
		return map;
	}
	
}

```

---

<div class="post-metadata">

**Author:** ![Goran\_Petrovikj\_n47](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/goran_petrovikj_n47/32/4962_2.png) [@Goran\_Petrovikj\_n47](https://community.apollographql.com/u/Goran_Petrovikj_n47)\
**Post date:** [March 11, 2024, 9:33am UTC](https://community.apollographql.com/t/federated-entity-data-fetcher-implementation-spring-for-graphql-users/6364/2 "2024-03-11T09:33:04Z")

</div>

Thank you for sharing the solution!

---

<div class="post-metadata">

**Author:** ![dkuc](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/dkuc/32/2892_2.png) [@dkuc](https://community.apollographql.com/u/dkuc)\
**Post date:** [March 11, 2024, 6:29pm UTC](https://community.apollographql.com/t/federated-entity-data-fetcher-implementation-spring-for-graphql-users/6364/3 "2024-03-11T18:29:40Z")

</div>

FYI `spring-graphql` v1.3 provides built-in support for federation so you won’t need this workaround - see [Federation :: Spring GraphQL](https://docs.spring.io/spring-graphql/reference/1.3/federation.html) for details

---

<div class="post-metadata">

**Author:** ![Justin\_Gonzalez](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/justin_gonzalez/32/5359_2.png) [@Justin\_Gonzalez](https://community.apollographql.com/u/Justin_Gonzalez)\
**Post date:** [February 6, 2025, 8:48pm UTC](https://community.apollographql.com/t/federated-entity-data-fetcher-implementation-spring-for-graphql-users/6364/4 "2025-02-06T20:48:45Z")

</div>


