New to Telerik UI for ASP.NET MVC? Start a free 30-day trial

GraphQL Binding

Updated on Oct 27, 2026

The Telerik UI Grid supports multiple server-side binding approaches. With the DataSource .Custom() option, you can configure the Grid to run read and CRUD operations against a GraphQL endpoint.

What is GraphQL?

GraphQL is a query language for APIs and a runtime that fulfills client requests with existing data. It describes the available data clearly and returns only the fields requested by the client.

As an alternative to REST, GraphQL lets you fetch data from multiple related sources in a single request. A GraphQL query can access properties from one resource and follow references to related resources.

Implementing the Service

First, create a running service that follows GraphQL and .NET guidelines: Creating a GraphQL Backend on .NET

For a complete service implementation, review the public Telerik sample repository: Kendo UI Demos Service - graphql

Update Startup.cs to register the GraphQL services and schema, for example:

C#
        // Product
    services.AddTransient<IProductRepository, ProductRepository>();
        services.AddSingleton<ProductQuery>();
        services.AddSingleton<ProductMutation>();
        services.AddSingleton<ProductType>();
        services.AddSingleton<ProductInputType>();

        services.AddSingleton<ISchema>(new ProductsSchema(new FuncServiceProvider(type => services.BuildServiceProvider().GetService(type))));

Binding the Grid

To bind the Grid to GraphQL, configure the DataSource transport, schema, and request payload handlers.

Configuring the DataSource

Define the GraphQL endpoint URLs in the DataSource .Custom() transport configuration. When you enable editing, also configure .Schema() so the Grid can map fields and parse the response.

C#
    .DataSource(dataSource => dataSource
        .Custom()
        .PageSize(20)
        .Schema(schema =>
        {
            schema.Model(model =>
            {
                model.Id(p => p.ProductID);
                model.Field(p => p.ProductID).Editable(false).From("productID");
                model.Field(p => p.ProductName).From("productName");
                model.Field(p => p.UnitPrice).From("unitPrice");
                model.Field(p => p.UnitsInStock).From("unitsInStock");
            })
            .Data(d => "schemaData")
            .Total(t => "schemaTotal");
        })
        .Transport(transport => transport
            .Create(r => r
                .Url("https://demos.telerik.com/service/v2/graphql/")
                .ContentType("application/json")
                .Type(HttpVerbs.Post)
                .Data("additionalDataOnCreate")
            )
            .Read(r => r
                .Url("https://demos.telerik.com/service/v2/graphql/")
                .ContentType("application/json")
                .Type(HttpVerbs.Post)
                .Data("additionalDataOnRead")
            )
            .Update(r => r
                .Url("https://demos.telerik.com/service/v2/graphql/")
                .ContentType("application/json")
                .Type(HttpVerbs.Post)
                .Data("additionalDataOnUpdate")
            )
            .Destroy(r => r
                .Url("https://demos.telerik.com/service/v2/graphql/")
                .ContentType("application/json")
                .Type(HttpVerbs.Post)
                .Data("additionalDataOnDestroy")
            )
            .ParameterMap("parameterMap")
        )
    )

Handling Parameters

Use JavaScript helper functions to send GraphQL queries and map response data:

JS
<script>
    function additionalDataOnCreate(model) {
        var createQuery = "mutation CreateProductMutation($product: ProductInput!){" +
            "createProduct(product: $product){" +
                "productID," +
                "productName," +
                "unitPrice," +
                "unitsInStock" +
            "}" +
        "}";
        var queryFields = getQueryFields(model);

        return {
            query: createQuery,
            variables: { "product": queryFields }
        };
    }

    function additionalDataOnRead() {
        var readQuery = "query {" +
            "products { productID, productName, unitPrice, unitsInStock }" +
        "}";

        return { query: readQuery };
    }

    function additionalDataOnUpdate(model) {
        var updateQuery = "mutation UpdateProductMutation($product: ProductInput!){" +
            "updateProduct(product: $product){" +
                "productID," +
                "productName," +
                "unitPrice," +
                "unitsInStock" +
            "}" +
        "}";
        var queryFields = getQueryFields(model);

        return {
            query: updateQuery,
            variables: { "product": queryFields }
        };
    }

    function additionalDataOnDestroy(model) {
        var destroyQuery = "mutation DeleteProductMutation($product: ProductInput!){" +
            "deleteProduct(product: $product){" +
                "productID," +
                "productName," +
                "unitPrice," +
                "unitsInStock" +
            "}" +
        "}";
        var queryFields = getQueryFields(model);

        return {
            query: destroyQuery,
            variables: { "product": queryFields }
        };
    }

    function parameterMap(options, operation) {
        return kendo.stringify({
            query: options.query,
            variables: options.variables
        });
    }

    function schemaData(response) {
        var data = response.data;

        if (data.products) { return data.products; }
        else if (data.createProduct) { return data.createProduct; }
        else if (data.updateProduct) { return data.updateProduct; }
        else if (data.deleteProduct) { return data.deleteProduct; }
    }

    function schemaTotal(response) {
        return response.data.products.length;
    }

    function getQueryFields(model) {
        var fields = {
            "productID": model.productID,
            "productName": model.productName,
            "unitPrice": model.unitPrice,
            "unitsInStock": model.unitsInStock
        };

        return fields;
    }
</script>

See Also