Skip to content

Commit

Permalink
[docs] cleanup project documentation (#205)
Browse files Browse the repository at this point in the history
Cleaned up README and added new CONTRIBUTING doc (that also includes how to release this project).
  • Loading branch information
dariuszkuc committed Jun 3, 2022
1 parent 118c896 commit c1333af
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 75 deletions.
93 changes: 93 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Contributing to Federation JVM

The Apollo team welcomes contributions of all kinds, including bug reports, documentation, test cases, bug fixes, and features. There are just a few guidelines you need to follow which are described in detail below.

If you want to discuss the project or just say hi, stop by [the Apollo community forums](https://community.apollographql.com/).

## Workflow

We love Github issues! Before working on any new features, please open an issue so that we can agree on the direction, and hopefully avoid investing a lot of time on a feature that might need reworking.

Small pull requests for things like typos, bugfixes, etc are always welcome.

Please note that we will not accept pull requests for style changes.

### Fork this repo

You should create a fork of this project in your account and work from there. You can create a fork by clicking the fork button in GitHub.

### One feature, one branch

Work for each new feature/issue should occur in its own branch. To create a new branch from the command line:

```shell
git checkout -b my-new-feature
```
where "my-new-feature" describes what you're working on.

### Verify your changes locally

You can use Gradle to build all the modules from the root directory

```shell
./gradlew clean build
```

> NOTE: in order to ensure you use the right version of Gradle we highly recommend to use the provided wrapper scripts
### Add tests for any bug fixes or new functionality

#### Unit Tests

We are using [JUnit](https://junit.org/junit5/) and [jacoco](https://www.eclemma.org/jacoco/) for our main testing libraries. This ensures we have good code coverage and can easily test all cases of schema federation.

To run tests:

```shell
./gradlew check
```

#### Linting
We are using [Spotless](https://github.com/diffplug/spotless/) to apply [Google Java Format](https://github.com/google/google-java-format) for code style checking and linting.

**Note**:
Spotless verification tasks will be run as part of the build whenever it includes `check` task (e.g. `build` task will also execute `check` task). If you want to run linting manually, run the command

```shell
./gradlew spotlessCheck
```

`spotlessCheck` task will verify whether source code is formatted according to the Google Java Format style rules. In order to automatically apply Google style formatting, run the command

```shell
./gradlew spotlessApply
```

### Add documentation for new or updated functionality

Please add appropriate javadocs in the source code and ask the maintainers to update the documentation with any relevant information.

### Merging your contribution

Create a new pull request (with appropriate labels) and your code will be reviewed by the maintainers. They will confirm at least the following:

- Tests run successfully (unit, coverage, integration, style)
- Contribution policy has been followed
- Apollo [CLA](https://contribute.apollographql.com/) is signed

A maintainer will need to sign off on your pull request before it can be merged.

## Releasing

In order to [release a new version](https://github.com/apollographql/federation-jvm/releases) we need to draft a new release
and tag the commit. Releases are following [semantic versioning](https://semver.org/) and specify major, minor and patch version.

Once release is published it will trigger corresponding [Github Action](https://github.com/apollographql/federation-jvm/blob/master/.github/workflows/release.yml)
based on the published release event. Release workflow will then proceed to build and publish all library artifacts to [Maven Central](https://central.sonatype.org/).

### Release requirements

- tag should specify newly released library version that is following [semantic versioning](https://semver.org/)
- tag and release name should match
- release should contain the information about all the change sets that were included in the given release. We are using `release-drafter` to help automatically
collect this information and generate automatic release notes.
208 changes: 165 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,82 +5,180 @@

# Apollo Federation on the JVM

Packages published to Maven Central. Note that older versions of
this package may only be available in JCenter, but we are planning to republish these versions to Maven Central.
[**Apollo Federation**](https://www.apollographql.com/docs/federation/) is a powerful, open architecture that helps you create a **unified supergraph** that combines multiple GraphQL APIs.
`graphql-java-support` provides Apollo Federation support for building subgraphs in the `graphql-java` ecosystem. Individual subgraphs can be run independently of each other but can also specify
relationships to the other subgraphs by using Federated directives. See [Apollo Federation documentation](https://www.apollographql.com/docs/federation/) for details.

```mermaid
graph BT;
gateway([Supergraph<br/>gateway]);
serviceA[Users<br/>subgraph];
serviceB[Products<br/>subgraph];
serviceC[Reviews<br/>subgraph];
gateway --- serviceA & serviceB & serviceC;
```

`graphql-java-support` is built on top of `graphql-java` and provides transformation logic to make your GraphQL schemas Federation compatible. `SchemaTransformer` adds common Federation
type definitions (e.g. `_Any` scalar, `_Entity` union, Federation directives, etc) and allows you to easily specify your Federated entity resolvers.

An example of [graphql-spring-boot](https://www.graphql-java-kickstart.com/spring-boot/) microservice is available
in [spring-example](spring-example).
This project also provides a set of Federation aware instrumentations:

**👍👎 Let us know what you think!**
* `CacheControlInstrumentation` - instrumentation that computes a max age for an operation based on `@cacheControl` directives
* `FederatedTracingInstrumentation` - instrumentation that generates trace information for federated operations

_We're looking for developers to participate in a 75 minute remote research interview to learn understand the challenges around using and adopting GraphQL. Take the [quick survey here](https://www.surveymonkey.com/r/TZMXTHJ) and we'll follow up by email_
## Installation

Federation JVM libraries are published to [Maven Central](https://search.maven.org/search?q=g:com.apollographql.federation%20AND%20a:federation-graphql-java-support).
Using a JVM dependency manager, link `graphql-java-support` to your project.

## Getting started
With Maven:

### Dependency management with Gradle
```xml
<dependency>
<groupId>com.apollographql.federation</groupId>
<artifactId>federation-graphql-java-support</artifactId>
<version>${latestVersion}</version>
</dependency>
```

Make sure Maven Central is among your repositories:
With Gradle (Groovy):

```groovy
repositories {
mavenCentral()
implementation 'com.apollographql.federation:federation-graphql-java-support:$latestVersion'
```

## Usage

Additional documentation on the Apollo Federation and JVM usage can be found on the [Apollo Documentation Portal](https://www.apollographql.com/docs/federation/).

Federation JVM example integrations

* [Spring GraphQL Federation Example](https://github.com/apollographql/federation-jvm-spring-example)
* [Netflix DGS Federation Example](https://github.com/Netflix/dgs-federation-example)
* [GraphQL Java Kickstart Federation Example](https://github.com/setchy/graphql-java-kickstart-federation-example)

### Creating Federated Schemas

Using `graphql-java` (or [your](https://docs.spring.io/spring-graphql/docs/current/reference/html/) [framework](https://netflix.github.io/dgs/) of [choice](https://www.graphql-java-kickstart.com/spring-boot/))
we first need to create a GraphQL schema.

Assuming there is already a subgraph that defines a base `Product` type

```graphql
# product subgraph
type Query {
product(id: ID!): Product
}

type Product @key(fields: "id") {
id: ID!,
description: String
}
```

Add a dependency to `graphql-java-support`:
We can create another subgraph that extends `Product` type and adds the `reviews` field.

```groovy
dependencies {
implementation 'com.apollographql.federation:federation-graphql-java-support:2.0.0'
```graphql
# reviews subgraph
type Product @extends @key(fields: "id") {
id: ID! @external
reviews: [Review!]!
}

type Review {
id: ID!
text: String
rating: Int!
}
```

### graphql-java schema transformation
>NOTE: This subgraph does not specify any top level queries.

Using the above schema file, we first need to generate the `TypeDefinitionRegistry` and `RuntimeWiring` objects.

```java
SchemaParser parser = new SchemaParser();
TypeDefinitionRegistry typeDefinitionRegistry = parser.parse(Paths.get("schema.graphqls").toFile());
RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring().build();
```

We can then generate Federation compatible schema using schema transformer. In order to be able to resolve the federated `Product` type, we need to provide `TypeResolver` to resolve [`_Entity`](https://www.apollographql.com/docs/federation/federation-spec/#union-_entity)
union type and a `DataFetcher` to resolve [`_entities`](https://www.apollographql.com/docs/federation/federation-spec/#query_entities) query.

`graphql-java-support` produces a `graphql.schema.GraphQLSchema` by transforming your existing schema in accordance to
the [federation specification](https://www.apollographql.com/docs/apollo-server/federation/federation-spec/). It follows
the `Builder` pattern.
```java
DataFetcher entityDataFetcher = env -> {
List<Map<String, Object>> representations = env.getArgument(_Entity.argumentName);
return representations.stream()
.map(representation -> {
if ("Product".equals(representation.get("__typename"))) {
return new Product((String)representation.get("id"));
}
return null;
})
.collect(Collectors.toList());
};
TypeResolver entityTypeResolver = env -> {
final Object src = env.getObject();
if (src instanceof Product) {
return env.getSchema()
.getObjectType("Product");
}
return null;
};

GraphQLSchema federatedSchema = Federation.transform(typeDefinitionRegistry, runtimeWiring)
.fetchEntities(entityDataFetcher)
.resolveEntityType(entityTypeResolver)
.build();
```

Start with `com.apollographql.federation.graphqljava.Federation.transform(…)`, which can receive either:
This will generate a schema with additional federated info.

- A `GraphQLSchema`;
- A `TypeDefinitionRegistry`, optionally with a `RuntimeWiring`;
- A String, Reader, or File declaring the schema using
the [Schema Definition Language](https://www.apollographql.com/docs/apollo-server/essentials/schema/#schema-definition-language),
optionally with a `RuntimeWiring`;
```graphql
union _Entity = Product

and returns a `SchemaTransformer`.
type Product @extends @key(fields : "id") {
id: ID! @external
reviews: [Review!]!
}

If your schema does not contain any types annotated with the `@key` directive, nothing else is required. You can build a
transformed `GraphQLSchema` with `SchemaTransformer#build()`, and confirm it exposes `query { _schema { sdl } }`.
type Query {
_entities(representations: [_Any!]!): [_Entity]!
_service: _Service
}

Otherwise, all types annotated with `@key` will be part of the `_Entity` union type, and reachable
through `query { _entities(representations: [Any!]!) { … } }`. Before calling `SchemaTransformer#build()`, you will also
need to provide:
type Review {
id: ID!
rating: Int!
text: String
}

- A `TypeResolver` for `_Entity` using `SchemaTransformer#resolveEntityType(TypeResolver)`;
- A `DataFetcher` or `DataFetcherFactory` for `_entities`
using `SchemaTransformer#fetchEntities(DataFetcher|DataFetcherFactory)`.
type _Service {
sdl: String!
}

A minimal but complete example is available in
[AppConfiguration](spring-example/src/main/java/com/apollographql/federation/springexample/graphqljava/AppConfiguration.java).
scalar _Any

### Federated tracing
scalar _FieldSet
```

### Instrumentation

#### Federated Tracing

To make your server generate performance traces and return them along with responses to the Apollo Gateway (which then
can send them to Apollo Graph Manager), install the `FederatedTracingInstrumentation` into your `GraphQL` object:
[Tracing your GraphQL queries](https://www.apollographql.com/docs/federation/metrics) can provide you detailed insights into your GraphQL layer's performance and usage. Single federated query may
be executed against multiple GraphQL servers. Apollo Gateway provides ability to aggregate trace data generated by the subgraphs calls and then send them to [Apollo Studio](https://www.apollographql.com/docs/studio/)

To make your server generate performance traces and return them along with responses to the Apollo Gateway, install the `FederatedTracingInstrumentation` into your `GraphQL` object:

```java
GraphQL graphql = GraphQL.newGraphQL(graphQLSchema)
.instrumentation(new FederatedTracingInstrumentation())
.build();
```

It is generally desired to only create traces for requests that actually come from Apollo Gateway, as they aren't
helpful if you're connecting directly to your backend service for testing. In order for `FederatedTracingInstrumentation`
to know if the request is coming from Gateway, you should populate the tracing header information directly in the
`GraphQLContext` map.
It is generally desired to only create traces for requests that actually come from Apollo Gateway, as they aren't helpful if you're connecting directly to your backend service for testing. In order
for `FederatedTracingInstrumentation` to know if the request is coming from the Gateway, you should populate the tracing header information directly in the `GraphQLContext` map.

```java
Map<Object, Object> contextMap = new HashMap<>();
Expand All @@ -95,3 +193,27 @@ ExecutionInput executionInput = ExecutionInput.newExecutionInput()
.build();
graphql.executeAsync(executionInput);
```

## Contact

If you have a specific question about the library or code, please start a discussion in the [Apollo community forums](https://community.apollographql.com/).

## Contributing

To get started, please fork the repo and checkout a new branch. You can then build the library locally with Gradle

```shell
./gradlew clean build
```

See more info in [CONTRIBUTING.md](CONTRIBUTING.md).

After you have your local branch set up, take a look at our open issues to see where you can contribute.

## Security

For more info on how to contact the team for security issues, see our [Security Policy](https://github.com/apollographql/federation-jvm/security/policy).

## License

This library is licensed under [The MIT License (MIT)](LICENSE).
30 changes: 0 additions & 30 deletions RELEASING.md

This file was deleted.

2 changes: 0 additions & 2 deletions graphql-java-support/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import com.google.protobuf.gradle.generateProtoTasks
import com.google.protobuf.gradle.plugins
import com.google.protobuf.gradle.protobuf
import com.google.protobuf.gradle.protoc

Expand Down

0 comments on commit c1333af

Please sign in to comment.