WebApiAdaptor in Syncfusion® React Grid Component
17 Mar 202524 minutes to read
The WebApiAdaptor
is an extension of the ODataAdaptor
, designed to interact with Web APIs created with OData endpoints. This adaptor ensures seamless communication between Syncfusion® Grid and OData-endpoint based Web APIs, enabling efficient data retrieval and manipulation. For successful integration, the endpoint must be capable of understanding OData-formatted queries sent along with the request.
To enable the OData query option for a Web API, please refer to the corresponding documentation, which provides detailed instructions on configuring the endpoint to understand OData-formatted queries.
This section describes a step-by-step process for retrieving data service using WebApiAdaptor
, then binding it to the React Grid component to facilitate data and CRUD operations.
Creating a Web API service
To configure a server for use with Syncfusion® React Grid, you need to follow the below steps:
1. Project Creation:
Open Visual Studio and create an React and ASP.NET Core project named WebApiAdaptor. To create an React and ASP.NET Core application, follow the documentation link for detailed steps.
2. Model Class Creation:
Create a model class named OrdersDetails.cs
in the server-side Models folder to represent the order data.
namespace WebApiAdaptor.Server.Models
{
public class OrdersDetails
{
public static List<OrdersDetails> order = new List<OrdersDetails>();
public OrdersDetails()
{
}
public OrdersDetails(
int OrderID, string CustomerId, int EmployeeId, double Freight, bool Verified,
DateTime OrderDate, string ShipCity, string ShipName, string ShipCountry,
DateTime ShippedDate, string ShipAddress)
{
this.OrderID = OrderID;
this.CustomerID = CustomerId;
this.EmployeeID = EmployeeId;
this.Freight = Freight;
this.ShipCity = ShipCity;
this.Verified = Verified;
this.OrderDate = OrderDate;
this.ShipName = ShipName;
this.ShipCountry = ShipCountry;
this.ShippedDate = ShippedDate;
this.ShipAddress = ShipAddress;
}
public static List<OrdersDetails> GetAllRecords()
{
if (order.Count() == 0)
{
int code = 10000;
for (int i = 1; i < 10; i++)
{
order.Add(new OrdersDetails(code + 1, "ALFKI", i + 0, 2.3 * i, false, new DateTime(1991, 05, 15), "Berlin", "Simons bistro", "Denmark", new DateTime(1996, 7, 16), "Kirchgasse 6"));
order.Add(new OrdersDetails(code + 2, "ANATR", i + 2, 3.3 * i, true, new DateTime(1990, 04, 04), "Madrid", "Queen Cozinha", "Brazil", new DateTime(1996, 9, 11), "Avda. Azteca 123"));
order.Add(new OrdersDetails(code + 3, "ANTON", i + 1, 4.3 * i, true, new DateTime(1957, 11, 30), "Cholchester", "Frankenversand", "Germany", new DateTime(1996, 10, 7), "Carrera 52 con Ave. Bolívar #65-98 Llano Largo"));
order.Add(new OrdersDetails(code + 4, "BLONP", i + 3, 5.3 * i, false, new DateTime(1930, 10, 22), "Marseille", "Ernst Handel", "Austria", new DateTime(1996, 12, 30), "Magazinweg 7"));
order.Add(new OrdersDetails(code + 5, "BOLID", i + 4, 6.3 * i, true, new DateTime(1953, 02, 18), "Tsawassen", "Hanari Carnes", "Switzerland", new DateTime(1997, 12, 3), "1029 - 12th Ave. S."));
code += 5;
}
}
return order;
}
public int? OrderID { get; set; }
public string? CustomerID { get; set; }
public int? EmployeeID { get; set; }
public double? Freight { get; set; }
public string? ShipCity { get; set; }
public bool? Verified { get; set; }
public DateTime OrderDate { get; set; }
public string? ShipName { get; set; }
public string? ShipCountry { get; set; }
public DateTime ShippedDate { get; set; }
public string? ShipAddress { get; set; }
}
}
3. API Controller Creation:
Create a file named OrdersController.cs
under the Controllers folder. This controller will handle data communication with the React Grid component. Implement the Get method in the controller to return the data in JSON format, including the Items and Count properties as required by WebApiAdaptor
.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using WebApiAdaptor.Server.Models;
namespace WebApiAdaptor.Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class OrdersController : ControllerBase
{
[HttpGet]
public object Get()
{
var data = OrdersDetails.GetAllRecords().ToList();
return new { Items = data, Count = data.Count() };
}
}
}
4. Run the Application:
Run the application in Visual Studio. It will be accessible on a URL like https://localhost:xxxx.
After running the application, you can verify that the server-side API controller is successfully returning the order data in the URL(https://localhost:xxxx/api/Orders). Here xxxx denotes the port number.
Connecting Syncfusion® React Grid to an API service
To integrate the Syncfusion® Grid component into your React and ASP.NET Core project using Visual Studio, follow the below steps:
Step 1: Install syncfusion® package
Open your terminal in the project’s root directory of client folder and install the required Syncfusion® packages using npm:
npm install @syncfusion/ej2-react-grids --save
npm install @syncfusion/ej2-data --save
Step 2: Adding CSS reference
Include the necessary CSS files in your styles.css
file to style the Syncfusion® React components:
@import '../node_modules/@syncfusion/ej2-base/styles/material.css';
@import '../node_modules/@syncfusion/ej2-buttons/styles/material.css';
@import '../node_modules/@syncfusion/ej2-calendars/styles/material.css';
@import '../node_modules/@syncfusion/ej2-dropdowns/styles/material.css';
@import '../node_modules/@syncfusion/ej2-inputs/styles/material.css';
@import '../node_modules/@syncfusion/ej2-navigations/styles/material.css';
@import '../node_modules/@syncfusion/ej2-popups/styles/material.css';
@import '../node_modules/@syncfusion/ej2-splitbuttons/styles/material.css';
@import '../node_modules/@syncfusion/ej2-react-grids/styles/material.css';
Step 3: Adding Syncfusion® component
In your component file (e.g., App.ts), import DataManager
and WebApiAdaptor
from @syncfusion/ej2-data
. Create a DataManager
instance specifying the URL of your API endpoint(https:localhost:xxxx/api/Orders) using the url
property and set the adaptor WebApiAdaptor
.
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
import { GridComponent, ColumnsDirective, ColumnDirective } from '@syncfusion/ej2-react-grids';
function App() {
const data = new DataManager({
url:'https://localhost:xxxx/api/Orders', // Here xxxx represents the port number
adaptor: new WebApiAdaptor()
});
return <GridComponent dataSource={data} height={320}>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' isPrimaryKey={true} width='150'textAlign='Right'></ColumnDirective>
<ColumnDirective field='CustomerID' headerText='Customer ID' width='150'></ColumnDirective>
<ColumnDirective field='ShipCity' headerText='Ship City' width='150'/>
<ColumnDirective field='ShipCountry' headerText='Ship Country' width='150'/>
</ColumnsDirective>
</GridComponent>
};
export default App;
Replace https://localhost:xxxx/api/Orders with the actual URL of your API endpoint that provides the data in a consumable format (e.g., JSON).
Run the application in Visual Studio. It will be accessible on a URL like https://localhost:xxxx.
Ensure your API service is configured to handle CORS (Cross-Origin Resource Sharing) if necessary.
[program.cs]
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
});
});
var app = builder.Build();
app.UseCors();
Handling filtering operation
To handle filter operations, ensure that your Web API endpoint supports filtering based on OData-formatted queries. Implement the filtering logic on the server-side as shown in the provided code snippet.
// GET: api/Orders
[HttpGet]
public object Get()
{
var queryString = Request.Query;
var data = Orders.GetAllRecords().ToList();
string filter = queryString["$filter"];
if (filter != null)
{
var filters = filter.Split(new string[] { " and " }, StringSplitOptions.RemoveEmptyEntries);
foreach (var filterItem in filters)
{
var filterfield = "";
var filtervalue = "";
var filterParts = filterItem.Split('(', ')', '\'');
if (filterParts.Length != 9)
{
var filterValueParts = filterParts[1].Split();
filterfield = filterValueParts[0];
filtervalue = filterValueParts[2];
}
else
{
filterfield = filterParts[3];
filtervalue = filterParts[5];
}
switch (filterfield)
{
case "OrderID":
data = (from cust in data
where cust.OrderID.ToString() == filtervalue.ToString()
select cust).ToList();
break;
case "CustomerID":
data = (from cust in data
where cust.CustomerID.ToLower().StartsWith(filtervalue.ToString())
select cust).ToList();
break;
case "ShipCity":
data = (from cust in data
where cust.ShipCity.ToLower().StartsWith(filtervalue.ToString())
select cust).ToList();
break;
}
}
return new { Items = data, Count = data.Count() };
}
}
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
import { GridComponent, ColumnsDirective, ColumnDirective, Filter, Inject } from '@syncfusion/ej2-react-grids';
function App() {
const data = new DataManager({
url: 'https://localhost:xxxx/api/Orders', // Replace your hosted link
adaptor: new WebApiAdaptor()
});
return <GridComponent dataSource={data} allowFiltering={true} height={320}>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' isPrimaryKey={true} width='150'textAlign='Right'></ColumnDirective>
<ColumnDirective field='CustomerID' headerText='Customer ID' width='150'></ColumnDirective>
<ColumnDirective field='ShipCity' headerText='Ship City' width='150'/>
</ColumnsDirective>
<Inject services={[Filter]} />
</GridComponent>
};
export default App;
Handling searching operation
To handle search operation, implement search logic on the server side according to the received OData-formatted query.
// GET: api/Orders
[HttpGet]
public object Get()
{
var queryString = Request.Query;
var data = Orders.GetAllRecords().ToList();
string filter = queryString["$filter"];
if (filter != null)
{
var filters = filter.Split(new string[] { " and " }, StringSplitOptions.RemoveEmptyEntries);
foreach (var filterItem in filters)
{
if (filterItem.Contains("substringof")){
// Perform Searching
var searchParts = filterItem.Split('(', ')', '\'');
var searchValue = searchParts[3];
// Apply the search value to all searchable fields
data = data.Where(cust =>
cust.OrderID.ToString().Contains(searchValue) ||
cust.CustomerID.ToLower().Contains(searchValue) ||
cust.ShipCity.ToLower().Contains(searchValue)
// Add conditions for other searchable fields as needed
).ToList();
}
else
{
// Perform filtering
}
}
}
return new { Items = data, Count = data.Count() };
}
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
import { GridComponent, ColumnsDirective, ColumnDirective, Toolbar, ToolbarItems, Inject } from '@syncfusion/ej2-react-grids';
function App() {
const data = new DataManager({
url: 'api/Orders',
adaptor: new WebApiAdaptor()
});
const toolbar: ToolbarItems[] = ['Search'];
return <GridComponent dataSource={data} height={320} toolbar={toolbar}>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' isPrimaryKey={true} width='150'textAlign='Right'></ColumnDirective>
<ColumnDirective field='CustomerID' headerText='Customer ID' width='150'></ColumnDirective>
<ColumnDirective field='ShipCity' headerText='Ship City' width='150'/>
<ColumnDirective field='ShipCountry' headerText='Ship Country' width='150'/>
</ColumnsDirective>
<Inject services={[Toolbar]} />
</GridComponent>
};
export default App;
Handling sorting operation
To handle sorting actions, implement sorting logic on the server-side according to the received OData-formatted query.
Ascending Sorting
Descending Sorting
// GET: api/Orders
[HttpGet]
public object Get()
{
var queryString = Request.Query;
var data = Orders.GetAllRecords().ToList();
string sort = queryString["$orderby"]; //sorting
if (!string.IsNullOrEmpty(sort))
{
var sortConditions = sort.Split(',');
var orderedData = data.OrderBy(x => 0); // Start with a stable sort
foreach (var sortCondition in sortConditions)
{
var sortParts = sortCondition.Trim().Split(' ');
var sortBy = sortParts[0];
var sortOrder = sortParts.Length > 1 && sortParts[1].ToLower() == "desc";
switch (sortBy)
{
case "OrderID":
orderedData = sortOrder ? orderedData.ThenByDescending(x => x.OrderID) : orderedData.ThenBy(x => x.OrderID);
break;
case "CustomerID":
orderedData = sortOrder ? orderedData.ThenByDescending(x => x.CustomerID) : orderedData.ThenBy(x => x.CustomerID);
break;
case "ShipCity":
orderedData = sortOrder ? orderedData.ThenByDescending(x => x.ShipCity) : orderedData.ThenBy(x => x.ShipCity);
break;
}
}
data = orderedData.ToList();
}
return new { Items = data, Count = data.Count() };
}
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
import { GridComponent, ColumnsDirective, ColumnDirective, Sort, Inject } from '@syncfusion/ej2-react-grids';
function App() {
const data = new DataManager({
url: 'https://localhost:xxxx/api/Orders', // Replace your hosted link
adaptor: new WebApiAdaptor()
});
return <GridComponent dataSource={data} allowSorting={true} height={320}>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' isPrimaryKey={true} width='150'textAlign='Right'></ColumnDirective>
<ColumnDirective field='CustomerID' headerText='Customer ID' width='150'></ColumnDirective>
<ColumnDirective field='ShipCity' headerText='Ship City' width='150'/>
<ColumnDirective field='ShipCountry' headerText='Ship Country' width='150'/>
</ColumnsDirective>
<Inject services={[Sort]} />
</GridComponent>
};
export default App;
Handling paging operation
Implement paging logic on the server-side according to the received OData-formatted query. Ensure that the endpoint supports sorting based on the specified criteria.
// GET: api/Orders
[HttpGet]
public object Get()
{
var queryString = Request.Query;
var data = Orders.GetAllRecords().ToList();
int skip = Convert.ToInt32(queryString["$skip"]);
int take = Convert.ToInt32(queryString["$top"]);
return take != 0 ? new { Items = data.Skip(skip).Take(take).ToList(), Count = data.Count() } : new { Items = data, Count = data.Count() };
}
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
import { GridComponent, ColumnsDirective, ColumnDirective, Page, Inject } from '@syncfusion/ej2-react-grids';
function App() {
const data = new DataManager({
url: 'https://localhost:xxxx/api/Orders', // Replace your hosted link
adaptor: new WebApiAdaptor()
});
return <GridComponent dataSource={data} allowPaging={true} height={320}>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' isPrimaryKey={true} width='150'textAlign='Right'></ColumnDirective>
<ColumnDirective field='CustomerID' headerText='Customer ID' width='150'></ColumnDirective>
<ColumnDirective field='ShipCity' headerText='Ship City' width='150'/>
<ColumnDirective field='ShipCountry' headerText='Ship Country' width='150'/>
</ColumnsDirective>
<Inject services={[Page]} />
</GridComponent>
};
export default App;
Handling CRUD operations
To manage CRUD (Create, Read, Update, Delete) operations using the WebApiAdaptor, follow the provided guide for configuring the Syncfusion® Grid for editing and utilize the sample implementation of the OrdersController
in your server application. This controller handles HTTP requests for CRUD operations such as GET, POST, PUT, and DELETE.
To enable CRUD operations in the Syncfusion® Grid component within an React application, follow these steps:
import { ColumnDirective, ColumnsDirective, GridComponent, ToolbarItems, EditSettingsModel, Toolbar, Edit, Inject } from '@syncfusion/ej2-react-grids';
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
function App() {
const data = new DataManager({
url: 'https://localhost:xxxx/api/Orders', // Replace your hosted link
adaptor: new WebApiAdaptor()
});
const editSettings: EditSettingsModel = { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Normal' };
const toolbar: ToolbarItems[] = ['Add', 'Edit', 'Delete', 'Update', 'Cancel', 'Search'];
const orderIDRules: object = {required: true};
const customerIDRules: object = {required: true, minLength: 3};
return <GridComponent dataSource={data} editSettings={editSettings} toolbar={toolbar} height={320}>
<ColumnsDirective>
<ColumnDirective field='OrderID' headerText='Order ID' isPrimaryKey={true} width='150' textAlign='Right' validationRules={orderIDRules}></ColumnDirective>
<ColumnDirective field='CustomerID' headerText='Customer ID' width='150' validationRules={customerIDRules}></ColumnDirective>
<ColumnDirective field='ShipCity' headerText='Ship City' width='150'/>
<ColumnDirective field='ShipCountry' headerText='Ship Country' width='150'/>
</ColumnsDirective>
<Inject services={[Toolbar, Edit]} />
</GridComponent>
};
export default App;
Normal/Inline editing is the default edit mode for the Grid component. To enable CRUD operations, ensure that the isPrimaryKey property is set to true for a specific Grid column, ensuring that its value is unique.
Insert Record
To insert a new record into your Syncfusion® Grid, you can utilize the HttpPost
method in your server application. Below is a sample implementation of inserting a record using the OrdersController:
// POST: api/Orders
[HttpPost]
/// <summary>
/// Inserts a new data item into the data collection.
/// </summary>
/// <param name="newRecord">It holds new record detail which is need to be inserted.</param>
/// <returns>Returns void</returns>
public void Post([FromBody] OrdersDetails newRecord)
{
// Insert a new record into the OrdersDetails model
OrdersDetails.GetAllRecords().Insert(0, newRecord);
}
Update Record
Updating a record in the Syncfusion® Grid can be achieved by utilizing the HttpPut
method in your controller. Here’s a sample implementation of updating a record:
// PUT: api/Orders/5
[HttpPut]
/// <summary>
/// Update a existing data item from the data collection.
/// </summary>
/// <param name="updatedOrder">It holds updated record detail which is need to be updated.</param>
/// <returns>Returns void</returns>
public void Put(int id, [FromBody] OrdersDetails updatedOrder)
{
// Find the existing order by ID
var existingOrder = OrdersDetails.GetAllRecords().FirstOrDefault(o => o.OrderID == id);
if (existingOrder != null)
{
// If the order exists, update its properties
existingOrder.OrderID = updatedOrder.OrderID;
existingOrder.CustomerID = updatedOrder.CustomerID;
existingOrder.ShipCity = updatedOrder.ShipCity;
existingOrder.ShipCountry = updatedOrder.ShipCountry;
}
}
Delete Record
To delete a record from your Syncfusion® Grid, you can utilize the HttpDelete
method in your controller. Below is a sample implementation:
// DELETE: api/5
[HttpDelete("{id}")]
/// <summary>
/// Remove a specific data item from the data collection.
/// </summary>
/// <param name="key">It holds specific record detail id which is need to be removed.</param>
/// <returns>Returns void</returns>
public void Delete(int key)
{
// Find the order to remove by ID
var orderToRemove = OrdersDetails.GetAllRecords().FirstOrDefault(order => order.OrderID == key);
// If the order exists, remove it
if (orderToRemove != null)
{
OrdersDetails.GetAllRecords().Remove(orderToRemove);
}
}