github.com/niko0xdev/gqlgen@v0.17.55-0.20240120102243-2ecff98c3e37/docs/content/recipes/federation.md (about)

     1  ---
     2  title: 'Using Apollo federation gqlgen'
     3  description: How federate many services into a single graph using Apollo
     4  linkTitle: Apollo Federation
     5  menu: { main: { parent: 'recipes' } }
     6  ---
     7  
     8  In this quick guide we are going to implement the example [Apollo Federation](https://www.apollographql.com/docs/apollo-server/federation/introduction/)
     9  server in gqlgen. You can find the finished result in the [examples directory](https://github.com/niko0xdev/gqlgen/tree/master/_examples/federation).
    10  
    11  ## Enable federation
    12  
    13  Uncomment federation configuration in your `gqlgen.yml`
    14  
    15  ```yml
    16  # Uncomment to enable federation
    17  federation:
    18    filename: graph/federation.go
    19    package: graph
    20  ```
    21  
    22  ### Federation 2
    23  
    24  If you are using Apollo's Federation 2 standard, your schema should automatically be upgraded so long as you include the required `@link` directive within your schema. If you want to force Federation 2 composition, the `federation` configuration supports a `version` flag to override that. For example:
    25  
    26  ```yml
    27  federation:
    28    filename: graph/federation.go
    29    package: graph
    30    version: 2
    31  ```
    32  
    33  ## Create the federated servers
    34  
    35  For each server to be federated we will create a new gqlgen project.
    36  
    37  ```bash
    38  go run github.com/niko0xdev/gqlgen
    39  ```
    40  
    41  Update the schema to reflect the federated example
    42  ```graphql
    43  type Review {
    44    body: String
    45    author: User @provides(fields: "username")
    46    product: Product
    47  }
    48  
    49  extend type User @key(fields: "id") {
    50    id: ID! @external # External directive not required for key fields in federation v2
    51    reviews: [Review]
    52  }
    53  
    54  extend type Product @key(fields: "upc") {
    55    upc: String! @external # External directive not required for key fields in federation v2
    56    reviews: [Review]
    57  }
    58  ```
    59  
    60  
    61  and regenerate
    62  ```bash
    63  go run github.com/niko0xdev/gqlgen
    64  ```
    65  
    66  then implement the resolvers
    67  ```go
    68  // These two methods are required for gqlgen to resolve the internal id-only wrapper structs.
    69  // This boilerplate might be removed in a future version of gqlgen that can no-op id only nodes.
    70  func (r *entityResolver) FindProductByUpc(ctx context.Context, upc string) (*model.Product, error) {
    71  	return &model.Product{
    72  		Upc: upc,
    73  	}, nil
    74  }
    75  
    76  func (r *entityResolver) FindUserByID(ctx context.Context, id string) (*model.User, error) {
    77  	return &model.User{
    78  		ID: id,
    79  	}, nil
    80  }
    81  
    82  // Here we implement the stitched part of this service, returning reviews for a product. Of course normally you would
    83  // go back to the database, but we are just making some data up here.
    84  func (r *productResolver) Reviews(ctx context.Context, obj *model.Product) ([]*model.Review, error) {
    85  	switch obj.Upc {
    86  	case "top-1":
    87  		return []*model.Review{{
    88  			Body: "A highly effective form of birth control.",
    89  		}}, nil
    90  
    91  	case "top-2":
    92  		return []*model.Review{{
    93  			Body: "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.",
    94  		}}, nil
    95  
    96  	case "top-3":
    97  		return []*model.Review{{
    98  			Body: "This is the last straw. Hat you will wear. 11/10",
    99  		}}, nil
   100  
   101  	}
   102  	return nil, nil
   103  }
   104  
   105  func (r *userResolver) Reviews(ctx context.Context, obj *model.User) ([]*model.Review, error) {
   106  	if obj.ID == "1234" {
   107  		return []*model.Review{{
   108  			Body: "Has an odd fascination with hats.",
   109  		}}, nil
   110  	}
   111  	return nil, nil
   112  }
   113  ```
   114  
   115  > Note
   116  >
   117  > Repeat this step for each of the services in the apollo doc (accounts, products, reviews)
   118  
   119  ## Create the federation gateway
   120  
   121  ```bash
   122  npm install --save @apollo/gateway apollo-server graphql
   123  ```
   124  
   125  ```typescript
   126  const { ApolloServer } = require('apollo-server');
   127  const { ApolloGateway } = require("@apollo/gateway");
   128  
   129  const gateway = new ApolloGateway({
   130      serviceList: [
   131          { name: 'accounts', url: 'http://localhost:4001/query' },
   132          { name: 'products', url: 'http://localhost:4002/query' },
   133          { name: 'reviews', url: 'http://localhost:4003/query' }
   134      ],
   135  });
   136  
   137  const server = new ApolloServer({
   138      gateway,
   139  
   140      subscriptions: false,
   141  });
   142  
   143  server.listen().then(({ url }) => {
   144      console.log(`🚀 Server ready at ${url}`);
   145  });
   146  ```
   147  
   148  ## Start all the services
   149  
   150  In separate terminals:
   151  ```bash
   152  go run accounts/server.go
   153  go run products/server.go
   154  go run reviews/server.go
   155  node gateway/index.js
   156  ```
   157  
   158  ## Query the federated gateway
   159  
   160  The examples from the apollo doc should all work, eg
   161  
   162  ```graphql
   163  query {
   164    me {
   165      username
   166      reviews {
   167        body
   168        product {
   169          name
   170          upc
   171        }
   172      }
   173    }
   174  }
   175  ```
   176  
   177  should return
   178  
   179  ```json
   180  {
   181    "data": {
   182      "me": {
   183        "username": "Me",
   184        "reviews": [
   185          {
   186            "body": "A highly effective form of birth control.",
   187            "product": {
   188              "name": "Trilby",
   189              "upc": "top-1"
   190            }
   191          },
   192          {
   193            "body": "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.",
   194            "product": {
   195              "name": "Trilby",
   196              "upc": "top-1"
   197            }
   198          }
   199        ]
   200      }
   201    }
   202  }
   203  ```