Get started
Get started with GraphQL in Gloo Mesh Gateway by setting up API gateway and GraphQL server functionality for your apps in the same process.
Overview
In this getting started tutorial, you define schema fields for the Bookinfo sample app services, define GraphQL resolvers for each field, and map the schema definitions to the resolvers. Then, you set up routes to the GraphQL server and test the routes by sending GraphQL queries.
The following diagram shows how each of the Gloo custom resources that you create in this guide function together for your GraphQL setup.
- The routes in your
RouteTable
serve as the entry point which users can query. - When Gloo Mesh Gateway receives a query to your GraphQL route, it matches the request to a particular
GraphQLSchema
, which contains the mappings of GraphQL resolvers to API schema fields.- GraphQL resolvers are defined in a
GraphQLResolverMap
. Resolvers return results from the backing service for the API schema field that the resolver is mapped to. - API schema fields are defined in an
ApiDoc
. API schema fields determine what kind of data can be returned to a client that makes a GraphQL query to your endpoint.
- GraphQL resolvers are defined in a
- Any GraphQL policies you apply, such as to allow only specific queries or to cache queries, are applied when Gloo Mesh Gateway receives and processes the request.
Install GraphQL
Set the Gloo Mesh Gateway license with the Gloo GraphQL add-on as an environment variable.
export GLOO_MESH_GATEWAY_LICENSE_KEY=<key>
- To check that your Gloo Mesh Gateway license includes the Gloo GraphQL add-on:In the output, verify that your Gloo Mesh Gateway license is current and valid, and a GraphQL module is added to the license.
meshctl license check --key $(echo ${GLOO_MESH_GATEWAY_LICENSE_KEY} | base64 -w0)
INFO License key gloo-gateway-license-key for product gloo-gateway is valid. Expires at 08 Oct 24 12:31 CEST INFO License key gloo-gateway-license-key for gloo-gateway/graphql add-on is valid. Expires at 08 Oct 24 12:31 CEST SUCCESS Licenses are valid
- To purchase a license, contact an account representative.
- To check that your Gloo Mesh Gateway license includes the Gloo GraphQL add-on:
Install GraphQL by installing Gloo Mesh Gateway for the first time, or by upgrading your existing Gloo Mesh Gateway installation.
GraphQL is supported for gateway proxies that run the Solo distribution of Istio at version 1.16.1 or later.- Install: Install Gloo Mesh Gateway with one of the following options.
- Upgrade: If you purchased the Gloo GraphQL license module after you installed Gloo Mesh Gateway, upgrade your installation with the new Gloo Mesh Gateway license key.
Deploy the Bookinfo sample app and configure an HTTP or HTTPS listener on your ingress gateway.
Set up GraphQL resolvers with Bookinfo
Explore GraphQL resolution with the Bookinfo sample application.
In Gloo Mesh Gateway, you can create GraphQL REST and gRPC resolvers to fetch the data from your backend. In the following steps, you define schema fields for Bookinfo services, define GraphQL resolvers for each field, and map the schema definitions to the resolvers.
If you have not already, save the name of your cluster in an environment variable.
export CLUSTER_NAME=<cluster>
Start by defining your schema in an
ApiDoc
Gloo custom resource, which determines what kind of data can be returned to a client that makes a GraphQL query to your endpoint. In this schema definition:- The top-level query type defines the
productsForHome
field. This field references theProduct
object type, which means that when a client queriesproductsForHome
, fields fromProduct
are returned. - The
Product
object type defines theid
,title
,descriptionHtml
,reviews
, andratings
fields. Thereviews
andratings
fields reference object types of their own, which contain additional fields.
kubectl apply -f - <<EOF apiVersion: apimanagement.gloo.solo.io/v2 kind: ApiDoc metadata: name: bookinfo-rest-apidoc namespace: bookinfo spec: graphql: schemaDefinition: |- # Top-level query type type Query { """Description of a book in HTML""" productsForHome: [Product] } # Product object type """Each book has a product entry""" type Product { """Unique identifier for books""" id: String """The book title""" title: String """Description of a book in HTML""" descriptionHtml: String """List of reader reviews for this book. Queries the reviews REST service""" reviews: [Review] """List of reader ratings for this book. Queries the ratings REST service""" ratings: [Rating] } """A book review""" type Review { """Name of the reviewer""" reviewer: String """Review details""" text: String "Reviewer Rating, this field is provided by the reviews REST service, which queries the ratings REST service" rating: ReviewerRating } type ReviewerRating { stars: Int color: String } """A book rating""" type Rating { """Name of the user peforming the rating""" reviewer: String """Number of stars for this rating""" numStars: Int } EOF
- The top-level query type defines the
Define the resolvers for the schema fields in a
GraphQLResolverMap
Gloo custom resource. A resolver is responsible for returning results from the backing service for the field that the resolver is mapped to. In this resolver map:- For the
productsForHome
field in the top-level query type, theproductpage
Bookinfo service is defined as the resolver. In other words, when a client queriesproductsForHome
, theproductpage
service resolves this request and fetches information from theProduct
type. - For the
Product
object type, theratings
andreviews
Bookinfo services are defined as resolvers for theratings
andreviews
fields. In other words, when theproductpage
service fetches information about theProduct
type, theratings
andreviews
services return information for the product’sratings
andreviews
fields. - For
ratings
andreviews
, aresolverResultTransform
jq filter is applied to the results for each.- The result data from
ratings
is not formatted in a way that the client can understand, so this jq filter reformats the result data so that it is returned in sets of entries for each reviewer and their rating. For example, the response is transformed such as:{"reviewer":"Reviewer1","numStars":5},{"reviewer":"Reviewer2","numStars":4}
. - The result data from
reviews
is typically formatted as{"id": 0, "reviews": { /*review content */}}
. This jq filter reformats the result data to only return thereviews
field content, without theid
.
- The result data from
kubectl apply -f - <<EOF apiVersion: apimanagement.gloo.solo.io/v2 kind: GraphQLResolverMap metadata: name: bookinfo-rest-resolvermap namespace: bookinfo spec: types: # Top-level query type Query: fields: productsForHome: resolvers: - restResolver: destinations: - port: number: 9080 ref: name: productpage namespace: bookinfo cluster: $CLUSTER_NAME request: headers: :path: jq: '"/api/v1/products"' # Product object type Product: fields: ratings: resolvers: - resolverResultTransform: jq: '.resolverResultVar.ratings | to_entries | map(.reviewer=.key | .numStars=.value | del(.key,.value))' restResolver: destinations: - port: number: 9080 ref: name: ratings namespace: bookinfo cluster: $CLUSTER_NAME request: headers: :path: jq: '"/ratings/" + (.parentVar.id | tostring)' variables: parentVar: graphqlParent: {} resolverResultVar: resolverResult: {} reviews: resolvers: - resolverResultTransform: jq: '.resolverResultVar.reviews' restResolver: destinations: - port: number: 9080 ref: name: reviews namespace: bookinfo cluster: $CLUSTER_NAME request: headers: :path: jq: '"/reviews/" + (.parentVar.id | tostring)' variables: parentVar: graphqlParent: {} resolverResultVar: resolverResult: {} EOF
- For the
Create a
GraphQLSchema
Gloo CR to map the types and fields from your schema definition that you defined in step 1 to the resolvers that you defined in step 2. TheGraphQLSchema
CR ensures that the GraphQL resolver services can access the field information for each type.kubectl apply -f - <<EOF apiVersion: apimanagement.gloo.solo.io/v2 kind: GraphQLSchema metadata: name: bookinfo-rest-graphqlschema namespace: bookinfo spec: resolved: options: {} resolverMapRefs: - name: bookinfo-rest-resolvermap namespace: bookinfo clusterName: $CLUSTER_NAME schemaRef: name: bookinfo-rest-apidoc namespace: bookinfo clusterName: $CLUSTER_NAME EOF
Route to the GraphQL server
Set up routes to the GraphQL server and test the routes by sending GraphQL queries.
Create a
RouteTable
resource with agraphql-bookinfo
destination. This route table ensures that all GraphQL queries to the/graphql
path are now handled by the GraphQL server in the gateway, which uses the resolvers and schema you referenced in yourGraphQLSchema
.kubectl apply -f - <<EOF apiVersion: networking.gloo.solo.io/v2 kind: RouteTable metadata: name: graphql-bookinfo namespace: bookinfo spec: hosts: - www.example.com http: - name: graphql-bookinfo labels: route: graphql-bookinfo graphql: schema: name: bookinfo-rest-graphqlschema namespace: bookinfo clusterName: $CLUSTER_NAME matchers: - uri: prefix: /graphql virtualGateways: - name: istio-ingressgateway namespace: bookinfo EOF
Get the external address of your ingress gateway to test the
/graphql
route.export INGRESS_GW_ADDRESS=$(kubectl get svc -n gloo-mesh-gateways istio-ingressgateway -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}") echo $INGRESS_GW_ADDRESS
Send a request to the GraphQL endpoint to verify that the request is successfully resolved by the gateway.
In the JSON response, note that only the information you queried is returned:{"data":{"productsForHome":[{"title":"The Comedy of Errors","ratings":[{"reviewer":"Reviewer1","numStars":5},{"reviewer":"Reviewer2","numStars":4}]}]}}
Next steps
Now that you’ve tried out GraphQL with Gloo Mesh Gateway, check out the following pages to configure your own services for GraphQL integration.
- Visualize your GraphQL services in the UI.
- Configure further details for the API schema and resolvers for your GraphQL API, including adding
jq
transformations to your resolver maps. - Apply GraphQL policies to allow only specific queries or cache queries.
- Review the Gloo Mesh Gateway API reference for GraphQL.
Cleanup
You can optionally remove the resources that you set up as part of this guide.
kubectl delete ApiDoc -n bookinfo bookinfo-rest-apidoc
kubectl delete GraphQLResolverMap -n bookinfo bookinfo-rest-resolvermap
kubectl delete GraphQLSchema -n bookinfo bookinfo-rest-graphqlschema
kubectl delete RouteTable -n bookinfo graphql-bookinfo