Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

complete restructuring #9

Merged
merged 1 commit into from
Aug 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 0 additions & 11 deletions .docker/graph-router.Dockerfile

This file was deleted.

18 changes: 0 additions & 18 deletions .docker/inventory.Dockerfile

This file was deleted.

18 changes: 0 additions & 18 deletions .docker/users.Dockerfile

This file was deleted.

2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"program": "dist/index.js",
"outFiles": ["${workspaceFolder}/**/*.js"],
"preLaunchTask": "build",
"cwd": "${workspaceFolder}/src/implementations/apollo-server"
"cwd": "${workspaceFolder}/implementations/apollo-server"
},
{
"type": "java",
Expand Down
55 changes: 26 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ This repository contains a structured testing suite based on a federated schema

## Subgraph Schemas

### Users
### Users

```graphql
type User @key(fields:"email") {
email:ID!
name: String
totalProductsCreated: Int
type User @key(fields: "email") {
email: ID!
name: String
totalProductsCreated: Int
}
```

Expand All @@ -20,7 +20,8 @@ type User @key(fields:"email") {
extend type Product @key(fields: "id") {
id: ID! @external
dimensions: ProductDimension @external
delivery(zip: String): DeliveryEstimates @requires(fields: "dimensions { size weight }")
delivery(zip: String): DeliveryEstimates
@requires(fields: "dimensions { size weight }")
}

type ProductDimension {
Expand All @@ -37,12 +38,15 @@ type DeliveryEstimates {
### Products (schema to be implemented by library maintainers)

```graphql
type Product @key(fields: "id") @key(fields: "sku package") @key(fields: "sku variation { id }"){
type Product
@key(fields: "id")
@key(fields: "sku package")
@key(fields: "sku variation { id }") {
id: ID!
sku: String
package: String
variation: ProductVariation
dimensions: ProductDimension
dimensions: ProductDimension

createdBy: User @provides(fields: "totalProductsCreated")
}
Expand All @@ -60,22 +64,17 @@ extend type Query {
product(id: ID!): Product
}

extend type User @key(fields:"email") {
extend type User @key(fields: "email") {
email: ID! @external
totalProductsCreated: Int @external
}
```






## Testing Spec Compliance

* `_service` - support a `rover subgraph introspect` command (this is the Apollo Federation equivalent of Introspection for subgraphs)
* `query { _service { sdl } }`
* `@key` and `_entities` - support defining a single `@key`, multiple `@key` definitionss, multiple-fields `@key` and a complex fields `@key`. Below is an example of the single `@key` query that is sent from the graph router to the implementing `products` subgraph (the variables will be changed to test all `@key` definitions):
- `_service` - support a `rover subgraph introspect` command (this is the Apollo Federation equivalent of Introspection for subgraphs)
- `query { _service { sdl } }`
- `@key` and `_entities` - support defining a single `@key`, multiple `@key` definitionss, multiple-fields `@key` and a complex fields `@key`. Below is an example of the single `@key` query that is sent from the graph router to the implementing `products` subgraph (the variables will be changed to test all `@key` definitions):

```
query ($representations: [_Any!]!){
Expand All @@ -86,41 +85,39 @@ query ($representations: [_Any!]!){
}
```

* @requires - support defining complex fields
* This will be tested through a query covering [Product.delivery](<http://product.delivery>) where the library implementors dimensions { size weight } will need to be an expected { size: "1", weight: 1 } to pass. Example query that will be sent directly to `products` subgraph.
- @requires - support defining complex fields
- This will be tested through a query covering [Product.delivery](http://product.delivery) where the library implementors dimensions { size weight } will need to be an expected { size: "1", weight: 1 } to pass. Example query that will be sent directly to `products` subgraph.

```
query ($id: ID!){ product(id: $id) { dimensions { size weight } } }
```

* @provides - This will be covered by the library implementors at Product.createdBy where they will be expected to provide the User.totalProductsCreated to be *anything* *other than 4*
- @provides - This will be covered by the library implementors at Product.createdBy where they will be expected to provide the User.totalProductsCreated to be _anything_ _other than 4_

```
query ($id: ID!){ product(id: $id) { createdBy { email totalProductsCreated } } }
```

* @external - This is covered in the tests above.
* `extends` or `@extends` - This is covered in the `products` subgraph extension of the `User`
* `ftv1` (Federated Traces version 1) - A query with the `apollo-federated-include-trace:ftv1` header will be sent to the `products` subgraph which should return a value for the `extensions.ftv1` in the result.
* _NOTE: In the initial release of this testing strategy, we will not be validating `ftv1` to ensure it's in the proper format_
- @external - This is covered in the tests above.
- `extends` or `@extends` - This is covered in the `products` subgraph extension of the `User`
- `ftv1` (Federated Traces version 1) - A query with the `apollo-federated-include-trace:ftv1` header will be sent to the `products` subgraph which should return a value for the `extensions.ftv1` in the result.
- _NOTE: In the initial release of this testing strategy, we will not be validating `ftv1` to ensure it's in the proper format_

## Setting up the testing suite

1. `npm i`
1. `npm install`
2. `npm run setup`
- `npm run build` - compiles typescript code and composes supergraph SDL
- `npm run docker` - build docker images for `graph-router`, `users` and `inventory`

## Running the Test

`npm run test` will test all folders in the `src/implementations` folder. You can provide a comma separated string as an additional argument to test only specific libraries.
`npm run test` will test all folders in the `implementations` folder. You can provide a comma separated string as an additional argument to test only specific libraries.

## Test Results

A `results.md` file will be created that displays the testing results

## Contributing a new library to this test suite

Fork this repository and navigate to the [Apollo Federation Library Maintainers Implementation Guide](./src/implemenations/../implementations/_template_/README.md) for implementation instructions. Once you've completed the implementations instructions, feel free to create a PR and we'll review it. If you have any questions please open a GitHub issue on this repository.


Fork this repository and navigate to the [Apollo Federation Library Maintainers Implementation Guide](./src/implementations/_template_/README.md) for implementation instructions. Once you've completed the implementations instructions, feel free to create a PR and we'll review it. If you have any questions please open a GitHub issue on this repository.
17 changes: 17 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
services:
router:
image: ghcr.io/apollosolutions/gateway
volumes:
- ./supergraph.graphql:/etc/config/supergraph.graphql
environment:
- APOLLO_SCHEMA_CONFIG_EMBEDDED=/etc/config/supergraph.graphql
ports:
- 4000:4000
inventory:
image: apollo-federation-implementations/inventory
ports:
- 4003:4003
users:
image: apollo-federation-implementations/users
ports:
- 4002:4002
10 changes: 10 additions & 0 deletions implementations/_template_/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Example Dockerfile from apollo-server
#
# FROM node:14-alpine
# WORKDIR /web
# COPY package.json package-lock.json ./
# RUN npm install
# COPY index.js products.graphql ./
# EXPOSE 4001
# USER node
# CMD node index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ This doc is mean to provide Apollo Federation Library Maintainers with the neces

## Why should I even do this?

You've built a library and that should be celebrated! We want to build a stronger community around Apollo Federation and that includes us supporting you as a core maintainer! The Apollo Federation spec can potentially change overtime along with each implementing libraries `graphql` implementation (`graphql-js` vs `graphql-ruby` for example). This test suite should help identify scenarios where something is not working as epected early and Apollo can help provide guidance on what specifically might need to change.
You've built a library and that should be celebrated! We want to build a stronger community around Apollo Federation and that includes us supporting you as a core maintainer! The Apollo Federation spec can potentially change overtime along with each implementing libraries `graphql` implementation (`graphql-js` vs `graphql-ruby` for example). This test suite should help identify scenarios where something is not working as expected early and Apollo can help provide guidance on what specifically might need to change.

Dependabot will be setup in the near future to ensure that any changes to underlying packages will rerun the test suite and open an issue if there are any regressions.
Dependabot will be setup in the near future to ensure that any changes to underlying packages will rerun the test suite and open an issue if there are any regressions.

## How can I have my library included in this?

It's actually pretty easy! We have a `products` schema that you will need to implement to be used in the testing suite:

1. Copy the `src/implementations/_template_` folder and rename it to the name of your library
* You'll find 3 files that you need in the template folder: `docker-compose.yml`, `Dockerfile` and `products.graphql`
1. Copy the `implementations/_template_` folder and rename it to the name of your library
- You'll find 3 files that you need in the template folder: `docker-compose.yml`, `Dockerfile` and `products.graphql`
2. You'll need to implement the `products.graphql` file in your server, this is the reference implementation
3. Once you have the schema implemented, you'll need to modify the `Dockerfile` to make your server a Docker image and expose it on port 4001
* We will send traffic to `http://products:4001`, if your server has `/graphql` required you'll need to change it
- We will send traffic to `http://products:4001`, if your server has `/graphql` required you'll need to change it
4. You most likely don't need to modify the `docker-compose.yml` file, but it will be use for `docker compose` to test your implementation. If you do need to edit the `docker-compose.yml` file, your edits should only affect the `products` service defined.
5. Test only your library by running `npm run test {YOUR_IMPLEMENTATION_FOLDER_NAME}` and the results will be outputted to `results.md`

Expand All @@ -26,24 +26,34 @@ Below is data that is used in this testing strategy and what you should be using

```javascript
const products = [
{ id: 'apollo-federation', sku: 'federation', package: '@apollo/federation', variation: "OSS" },
{ id: 'apollo-studio', sku: 'studio', package: '', variation: "platform" }
]
{
id: "apollo-federation",
sku: "federation",
package: "@apollo/federation",
variation: "OSS",
},
{
id: "apollo-studio",
sku: "studio",
package: "",
variation: "platform",
},
];
```

## Debugging the projects
## Debugging the projects

There are debugging launch configurations established for all subgraphs provided to your along with the Graph Router.
In VSCode, you can open the debugger panel and debug any of the following:

* Debug Test - This debugs the actual test suite script
* Debug Graph Router - This launches/debugs the `ApolloGateway` instance
* Debug Users - This launches the `users` `ApolloServer` instance locally (not by the docker image). You can set break points in the resolver code as needed to explore.
* Debug Inventory - This launches the `inventory` `ApolloServer` instance locally (not by the docker image). You can set break points in the resolver code as needed to explore
- Debug Test - This debugs the actual test suite script
- Debug Graph Router - This launches/debugs the `ApolloGateway` instance
- Debug Users - This launches the `users` `ApolloServer` instance locally (not by the docker image). You can set break points in the resolver code as needed to explore.
- Debug Inventory - This launches the `inventory` `ApolloServer` instance locally (not by the docker image). You can set break points in the resolver code as needed to explore

### Debugging other implementations

It is not required to include debugging capabilities for every library, but it is very helpful. The follow libraries also have debug launch configurations established:

* Debug Products:apollo-server (TypeScript)
* Debug Products:federation-jvm (Java)
- Debug Products:apollo-server (TypeScript)
- Debug Products:federation-jvm (Java)
6 changes: 6 additions & 0 deletions implementations/_template_/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
services:
products:
# must be relative to the root of the project
build: implementations/_template_
ports:
- 4001:4001
8 changes: 8 additions & 0 deletions implementations/apollo-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM node:14-alpine
WORKDIR /web
COPY package.json package-lock.json ./
RUN npm install
COPY index.js products.graphql ./
EXPOSE 4001
USER node
CMD node index.js
6 changes: 6 additions & 0 deletions implementations/apollo-server/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
services:
products:
# must be relative to the root of the project
build: implementations/apollo-server
ports:
- 4001:4001
65 changes: 65 additions & 0 deletions implementations/apollo-server/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { readFileSync } from "fs";
import { ApolloServer, gql } from "apollo-server";
import { buildFederatedSchema } from "@apollo/federation";

const port = process.env.PRODUCTS_PORT || 4001;
const products = [
{
id: "apollo-federation",
sku: "federation",
package: "@apollo/federation",
variation: "OSS",
},
{
id: "apollo-studio",
sku: "studio",
package: "",
variation: "platform",
},
];

const sdl = readFileSync("products.graphql", "utf-8");

const typeDefs = gql(sdl);

const resolvers = {
Query: {
/** @type {(_: any, args: any, context: any) => any} */
product: (_, args, context) => {
return products.find((p) => p.id == args.id);
},
},
Product: {
/** @type {(reference: any) => any} */
variation: (reference) => {
if (reference.variation) return { id: reference.variation };
return { id: products.find((p) => p.id == reference.id)?.variation };
},
dimensions: () => {
return { size: "1", weight: 1 };
},
createdBy: () => {
return { email: "support@apollographql.com", totalProductsCreated: 1337 };
},
/** @type {(reference: any) => any} */
__resolveReference: (reference) => {
if (reference.id) return products.find((p) => p.id == reference.id);
else if (reference.sku && reference.package)
return products.find(
(p) => p.sku == reference.sku && p.package == reference.package
);
else
return products.find(
(p) => p.sku == reference.sku && p.variation == reference.variation.id
);
},
},
};

const server = new ApolloServer({
schema: buildFederatedSchema({ typeDefs, resolvers }),
});

server
.listen({ port })
.then(({ url }) => console.log(`Products subgraph ready at ${url}`));
12 changes: 12 additions & 0 deletions implementations/apollo-server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "apollo-server-implementation",
"type": "module",
"dependencies": {
"@apollo/federation": "^0.25.1",
"apollo-server": "^2.25.1",
"graphql": "^15.5.0"
},
"devDependencies": {
"typescript": "^4.3.2"
}
}