-
-
Notifications
You must be signed in to change notification settings - Fork 251
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2e927df
commit 1345a3c
Showing
32 changed files
with
707 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
name: Federation Specification Compatibility Test | ||
|
||
on: | ||
pull_request: | ||
branches: | ||
- series/2.x | ||
|
||
jobs: | ||
compatibility: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout current branch (full) | ||
uses: actions/checkout@v2 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Setup Java (temurin@17) | ||
uses: actions/setup-java@v2 | ||
with: | ||
distribution: 'temurin' | ||
java-version: '17' | ||
|
||
- name: Compatibility Test | ||
uses: apollographql/federation-subgraph-compatibility@v2 | ||
with: | ||
compose: 'apollo-compatibility/docker-compose.yaml' | ||
schema: 'apollo-compatibility/schema.graphql' | ||
path: 'graphql' | ||
port: 4001 | ||
debug: true | ||
token: ${{ secrets.GITHUB_TOKEN }} | ||
# Boolean flag to indicate whether any failing test should fail the script | ||
failOnWarning: false | ||
# Boolean flag to indicate whether any required test should fail the script | ||
failOnRequired: false | ||
# Working directory to run the test from | ||
workingDirectory: '' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
FROM hseeberger/scala-sbt:17.0.2_1.9.9_3.1.1 AS build | ||
|
||
WORKDIR /build | ||
COPY build.sbt . | ||
COPY project ./project | ||
COPY core ./core | ||
COPY federation ./federation | ||
COPY adapters/quick ./adapters/quick | ||
COPY macros ./macros | ||
COPY apollo-compatibility/src ./apollo-compatibility/src | ||
EXPOSE 4001 | ||
CMD sbt apollo-compatibility/run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# federated subgraph to test apollo federation spec compatibility | ||
|
||
Implementation of a federated subgraph aligned to the requirements outlined in [apollo-federation-subgraph-compatibility](https://github.com/apollographql/apollo-federation-subgraph-compatibility). | ||
|
||
The subgraph can be used to verify compability against [Apollo Federation Subgraph Specification](https://www.apollographql.com/docs/federation/subgraph-spec). | ||
|
||
### Run compatibility tests | ||
Execute the following command from the root of the repo | ||
|
||
``` | ||
npx @apollo/federation-subgraph-compatibility docker --compose apollo-compatibility/docker-compose.yml --schema apollo-compatibility/schema.graphql | ||
``` | ||
|
||
### Printing the GraphQL Schema (SDL) | ||
|
||
``` | ||
sbt "apollo-compability/run printSchema" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
services: | ||
products: | ||
build: | ||
context: . | ||
dockerfile: ./apollo-compatibility/Dockerfile | ||
ports: | ||
- 4001:4001 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
extend schema | ||
@link( | ||
url: "https://specs.apollo.dev/federation/v2.3" | ||
import: [ | ||
"@composeDirective" | ||
"@extends" | ||
"@external" | ||
"@key" | ||
"@inaccessible" | ||
"@interfaceObject" | ||
"@override" | ||
"@provides" | ||
"@requires" | ||
"@shareable" | ||
"@tag" | ||
] | ||
) | ||
@link(url: "https://myspecs.dev/myCustomDirective/v1.0", import: ["@custom"]) | ||
@composeDirective(name: "@custom") | ||
|
||
directive @custom on OBJECT | ||
|
||
type Product | ||
@custom | ||
@key(fields: "id") | ||
@key(fields: "sku package") | ||
@key(fields: "sku variation { id }") { | ||
id: ID! | ||
sku: String | ||
package: String | ||
variation: ProductVariation | ||
dimensions: ProductDimension | ||
createdBy: User @provides(fields: "totalProductsCreated") | ||
notes: String @tag(name: "internal") | ||
research: [ProductResearch!]! | ||
} | ||
|
||
type DeprecatedProduct @key(fields: "sku package") { | ||
sku: String! | ||
package: String! | ||
reason: String | ||
createdBy: User | ||
} | ||
|
||
type ProductVariation { | ||
id: ID! | ||
} | ||
|
||
type ProductResearch @key(fields: "study { caseNumber }") { | ||
study: CaseStudy! | ||
outcome: String | ||
} | ||
|
||
type CaseStudy { | ||
caseNumber: ID! | ||
description: String | ||
} | ||
|
||
type ProductDimension @shareable { | ||
size: String | ||
weight: Float | ||
unit: String @inaccessible | ||
} | ||
|
||
extend type Query { | ||
product(id: ID!): Product | ||
deprecatedProduct(sku: String!, package: String!): DeprecatedProduct | ||
@deprecated(reason: "Use product query instead") | ||
} | ||
|
||
extend type User @key(fields: "email") { | ||
averageProductsCreatedPerYear: Int | ||
@requires(fields: "totalProductsCreated yearsOfEmployment") | ||
email: ID! @external | ||
name: String @override(from: "users") | ||
totalProductsCreated: Int @external | ||
yearsOfEmployment: Int! @external | ||
} | ||
|
||
type Inventory @interfaceObject @key(fields: "id") { | ||
id: ID! | ||
deprecatedProducts: [DeprecatedProduct!]! | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import caliban.CalibanError | ||
import zio._ | ||
import caliban.quick._ | ||
import services.{ InventoryService, ProductService, UserService } | ||
import zio.http.Server | ||
|
||
object Main extends ZIOAppDefault { | ||
|
||
def run = for { | ||
args <- ZIOAppArgs.getArgs | ||
_ <- (args match { | ||
case Chunk("printSchema") => printSchema | ||
case _ => runServer | ||
}) | ||
} yield () | ||
|
||
val printSchema = Console.printLine(ProductSchema.print) | ||
|
||
val runServer = { | ||
val server: ZIO[ | ||
ProductService with UserService with InventoryService with Server, | ||
CalibanError.ValidationError, | ||
Int | ||
] = (ProductSchema.api.toApp("/graphql") flatMap Server.install) | ||
|
||
(server *> Console.printLine("Press any key to exit...") *> Console.readLine).orDie | ||
.provide( | ||
Server.defaultWithPort(4001), | ||
ProductService.inMemory, | ||
UserService.inMemory, | ||
InventoryService.inMemory | ||
) | ||
} | ||
|
||
} |
103 changes: 103 additions & 0 deletions
103
apollo-compatibility/src/main/scala/ProductSchema.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import caliban._ | ||
import caliban.federation.EntityResolver | ||
import caliban.federation.tracing.ApolloFederatedTracing | ||
import caliban.introspection.adt.{ __Directive, __DirectiveLocation } | ||
import caliban.schema.Annotations.GQLDeprecated | ||
import caliban.schema.{ GenericSchema, Schema } | ||
import models._ | ||
import services.{ InventoryService, ProductService, UserService } | ||
import zio.query.ZQuery | ||
import zio.{ URIO, ZIO } | ||
|
||
case class Query( | ||
product: QueryProductArgs => URIO[ProductService, Option[models.Product]], | ||
@GQLDeprecated("Use product query instead") deprecatedProduct: DeprecatedProductArgs => URIO[ | ||
ProductService, | ||
Option[DeprecatedProduct] | ||
] | ||
) | ||
|
||
object Query { | ||
object apiSchema extends GenericSchema[ProductService with UserService] | ||
implicit val schema: Schema[ProductService with UserService, Query] = apiSchema.gen | ||
} | ||
|
||
object ProductSchema extends GenericSchema[ProductService with UserService] { | ||
val productResolver: EntityResolver[ProductService with UserService] = | ||
EntityResolver[ProductService with UserService, ProductArgs, models.Product] { | ||
case ProductArgs.IdOnly(id) => | ||
ZQuery.serviceWithZIO[ProductService](_.getProductById(id.id)) | ||
case ProductArgs.SkuAndPackage(sku, p) => | ||
ZQuery.serviceWithZIO[ProductService](_.getProductBySkuAndPackage(sku, p)) | ||
case ProductArgs.SkuAndVariationId(sku, variation) => | ||
ZQuery.serviceWithZIO[ProductService](_.getProductBySkuAndVariationId(sku, variation.id.id)) | ||
} | ||
|
||
val userResolver: EntityResolver[UserService with ProductService] = | ||
EntityResolver[UserService with ProductService, UserArgs, User] { args => | ||
ZQuery.serviceWithZIO[UserService](_.getUser) | ||
} | ||
|
||
val productResearchResolver: EntityResolver[UserService with ProductService] = | ||
EntityResolver.from[ProductResearchArgs] { args => | ||
ZQuery.some( | ||
ProductResearch( | ||
CaseStudy(caseNumber = args.study.caseNumber, Some("Federation Study")), | ||
None | ||
) | ||
) | ||
} | ||
|
||
val deprecatedProductResolver: EntityResolver[ProductService with UserService] = | ||
EntityResolver[ProductService with UserService, DeprecatedProductArgs, DeprecatedProduct] { args => | ||
ZQuery.some( | ||
models.DeprecatedProduct( | ||
sku = "apollo-federation-v1", | ||
`package` = "@apollo/federation-v1", | ||
reason = Some("Migrate to Federation V2"), | ||
createdBy = ZIO.serviceWithZIO[UserService](_.getUser) | ||
) | ||
) | ||
} | ||
|
||
val inventoryResolver: EntityResolver[InventoryService with UserService] = | ||
EntityResolver[InventoryService with UserService, InventoryArgs, Inventory] { args => | ||
ZQuery.serviceWith[InventoryService](_.getById(args.id.id)) | ||
} | ||
|
||
val api: GraphQL[ProductService with UserService with InventoryService] = | ||
graphQL( | ||
RootResolver( | ||
Query( | ||
args => ZIO.serviceWithZIO[ProductService](_.getProductById(args.id.id)), | ||
args => | ||
ZIO.some( | ||
models.DeprecatedProduct( | ||
sku = "apollo-federation-v1", | ||
`package` = "@apollo/federation-v1", | ||
reason = Some("Migrate to Federation V2"), | ||
createdBy = ZIO.serviceWithZIO[UserService](_.getUser) | ||
) | ||
) | ||
) | ||
), | ||
directives = List( | ||
__Directive( | ||
"custom", | ||
None, | ||
Set(__DirectiveLocation.OBJECT), | ||
_ => Nil, | ||
isRepeatable = false | ||
) | ||
) | ||
) @@ federated( | ||
productResolver, | ||
userResolver, | ||
productResearchResolver, | ||
deprecatedProductResolver, | ||
inventoryResolver | ||
) @@ ApolloFederatedTracing.wrapper() | ||
|
||
val print = api.render | ||
|
||
} |
12 changes: 12 additions & 0 deletions
12
apollo-compatibility/src/main/scala/models/CaseStudy.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package models | ||
|
||
import caliban.schema.Schema | ||
|
||
case class CaseStudy( | ||
caseNumber: ID, | ||
description: Option[String] | ||
) | ||
|
||
object CaseStudy { | ||
implicit val schema: Schema[Any, CaseStudy] = Schema.gen | ||
} |
10 changes: 10 additions & 0 deletions
10
apollo-compatibility/src/main/scala/models/CaseStudyArgs.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package models | ||
|
||
import caliban.schema.{ ArgBuilder, Schema } | ||
|
||
case class CaseStudyArgs(caseNumber: ID) | ||
|
||
object CaseStudyArgs { | ||
implicit val schema: Schema[Any, CaseStudyArgs] = Schema.gen | ||
implicit val argBuilder: ArgBuilder[CaseStudyArgs] = ArgBuilder.gen | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package models | ||
|
||
import caliban.parsing.adt.Directive | ||
import caliban.schema.Annotations.GQLDirective | ||
|
||
case class Custom() extends GQLDirective(Directive("custom")) |
19 changes: 19 additions & 0 deletions
19
apollo-compatibility/src/main/scala/models/DeprecatedProduct.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package models | ||
|
||
import caliban.schema.{ GenericSchema, Schema } | ||
import services.UserService | ||
import zio.URIO | ||
|
||
@GQLKey("sku package") | ||
case class DeprecatedProduct( | ||
sku: String, | ||
`package`: String, | ||
reason: Option[String], | ||
createdBy: URIO[UserService, Option[User]] | ||
) | ||
|
||
object DeprecatedProduct { | ||
object apiSchema extends GenericSchema[UserService] | ||
|
||
implicit val schema: Schema[UserService, DeprecatedProduct] = apiSchema.gen[UserService, DeprecatedProduct] | ||
} |
13 changes: 13 additions & 0 deletions
13
apollo-compatibility/src/main/scala/models/DeprecatedProductArgs.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package models | ||
|
||
import caliban.schema.{ ArgBuilder, Schema } | ||
|
||
case class DeprecatedProductArgs( | ||
sku: String, | ||
`package`: String | ||
) | ||
|
||
object DeprecatedProductArgs { | ||
implicit val schema: Schema[Any, DeprecatedProductArgs] = Schema.gen | ||
implicit val argBuilder: ArgBuilder[DeprecatedProductArgs] = ArgBuilder.gen[DeprecatedProductArgs] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package models | ||
|
||
import caliban.schema.{ ArgBuilder, Schema } | ||
import caliban.Value.StringValue | ||
|
||
case class ID(id: String) extends AnyVal | ||
|
||
object ID { | ||
implicit val schema: Schema[Any, ID] = Schema.scalarSchema[ID]("ID", None, None, None, id => StringValue(id.id)) | ||
implicit val argBuilder: ArgBuilder[ID] = ArgBuilder.string.map(ID(_)) | ||
} |
Oops, something went wrong.