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