diff --git a/naptime-graphql/src/main/scala/org/coursera/naptime/ari/graphql/SangriaGraphQlSchemaBuilder.scala b/naptime-graphql/src/main/scala/org/coursera/naptime/ari/graphql/SangriaGraphQlSchemaBuilder.scala index 284294ec..c05c1131 100644 --- a/naptime-graphql/src/main/scala/org/coursera/naptime/ari/graphql/SangriaGraphQlSchemaBuilder.scala +++ b/naptime-graphql/src/main/scala/org/coursera/naptime/ari/graphql/SangriaGraphQlSchemaBuilder.scala @@ -30,6 +30,10 @@ import sangria.schema.Value import sangria.schema.Field import sangria.schema.ObjectType +import scala.util.Failure +import scala.util.Success +import scala.util.Try + class SangriaGraphQlSchemaBuilder(resources: Set[Resource], schemas: Map[String, RecordDataSchema]) extends StrictLogging { @@ -66,10 +70,26 @@ class SangriaGraphQlSchemaBuilder(resources: Set[Resource], schemas: Map[String, val schemaErrors = topLevelResourceObjectsAndErrors.foldLeft(SchemaErrors.empty)(_ ++ _.errors) val dedupedResources = topLevelResourceObjects.groupBy(_.name).map(_._2.head).toList + + // first, try to individually generate graphql schemas from each resource, and discard + // invalid schemas. this is done so that assembler can start even if some upstreams expose + // invalid schemas. + val validResources = dedupedResources + .filter { resource => + val resourceRootObject = + ObjectType[SangriaGraphQlContext, DataMap](name = "root", fields = List(resource)) + Try(Schema(resourceRootObject)) match { + case Success(_) => true + case Failure(exception) => + this.logger.error(s"schema validation failed for ${resource.name}", exception) + false + } + } + val rootObject = ObjectType[SangriaGraphQlContext, DataMap]( name = "root", description = "Top-level accessor for Naptime resources", - fields = dedupedResources) + fields = validResources) WithSchemaErrors(Schema(rootObject), schemaErrors) } diff --git a/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/SangriaGraphQlSchemaBuilderTest.scala b/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/SangriaGraphQlSchemaBuilderTest.scala new file mode 100644 index 00000000..74726fbd --- /dev/null +++ b/naptime-graphql/src/test/scala/org/coursera/naptime/ari/graphql/SangriaGraphQlSchemaBuilderTest.scala @@ -0,0 +1,56 @@ +package org.coursera.naptime.ari.graphql + +import com.google.inject.Injector +import com.linkedin.data.schema.RecordDataSchema +import org.coursera.naptime.ResourceName +import org.coursera.naptime.ari.FullSchema +import org.coursera.naptime.ari.LocalSchemaProvider +import org.coursera.naptime.ari.SchemaProvider +import org.coursera.naptime.ari.graphql.models.MergedCourse +import org.coursera.naptime.ari.graphql.models.MergedInstructor +import org.coursera.naptime.ari.graphql.models.MergedPartner +import org.coursera.naptime.ari.graphql.models.RecordWithUnionTypes +import org.coursera.naptime.model.Keyed +import org.coursera.naptime.router2.NaptimeRoutes +import org.coursera.naptime.router2.ResourceRouterBuilder +import org.coursera.naptime.schema.Handler +import org.coursera.naptime.schema.HandlerKind +import org.coursera.naptime.schema.Parameter +import org.coursera.naptime.schema.Resource +import org.coursera.naptime.schema.ResourceKind +import org.junit.Test +import org.mockito.Mockito._ +import org.scalatest.junit.AssertionsForJUnit +import org.scalatest.mockito.MockitoSugar + +class SangriaGraphQlSchemaBuilderTest extends AssertionsForJUnit { + @Test + def badResourceSchemaOmitFromGraphqlSchema(): Unit = { + val schemaTypes = Map( + "org.coursera.naptime.ari.graphql.models.MergedCourse" -> MergedCourse.SCHEMA, + "org.coursera.naptime.ari.graphql.models.FakeModel" -> RecordWithUnionTypes.SCHEMA, + "org.coursera.naptime.ari.graphql.models.MergedPartner" -> MergedPartner.SCHEMA, + "org.coursera.naptime.ari.graphql.models.MergedInstructor" -> MergedInstructor.SCHEMA + ) + val resourcesWithInvalidResource = + Set( + Models.courseResource.copy(version = Some(-1)), + Models.instructorResource, + Models.partnersResource, + Models.fakeModelResource + ) + val builder = new SangriaGraphQlSchemaBuilder(resourcesWithInvalidResource, schemaTypes) + val schema = builder.generateSchema().data + + val allResources2 = + Set( + Models.instructorResource, + Models.partnersResource, + Models.fakeModelResource + ) + val builder2 = new SangriaGraphQlSchemaBuilder(allResources2, schemaTypes) + val schema2 = builder2.generateSchema().data + + assertResult(schema2.renderPretty)(schema.renderPretty) + } +}