Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions composition-js/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# @apollo/composition

Apollo Federation composition utilities for building supergraphs from subgraphs.

## Features

- **Subgraph Composition**: Merge multiple subgraphs into a single supergraph
- **Schema Validation**: Validate subgraph compatibility and federation rules
- **Metadata Overlay**: Apply directives to subgraphs during composition
- **Federation 1 & 2 Support**: Handle both Federation 1 and Federation 2 subgraphs

## Installation

```bash
npm install @apollo/composition
```

## Basic Usage

```typescript
import { composeServices } from '@apollo/composition';
import { gql } from 'graphql-tag';

const subgraph1 = {
name: 'users',
url: 'http://localhost:4001',
typeDefs: gql`
type Query {
user: User!
}

type User @key(fields: "id") {
id: ID!
name: String!
}
`
};

const subgraph2 = {
name: 'accounts',
url: 'http://localhost:4002',
typeDefs: gql`
type User @key(fields: "id") {
id: ID!
balance: Float!
}
`
};

const result = composeServices([subgraph1, subgraph2]);

if (result.errors) {
console.error('Composition failed:', result.errors);
} else {
console.log('Supergraph SDL:', result.supergraphSdl);
}
```

## Metadata Overlay

The composition system supports applying metadata overlays to subgraphs during the composition process. This allows you to inject directives (like `@key`, `@external`, etc.) into subgraphs without modifying the original schema files.

### Using Metadata Overlay

```typescript
import { composeServices, CompositionOptions } from '@apollo/composition';

// Subgraphs without federation directives
const subgraph1 = {
name: 'users',
url: 'http://localhost:4001',
typeDefs: gql`
type Query {
user: User!
}

type User {
id: ID!
name: String!
email: String!
}
`
};

// Metadata overlay to add @key and @external directives
const metadataOverlay = JSON.stringify({
name: "UserServiceOverlay",
version: "1.0.0",
subgraphs: {
"users": {
types: {
"User": {
directives: [
{
name: "key",
args: { "fields": "id" }
}
],
fields: {
"email": {
directives: [
{ "name": "external" }
]
}
}
}
}
}
}
});

const options: CompositionOptions = {
metadataOverlay
};

const result = composeServices([subgraph1], options);
```

### Metadata Overlay Format

The metadata overlay is a JSON object with the following structure:

```json
{
"name": "OverlayName",
"version": "1.0.0",
"subgraphs": {
"subgraph-name": {
"types": {
"TypeName": {
"directives": [
{
"name": "directiveName",
"args": { "argName": "argValue" }
}
],
"fields": {
"fieldName": {
"directives": [
{
"name": "directiveName",
"args": { "argName": "argValue" }
}
]
}
}
}
}
}
}
}
```

### When to Use Metadata Overlay

- **Legacy Integration**: When working with existing subgraphs that don't have federation directives
- **Environment-Specific Configuration**: Different overlay configurations for different environments
- **Temporary Modifications**: Testing federation changes without modifying source schemas
- **Third-Party Subgraphs**: Adding federation metadata to subgraphs you don't control

## API Reference

### `composeServices(services, options?)`

Compose a supergraph from service definitions.

**Parameters:**
- `services`: Array of service definitions
- `options`: Optional composition options

**Returns:**
- `CompositionResult` - Success with schema and SDL, or failure with errors

### `CompositionOptions`

```typescript
interface CompositionOptions {
sdlPrintOptions?: PrintOptions;
allowedFieldTypeMergingSubtypingRules?: SubtypingRule[];
runSatisfiability?: boolean;
maxValidationSubgraphPaths?: number;
metadataOverlay?: string; // JSON string of metadata overlay
}
```

## Error Handling

The composition process validates:

- Subgraph compatibility
- Federation directive usage
- Type merging rules
- Metadata overlay format and application

Errors are returned as `GraphQLError[]` with detailed messages about what went wrong.

## Examples

See the `examples/` directory for complete working examples:

- `metadata-overlay-example.ts` - Using metadata overlay in composition
85 changes: 85 additions & 0 deletions composition-js/examples/metadata-overlay-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { composeServices, CompositionOptions } from '../src/compose';
import { gql } from 'graphql-tag';

// Example subgraphs without @key directives
const subgraph1 = {
name: 'users',
url: 'http://localhost:4001',
typeDefs: gql`
type Query {
user: User!
}

type User {
id: ID!
name: String!
email: String!
}
`
};

const subgraph2 = {
name: 'accounts',
url: 'http://localhost:4002',
typeDefs: gql`
type User {
id: ID!
balance: Float!
}
`
};

// Metadata overlay to add @key directives
const metadataOverlay = JSON.stringify({
name: "UserServiceOverlay",
version: "1.0.0",
subgraphs: {
"users": {
types: {
"User": {
directives: [
{
name: "key",
args: { "fields": "id" }
}
],
fields: {
"email": {
directives: [
{ "name": "external" }
]
}
}
}
}
},
"accounts": {
types: {
"User": {
directives: [
{
name: "key",
args: { "fields": "id" }
}
]
}
}
}
}
});

// Composition options with metadata overlay
const options: CompositionOptions = {
metadataOverlay
};

// Compose with metadata overlay
const result = composeServices([subgraph1, subgraph2], options);

if (result.errors) {
console.error('Composition failed:', result.errors);
} else {
console.log('Composition succeeded!');
console.log('Supergraph SDL:');
console.log(result.supergraphSdl);
}
3 changes: 2 additions & 1 deletion composition-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
},
"dependencies": {
"@apollo/federation-internals": "2.11.2",
"@apollo/query-graphs": "2.11.2"
"@apollo/query-graphs": "2.11.2",
"@apollo/metadata-overlay": "2.11.2"
},
"peerDependencies": {
"graphql": "^16.5.0"
Expand Down
Loading