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 ```