> For the complete documentation index, see [llms.txt](https://docs.flexbase.in/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flexbase.in/solution-structure/getting-started/features/rest-services/get-paged-list-example.md).

# Get Paged List Example

## Overview

This document demonstrates the complete **Get Paged List flow** using the **GetShippingPagedList** feature from the EBusiness application. The flow starts with a GET request to the controller and uses **Query projects** instead of **Handlers** in the DomainHandler section for data retrieval. This returns a paginated list of entities with metadata for data grids and large datasets.

## Complete Flow Architecture

```
GET Request → Controller → Service → Query Handler → RESTClient → External System
                                                                    ↓
Response ← Controller ← Service ← Query Handler ← RESTClient ← External System
```

### **Detailed Flow Breakdown**

```
1. GET Request
   ↓
2. Controller (API Entry Point)
   ↓
3. Service Layer (Business Orchestration)
   ↓
4. Query Handler (RESTClient Integration)
   ├── Internal DTO → Request DTO Mapping
   ├── RESTClient Call to External System
   └── Response DTO → Internal DTO Mapping
   ↓
5. Response (Paged List with Metadata)
```

## Step-by-Step Implementation

### 1. **API Controller** - The Entry Point

**File**: `ShippingController_GetShippingPagedList.cs`

```csharp
[HttpGet()]
[Route("GetShippingPagedList")]
[ProducesResponseType(typeof(FlexiPagedList<GetShippingPagedListDto>), 200)]
public async Task<IActionResult> GetShippingPagedList([FromQuery]GetShippingPagedListParams parameters)
{
    return RunQueryPagedService<GetShippingPagedListParams, GetShippingPagedListDto>(
                parameters, _processShippingService.GetShippingPagedList);
}
```

**What Happens:**

* **HTTP Method**: `GET /api/Shipping/GetShippingPagedList`
* **Input**: `GetShippingPagedListParams` from query parameters
* **Action**: Calls the service layer to process the query
* **Response**: HTTP 200 OK with `FlexiPagedList<GetShippingPagedListDto>`

### 2. **Service Layer** - Business Orchestration

**File**: `ProcessShippingService_GetShippingPagedList.cs`

```csharp
public FlexiPagedList<GetShippingPagedListDto> GetShippingPagedList(GetShippingPagedListParams @params)
{
    return _flexHost.GetFlexiQuery<GetShippingPagedList>().AssignParameters(@params).Fetch();
}
```

**What Happens:**

* **Query Resolution**: Gets the FlexiQuery instance for GetShippingPagedList
* **Parameter Assignment**: Assigns query parameters to the query handler
* **Query Execution**: Calls the Fetch() method to execute the query
* **Result**: Returns paginated list of shipping with metadata

### 3. **Query Handler** - RESTClient Integration

**File**: `GetShippingPagedList.cs`

```csharp
public class GetShippingPagedList : FlexiQueryPagedListBridge<Shipping, GetShippingPagedListDto>
{
    protected readonly ILogger<GetShippingPagedList> _logger;
    protected GetShippingPagedListParams _params;
    protected readonly ShippingRESTClient _restClient;

    public GetShippingPagedList(ILogger<GetShippingPagedList> logger, ShippingRESTClient restClient)
    {
        _logger = logger;
        _restClient = restClient;
    }

    public virtual GetShippingPagedList AssignParameters(GetShippingPagedListParams @params)
    {
        _params = @params;
        return this;
    }

    public override FlexiPagedList<GetShippingPagedListDto> Fetch()
    {
        try
        {
            // Convert internal parameters to Request DTO
            GetShippingPagedListRequestDto requestParams = new GetShippingPagedListRequestDto
            {
                PageNumber = _params.PageNumber,
                PageSize = _params.PageSize,
                SearchTerm = _params.SearchTerm,
                OrderId = _params.OrderId,
                Status = _params.Status?.ToString(),
                FromDate = _params.FromDate,
                ToDate = _params.ToDate,
                SortBy = _params.SortBy,
                SortDirection = _params.SortDirection
            };

            // Call external REST service
            var response = _restClient.GetShippingPagedList(requestParams).Result;

            if (response.IsSuccessStatusCode)
            {
                var responseContent = response.Content.ReadAsStringAsync().Result;
                var responseDto = JsonConvert.DeserializeObject<GetShippingPagedListResponseDto>(responseContent);
                
                // Convert Response DTO to Internal DTO
                var items = responseDto.Items?.Select(x => new GetShippingPagedListDto
                {
                    Id = x.Id,
                    OrderId = x.OrderId,
                    ShippingAddress = x.ShippingAddress,
                    TrackingNumber = x.TrackingNumber,
                    Status = ParseShippingStatus(x.Status),
                    StatusDescription = x.StatusDescription,
                    TotalWeight = x.TotalWeight,
                    CreatedDate = x.CreatedDate,
                    CreatedBy = x.CreatedBy,
                    IsActive = x.IsActive
                }).ToList() ?? new List<GetShippingPagedListDto>();

                // Create paginated result
                var result = new FlexiPagedList<GetShippingPagedListDto>
                {
                    Items = items,
                    TotalCount = responseDto.TotalCount,
                    PageNumber = responseDto.PageNumber,
                    PageSize = responseDto.PageSize,
                    TotalPages = responseDto.TotalPages,
                    HasPreviousPage = responseDto.HasPreviousPage,
                    HasNextPage = responseDto.HasNextPage
                };

                _logger.LogDebug("Shipping paged list retrieved successfully. Count: {Count}, Page: {PageNumber}", 
                    result.TotalCount, result.PageNumber);
                return result;
            }
            else
            {
                _logger.LogWarning("Failed to retrieve shipping paged list. Status: {StatusCode}", response.StatusCode);
                return new FlexiPagedList<GetShippingPagedListDto>
                {
                    Items = new List<GetShippingPagedListDto>(),
                    TotalCount = 0,
                    PageNumber = _params.PageNumber,
                    PageSize = _params.PageSize,
                    TotalPages = 0,
                    HasPreviousPage = false,
                    HasNextPage = false
                };
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error retrieving shipping paged list");
            return new FlexiPagedList<GetShippingPagedListDto>
            {
                Items = new List<GetShippingPagedListDto>(),
                TotalCount = 0,
                PageNumber = _params.PageNumber,
                PageSize = _params.PageSize,
                TotalPages = 0,
                HasPreviousPage = false,
                HasNextPage = false
            };
        }
    }

    private ShippingStatus ParseShippingStatus(string status)
    {
        return status?.ToLower() switch
        {
            "created" => ShippingStatus.Created,
            "in_transit" => ShippingStatus.InTransit,
            "delivered" => ShippingStatus.Delivered,
            "cancelled" => ShippingStatus.Cancelled,
            _ => ShippingStatus.Unknown
        };
    }
}
```

**What Happens:**

* **Parameter Assignment**: Stores query parameters for use in RESTClient calls
* **Request Mapping**: Converts internal parameters to Request DTO
* **RESTClient Call**: Calls external shipping service via RESTClient
* **Response Mapping**: Converts Response DTO to Internal DTO with pagination
* **Error Handling**: Handles success/failure responses from external system
* **Data Transformation**: Applies business logic during mapping

### 4. **Query Parameters** - Input DTO

**File**: `GetShippingPagedListParams.cs`

```csharp
public class GetShippingPagedListParams : DtoBridge
{
    // Pagination parameters
    public int PageNumber { get; set; } = 1;
    public int PageSize { get; set; } = 10;
    
    // Filtering parameters
    public string SearchTerm { get; set; }
    public string OrderId { get; set; }
    public ShippingStatus? Status { get; set; }
    public DateTime? FromDate { get; set; }
    public DateTime? ToDate { get; set; }
    
    // Sorting parameters
    public string SortBy { get; set; } = "CreatedDate";
    public string SortDirection { get; set; } = "desc";
}
```

**What Happens:**

* **Pagination**: PageNumber and PageSize for pagination control
* **Filtering**: Multiple filter options for data refinement
* **Sorting**: SortBy and SortDirection for data ordering
* **Query Parameters**: Automatically bound from URL query string

### 5. **Output DTO** - Data Transfer Object

**File**: `GetShippingPagedListDto.cs`

```csharp
public partial class GetShippingPagedListDto : DtoBridge 
{
    public string Id { get; set; }
    public string OrderId { get; set; }
    public string ShippingAddress { get; set; }
    public string TrackingNumber { get; set; }
    public ShippingStatus Status { get; set; }
    public string StatusDescription { get; set; }
    public decimal TotalWeight { get; set; }
    public DateTime CreatedDate { get; set; }
    public string CreatedBy { get; set; }
    public bool IsActive { get; set; }
}
```

**What Happens:**

* **Grid Data**: Contains fields suitable for data grid display
* **Essential Fields**: Includes key information for list views
* **Performance**: Optimized for large dataset display

### 6. **AutoMapper Configuration** - Data Transformation

**File**: `GetShippingPagedListMapperConfiguration.cs`

```csharp
public partial class GetShippingPagedListMapperConfiguration : FlexMapperProfile
{
    public GetShippingPagedListMapperConfiguration() : base()
    {
        CreateMap<Shipping, GetShippingPagedListDto>()
            .ForMember(d => d.StatusDescription, opt => opt.MapFrom(s => s.Status.ToString()))
            .ForMember(d => d.IsActive, opt => opt.MapFrom(s => !s.IsSoftDeleted));
    }
}
```

**What Happens:**

* **Entity to DTO Mapping**: Maps domain entities to DTOs
* **Custom Mappings**: Handles complex property transformations
* **Grid Optimization**: Maps fields optimized for data grid display

## Key Differences from Get List

### **Get Paged List vs Get List Characteristics**

| Aspect                | Get Paged List                    | Get List                       |
| --------------------- | --------------------------------- | ------------------------------ |
| **Return Type**       | `FlexiPagedList<T>`               | `IEnumerable<T>`               |
| **Pagination**        | ✅ Built-in pagination             | ❌ No pagination                |
| **Use Case**          | Data grids/tables                 | Lookup/Dropdown                |
| **Performance**       | Optimized for large datasets      | Fast for small datasets        |
| **Memory Usage**      | Higher (includes pagination info) | Lower (no pagination metadata) |
| **Controller Method** | `RunQueryPagedService`            | `RunQueryListService`          |
| **Query Base**        | `FlexiQueryPagedListBridge`       | `FlexiQueryEnumerableBridge`   |

### **Get Paged List-Specific Features**

1. **Pagination**: Built-in pagination with PageNumber and PageSize
2. **Metadata**: Includes total count, page count, and pagination info
3. **Large Datasets**: Optimized for handling large amounts of data
4. **Data Grids**: Perfect for admin interfaces and data tables
5. **Performance**: Efficient memory usage for large datasets

### **Common Use Cases**

* **Data Grids**: Populate data tables with pagination
* **Admin Interfaces**: Large dataset management
* **Reporting**: Paginated report data
* **Search Results**: Paginated search results
* **Audit Logs**: Large audit trail displays

## Flow Summary

### **Synchronous Flow (Data Retrieval)**

1. **GET Request** → Controller receives request with query parameters
2. **Service Processing** → Business orchestration and query resolution
3. **Query Handler** → Database query building and execution
4. **AutoMapper** → Entity-to-DTO transformation
5. **Pagination** → Apply pagination to results
6. **Response** → HTTP 200 OK with paginated list and metadata

### **No Asynchronous Flow**

* **No Events**: Query operations don't publish events
* **No Subscribers**: No side effects or event processing
* **Immediate Response**: Data is returned immediately

## Query Building Patterns

### **Basic Query Building**

```csharp
protected override IQueryable<T> Build<T>()
{
    _repoFactory.Init(_params);
    IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
    
    // Add filtering logic here
    if (!string.IsNullOrEmpty(_params.SearchTerm))
    {
        query = query.Where(s => s.ShippingAddress.Contains(_params.SearchTerm) || 
                                s.TrackingNumber.Contains(_params.SearchTerm));
    }
    
    if (!string.IsNullOrEmpty(_params.OrderId))
    {
        query = query.Where(s => s.OrderId == _params.OrderId);
    }
    
    if (_params.Status.HasValue)
    {
        query = query.Where(s => s.Status == _params.Status.Value);
    }
    
    return query;
}
```

### **Advanced Query Building with Sorting**

```csharp
protected override IQueryable<T> Build<T>()
{
    _repoFactory.Init(_params);
    IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
    
    // Exclude soft deleted items
    query = query.Where(s => !s.IsSoftDeleted);
    
    // Search functionality
    if (!string.IsNullOrEmpty(_params.SearchTerm))
    {
        var searchTerm = _params.SearchTerm.ToLower();
        query = query.Where(s => s.ShippingAddress.ToLower().Contains(searchTerm) || 
                                s.TrackingNumber.ToLower().Contains(searchTerm) ||
                                s.OrderId.ToLower().Contains(searchTerm));
    }
    
    // Order ID filtering
    if (!string.IsNullOrEmpty(_params.OrderId))
    {
        query = query.Where(s => s.OrderId == _params.OrderId);
    }
    
    // Status filtering
    if (_params.Status.HasValue)
    {
        query = query.Where(s => s.Status == _params.Status.Value);
    }
    
    // Date range filtering
    if (_params.FromDate.HasValue)
    {
        query = query.Where(s => s.CreatedDate >= _params.FromDate.Value);
    }
    
    if (_params.ToDate.HasValue)
    {
        query = query.Where(s => s.CreatedDate <= _params.ToDate.Value);
    }
    
    // Dynamic sorting
    switch (_params.SortBy?.ToLower())
    {
        case "createddate":
            query = _params.SortDirection?.ToLower() == "asc" 
                ? query.OrderBy(s => s.CreatedDate)
                : query.OrderByDescending(s => s.CreatedDate);
            break;
        case "status":
            query = _params.SortDirection?.ToLower() == "asc" 
                ? query.OrderBy(s => s.Status)
                : query.OrderByDescending(s => s.Status);
            break;
        case "trackingnumber":
            query = _params.SortDirection?.ToLower() == "asc" 
                ? query.OrderBy(s => s.TrackingNumber)
                : query.OrderByDescending(s => s.TrackingNumber);
            break;
        default:
            query = query.OrderByDescending(s => s.CreatedDate);
            break;
    }
    
    return query;
}
```

## Pagination Metadata

### **FlexiPagedList Structure**

```csharp
public class FlexiPagedList<T>
{
    public IEnumerable<T> Items { get; set; }
    public int TotalCount { get; set; }
    public int PageNumber { get; set; }
    public int PageSize { get; set; }
    public int TotalPages { get; set; }
    public bool HasPreviousPage { get; set; }
    public bool HasNextPage { get; set; }
}
```

### **Frontend Integration Example**

```javascript
// Example frontend usage
const response = await fetch('/api/Shipping/GetShippingPagedList?pageNumber=1&pageSize=10&searchTerm=tracking');
const pagedData = await response.json();

console.log(`Total items: ${pagedData.totalCount}`);
console.log(`Page ${pagedData.pageNumber} of ${pagedData.totalPages}`);
console.log(`Items:`, pagedData.items);
```

## Performance Considerations

### **Optimization Strategies**

1. **Database Indexing**: Ensure proper indexes on filter and sort fields
2. **Selective Fields**: Only return necessary fields in DTO
3. **Query Optimization**: Use efficient WHERE clauses and sorting
4. **Page Size Limits**: Set reasonable maximum page sizes
5. **Caching**: Consider caching for frequently accessed data

### **When to Use Get Paged List vs Get List**

| Scenario                | Use Get Paged List | Use Get List |
| ----------------------- | ------------------ | ------------ |
| **Data Grids**          | ✅ Yes              | ❌ No         |
| **Large Datasets**      | ✅ Yes              | ❌ No         |
| **Admin Interfaces**    | ✅ Yes              | ❌ No         |
| **Reporting**           | ✅ Yes              | ❌ No         |
| **Dropdown Population** | ❌ No               | ✅ Yes        |
| **Lookup Tables**       | ❌ No               | ✅ Yes        |
| **Auto-complete**       | ❌ No               | ✅ Yes        |

## Error Handling

### **HTTP Status Codes**

* **200 OK**: Data retrieved successfully
* **400 Bad Request**: Invalid parameters (invalid page number, page size)
* **500 Internal Server Error**: Database or server error

### **Parameter Validation**

```csharp
[HttpGet()]
[Route("GetShippingPagedList")]
[ProducesResponseType(typeof(FlexiPagedList<GetShippingPagedListDto>), 200)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> GetShippingPagedList([FromQuery]GetShippingPagedListParams parameters)
{
    // Validate pagination parameters
    if (parameters.PageNumber < 1)
    {
        return BadRequest("Page number must be greater than 0");
    }
    
    if (parameters.PageSize < 1 || parameters.PageSize > 100)
    {
        return BadRequest("Page size must be between 1 and 100");
    }
    
    return RunQueryPagedService<GetShippingPagedListParams, GetShippingPagedListDto>(
                parameters, _processShippingService.GetShippingPagedList);
}
```

## Key Benefits

* **Performance**: Optimized for large datasets with pagination
* **Memory Efficiency**: Only loads required page of data
* **User Experience**: Smooth navigation through large datasets
* **Metadata**: Rich pagination information for frontend
* **Type Safety**: Strongly typed DTOs and parameters
* **AutoMapper**: Automatic entity-to-DTO mapping
* **No Side Effects**: Read-only operations
* **Testable**: Each component can be tested independently
* **Maintainable**: Clear separation of concerns

***

**This GetShippingPagedList example demonstrates how FlexBase enables clean, maintainable, and scalable paginated list operations optimized for data grids and large datasets!** 🚀
