Quantcast
Channel: Telerik Blogs
Viewing all articles
Browse latest Browse all 5210

How to Bind the Kendo UI Grid to a GraphQL API

$
0
0

Learn how to configure the Kendo UI Grid Component to easily consume data through GraphQL queries and mutations.

By now you have almost certainly heard of GraphQL, the runtime query language for APIs. With rapidly growing popularity, it is becoming an increasingly adopted standard for API development. This has generated demand for frameworks and UI tools that can easily consume the data from a GraphQL API – just like the Kendo UI Components can do, as we provide seamless integration through the DataSource component.

This blog provides a comprehensive guide on how to setup the Kendo UI Grid component to perform CRUD operations through GraphQL queries and mutations. It includes a sample application, code snippets and documentation resources to get you up and running with Kendo UI and GraphQL.

Why are Kendo UI Widgets Easy To Integrate with a GraphQL API?

The backbone of every data-driven Kendo UI Component is the DataSource. It possesses the agility to adapt to any data/service scenario and fully supports CRUD data operations. It is also highly configurable and provides tons of features for fine-tuning its behavior. This is also the main reason why consuming a GraphQL API is so easy with the DataSource abstraction.

Setup a GraphQL Service

First things first – we need to create a GraphQL service that can receive queries and mutations to validate and execute:

  1. Start by defining a type which describes the possible data that can be queried on the service:
    import {
        GraphQLObjectType,
        GraphQLString,
        GraphQLID,
        GraphQLFloat,
    } from'graphql';
      
    module.exports = new GraphQLObjectType({
        name: 'Product',
        fields: () => ({
            ProductID: { type: GraphQLID },
            ProductName: { type: GraphQLString },
            UnitPrice: { type: GraphQLFloat },
            UnitsInStock: { type: GraphQLFloat }
        })
    });

  2. Create queries for fetching the data and mutations for modifying the data server-side:
    const RootQuery = new GraphQLObjectType({
        name: 'RootQueryType',
        fields: {
            products: {
                type: new GraphQLList(Product),
                resolve(parent, args){
                    returnproducts;
                }
            }
        }
    });
      
    const Mutation = new GraphQLObjectType({
        name: 'Mutation',
        fields: {
            AddProduct: {
                type: Product,
                args:{
                    ProductName: { type: new GraphQLNonNull(GraphQLString) },
                    UnitPrice: { type: new GraphQLNonNull(GraphQLFloat) },
                    UnitsInStock: { type: new GraphQLNonNull(GraphQLFloat) }
                },
                resolve(parent, args) {
                    let newProduct = {
                        ProductID: uuidv1(),
                        ProductName: args.ProductName,
                        UnitsInStock: args.UnitsInStock,
                        UnitPrice: args.UnitPrice
                    }
                    products.unshift(newProduct);
      
                    returnnewProduct;
                }
            },
            UpdateProduct: {
                type: Product,
                args:{
                    ProductID: { type: new GraphQLNonNull(GraphQLID) },
                    ProductName: { type: new GraphQLNonNull(GraphQLString) },
                    UnitPrice: { type: new GraphQLNonNull(GraphQLFloat) },
                    UnitsInStock: { type: new GraphQLNonNull(GraphQLFloat) }
                },
                resolve(parent, args) {
                    let index= products.findIndex(product => product.ProductID == args.ProductID);
                    let product = products[index];
      
                    product.ProductName = args.ProductName;
                    product.UnitsInStock = args.UnitsInStock;
                    product.UnitPrice = args.UnitPrice;
      
                    returnproduct;
                }
            },
            DeleteProduct: {
                type: Product,
                args:{
                    ProductID: { type: new GraphQLNonNull(GraphQLID) }
                },
                resolve(parent, args) {
                    let index= products.findIndex(product => product.ProductID == args.ProductID);
                    products.splice(index, 1);
      
                    return{ ProductID: args.ProductID };
                }
            }
        }
    });
      
    module.exports = new GraphQLSchema({
        query: RootQuery,
        mutation: Mutation
    });

     

  3. Serve the GraphQL service over HTTP via a single endpoint which expresses the full set of its capabilities:

    import express from'express';
    import cors from'cors';
    import graphqlHTTP from'express-graphql';
    import schemafrom'./schema';
    import { createServer } from'http';
      
    const PORT = 3021;
      
    var app = express();
      
    app.use(cors());
      
    app.use('/graphql', graphqlHTTP({
        schema
    }));
      
    const server = createServer(app);
      
    server.listen(PORT, () => {
        console.log(`API Server isnow running onhttp://localhost:${PORT}/graphql`)
    });

For additional information on how to setup the server, required packages and the full GraphQL schema, refer to the source code of the sample application.

Configuring the Grid

To be able to use the Kendo UI Grid Component, just reference the required client-side resources of the framework:

Once you have the right setup, adding the Grid is as simple as placing a container element on the page and then initializing the widget with JavaScript:

<div id="content">
  <div id="grid"></div>
</div>
  
$(document).ready(function() {             
  $("#grid").kendoGrid({
    dataSource: dataSource,
    height: 550,
    groupable: true,
    sortable: true,
    pageable: true,
    toolbar: ["create"],
    editable: "inline",
    columns: [{
      field: "ProductID",
      title: "Product ID"
    },
    {
      field: "ProductName",
      title: "Product Name"
    },
    {
      field: "UnitPrice",
      title: "Unit Price"
    },
    {
      field: "UnitsInStock",
      title: "Units in stock"
    },
    {
      command: ["edit", "destroy"],
      title: "Options ",
      width: "250px"
    }]
  });
});
</script>

Using GraphQL on the Client

The wealth of configuration options that the DataSource offers allows you to easily integrate it to work with a GraphQL API and bind the Grid Component to it.

Compose Queries and Mutations

GraphQL is all about asking for specific fields on objects. To populate the Grid initially with records, we need to issue a query against the API to return the object types:

<script>
  varREAD_PRODUCTS_QUERY = "query {"+
    "products { ProductID, ProductName, UnitPrice, UnitsInStock }"+
  "}";
</script>

And then create the mutations for adding, updating and deleting the object type:

<script>       
  varADD_PRODUCT_QUERY = "mutation AddProduct($ProductName: String!, $UnitPrice: Float!, $UnitsInStock: Float!){"+
    "AddProduct(ProductName: $ProductName, UnitPrice: $UnitPrice, UnitsInStock: $UnitsInStock ){"+
      "ProductID,"+
      "ProductName,"+
      "UnitPrice,"+
      "UnitsInStock"+
    "}"+
  "}";
  
  varUPDATE_PRODUCT_QUERY = "mutation UpdateProduct($ProductID: ID!, $ProductName: String! ,$UnitPrice: Float!, $UnitsInStock: Float!){"+
    "UpdateProduct(ProductID: $ProductID, ProductName: $ProductName, UnitPrice: $UnitPrice, UnitsInStock: $UnitsInStock){"+
      "ProductID,"+
      "ProductName,"+
      "UnitPrice,"+
      "UnitsInStock"+
    "}"+
  "}";
  
  varDELETE_PRODUCT_QUERY = "mutation DeleteProduct($ProductID: ID!){"+
    "DeleteProduct(ProductID: $ProductID){"+
      "ProductID"+
    "}"+
  "}";
</script>

Consume the API

To request or modify data through a GraphQL query or mutation, all you have to do is to configure the transport.read method of the DataSource:

  • Set the content-type to “application/json.”
  • Set the request type to “POST.”
  • Pass the composed GraphQL query/mutation as “query” and the model data as “variables” parameters along with the requests to the remote service when performing CRUD operations. This is achieved through the transport.read’s data() method
<script>
    vardataSource = newkendo.data.DataSource({
        pageSize: 20,
        transport: {
            read: {
                contentType: "application/json",
                url: "http://localhost:3021/graphql",
                type: "POST",
                data: function() {
                    return{ query: READ_PRODUCTS_QUERY };
                }
            },
            update: {
                contentType: "application/json",
                url: "http://localhost:3021/graphql",
                type: "POST",
                data: function(model) {
                    return{
                        query: UPDATE_PRODUCT_QUERY,
                        variables: model
                    };
                }
            },
            destroy: {
                contentType: "application/json",
                url: "http://localhost:3021/graphql",
                type: "POST",
                data: function(model) {
                    return{
                        query: DELETE_PRODUCT_QUERY,
                        variables: model
                    };
                }
            },
            create: {
                contentType: "application/json",
                url: "http://localhost:3021/graphql",
                type: "POST",
                data: function(model) {
                    return{
                        query: ADD_PRODUCT_QUERY,
                        variables: model
                    };
                }
            },
            parameterMap: function(options, operation) {
                return  kendo.stringify(options);
            }
        },
        schema: {
            data: function(response) {
                vardata = response.data;
  
                if(data.products) {
                    returndata.products;
                } elseif(data.AddProduct) {
                    returndata.AddProduct;
                } elseif(data.UpdateProduct) {
                    returndata.UpdateProduct;
                } elseif(data.DeleteProduct){
                    returndata.DeleteProduct;
                }
            },
            model: {
                id: "ProductID",
                fields: {
                    ProductID: { type: "string", editable: false},
                    ProductName: { type: "string"},
                    UnitPrice: { type: "number"},
                    UnitsInStock: { type: "number"}
                }
            }
        }
    });
</script>

Format Request Parameters and Parse the Response

Beyond configuring the transports, there are also other features of the DataSource, like the parameterMap() and the schema options, that are useful for encoding the request parameters and parsing the API response:

Start Exploring the Grid

There you go – by simply setting up the DataSource we got the Grid up and running with a GraphQL API. From here on, you can start exploring the vast options of the Grid and also take advantage of the other 70+ ready-to-use Kendo UI components and easily bind them to a GraphQL service.

Additional Resources


Viewing all articles
Browse latest Browse all 5210

Trending Articles