github.com/mstephano/gqlgen-schemagen@v0.0.0-20230113041936-dd2cd4ea46aa/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/mstephano/gqlgen-schemagen/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/mstephano/gqlgen
    39  ```
    40  
    41  Update the schema to reflect the federated example
    42  
    43  ```graphql
    44  type Review {
    45  	body: String
    46  	author: User @provides(fields: "username")
    47  	product: Product
    48  }
    49  
    50  extend type User @key(fields: "id") {
    51  	id: ID! @external # External directive not required for key fields in federation v2
    52  	reviews: [Review]
    53  }
    54  
    55  extend type Product @key(fields: "upc") {
    56  	upc: String! @external # External directive not required for key fields in federation v2
    57  	reviews: [Review]
    58  }
    59  ```
    60  
    61  and regenerate
    62  
    63  ```bash
    64  go run github.com/mstephano/gqlgen
    65  ```
    66  
    67  then implement the resolvers
    68  
    69  ```go
    70  // These two methods are required for gqlgen to resolve the internal id-only wrapper structs.
    71  // This boilerplate might be removed in a future version of gqlgen that can no-op id only nodes.
    72  func (r *entityResolver) FindProductByUpc(ctx context.Context, upc string) (*model.Product, error) {
    73  	return &model.Product{
    74  		Upc: upc,
    75  	}, nil
    76  }
    77  
    78  func (r *entityResolver) FindUserByID(ctx context.Context, id string) (*model.User, error) {
    79  	return &model.User{
    80  		ID: id,
    81  	}, nil
    82  }
    83  
    84  // Here we implement the stitched part of this service, returning reviews for a product. Of course normally you would
    85  // go back to the database, but we are just making some data up here.
    86  func (r *productResolver) Reviews(ctx context.Context, obj *model.Product) ([]*model.Review, error) {
    87  	switch obj.Upc {
    88  	case "top-1":
    89  		return []*model.Review{{
    90  			Body: "A highly effective form of birth control.",
    91  		}}, nil
    92  
    93  	case "top-2":
    94  		return []*model.Review{{
    95  			Body: "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.",
    96  		}}, nil
    97  
    98  	case "top-3":
    99  		return []*model.Review{{
   100  			Body: "This is the last straw. Hat you will wear. 11/10",
   101  		}}, nil
   102  
   103  	}
   104  	return nil, nil
   105  }
   106  
   107  func (r *userResolver) Reviews(ctx context.Context, obj *model.User) ([]*model.Review, error) {
   108  	if obj.ID == "1234" {
   109  		return []*model.Review{{
   110  			Body: "Has an odd fascination with hats.",
   111  		}}, nil
   112  	}
   113  	return nil, nil
   114  }
   115  ```
   116  
   117  > Note
   118  >
   119  > Repeat this step for each of the services in the apollo doc (accounts, products, reviews)
   120  
   121  ## Create the federation gateway
   122  
   123  ```bash
   124  npm install --save @apollo/gateway apollo-server graphql
   125  ```
   126  
   127  ```typescript
   128  const { ApolloServer } = require("apollo-server");
   129  const { ApolloGateway } = require("@apollo/gateway");
   130  
   131  const gateway = new ApolloGateway({
   132  	serviceList: [
   133  		{ name: "accounts", url: "http://localhost:4001/query" },
   134  		{ name: "products", url: "http://localhost:4002/query" },
   135  		{ name: "reviews", url: "http://localhost:4003/query" },
   136  	],
   137  });
   138  
   139  const server = new ApolloServer({
   140  	gateway,
   141  
   142  	subscriptions: false,
   143  });
   144  
   145  server.listen().then(({ url }) => {
   146  	console.log(`🚀 Server ready at ${url}`);
   147  });
   148  ```
   149  
   150  ## Start all the services
   151  
   152  In separate terminals:
   153  
   154  ```bash
   155  go run accounts/server.go
   156  go run products/server.go
   157  go run reviews/server.go
   158  node gateway/index.js
   159  ```
   160  
   161  ## Query the federated gateway
   162  
   163  The examples from the apollo doc should all work, eg
   164  
   165  ```graphql
   166  query {
   167  	me {
   168  		username
   169  		reviews {
   170  			body
   171  			product {
   172  				name
   173  				upc
   174  			}
   175  		}
   176  	}
   177  }
   178  ```
   179  
   180  should return
   181  
   182  ```json
   183  {
   184  	"data": {
   185  		"me": {
   186  			"username": "Me",
   187  			"reviews": [
   188  				{
   189  					"body": "A highly effective form of birth control.",
   190  					"product": {
   191  						"name": "Trilby",
   192  						"upc": "top-1"
   193  					}
   194  				},
   195  				{
   196  					"body": "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.",
   197  					"product": {
   198  						"name": "Trilby",
   199  						"upc": "top-1"
   200  					}
   201  				}
   202  			]
   203  		}
   204  	}
   205  }
   206  ```