# Get List Example

## Overview

This document demonstrates the complete **Get List flow** using the **GetShippingDetails** 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 is similar to Get Paged List but returns a simple `IEnumerable<T>` without pagination.

## 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 (Simple List)
```

## Step-by-Step Implementation

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

**File**: `ShippingController_GetShippingDetails.cs`

```csharp
[HttpGet()]
[Route("GetShippingDetails")]
[ProducesResponseType(typeof(IEnumerable<GetShippingDetailsDto>), 200)]
public async Task<IActionResult> GetShippingDetails([FromQuery]GetShippingDetailsParams parameters)
{
    return RunQueryListService<GetShippingDetailsParams, GetShippingDetailsDto>(
                parameters, _processShippingService.GetShippingDetails);
}
```

**What Happens:**

* **HTTP Method**: `GET /api/Shipping/GetShippingDetails`
* **Input**: `GetShippingDetailsParams` from query parameters
* **Action**: Calls the service layer to process the query
* **Response**: HTTP 200 OK with `IEnumerable<GetShippingDetailsDto>`

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

**File**: `ProcessShippingService_GetShippingDetails.cs`

```csharp
public IEnumerable<GetShippingDetailsDto> GetShippingDetails(GetShippingDetailsParams @params)
{
    return _flexHost.GetFlexiQuery<GetShippingDetails>().AssignParameters(@params).Fetch();
}
```

**What Happens:**

* **Query Resolution**: Gets the FlexiQuery instance for GetShippingDetails
* **Parameter Assignment**: Assigns query parameters to the query handler
* **Query Execution**: Calls the Fetch() method to execute the query
* **Result**: Returns simple list of shipping details for lookup

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

**File**: `GetShippingDetails.cs`

```csharp
public class GetShippingDetails : FlexiQueryEnumerableBridge<Shipping, GetShippingDetailsDto>
{
    protected readonly ILogger<GetShippingDetails> _logger;
    protected GetShippingDetailsParams _params;
    protected readonly ShippingRESTClient _restClient;

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

    public virtual GetShippingDetails AssignParameters(GetShippingDetailsParams @params)
    {
        _params = @params;
        return this;
    }

    public override IEnumerable<GetShippingDetailsDto> Fetch()
    {
        try
        {
            // Convert internal parameters to Request DTO
            GetShippingDetailsRequestDto requestParams = new GetShippingDetailsRequestDto
            {
                SearchTerm = _params.SearchTerm,
                OrderId = _params.OrderId,
                Status = _params.Status?.ToString(),
                FromDate = _params.FromDate,
                ToDate = _params.ToDate,
                Limit = _params.Limit
            };

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

            if (response.IsSuccessStatusCode)
            {
                var responseContent = response.Content.ReadAsStringAsync().Result;
                var responseDto = JsonConvert.DeserializeObject<GetShippingDetailsResponseDto>(responseContent);
                
                // Convert Response DTO to Internal DTO
                var result = responseDto.ShippingDetails?.Select(x => new GetShippingDetailsDto
                {
                    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,
                    IsActive = x.IsActive
                }).ToList() ?? new List<GetShippingDetailsDto>();

                _logger.LogDebug("Shipping details retrieved successfully. Count: {Count}", result.Count);
                return result;
            }
            else
            {
                _logger.LogWarning("Failed to retrieve shipping details. Status: {StatusCode}", response.StatusCode);
                return new List<GetShippingDetailsDto>();
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error retrieving shipping details");
            return new List<GetShippingDetailsDto>();
        }
    }

    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 list
* **Error Handling**: Handles success/failure responses from external system
* **Data Transformation**: Applies business logic during mapping

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

**File**: `GetShippingDetailsParams.cs`

```csharp
public class GetShippingDetailsParams : DtoBridge
{
    // Add custom filtering parameters here
    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; }
    public int? Limit { get; set; }
}
```

**What Happens:**

* **Custom Filters**: Allows filtering by search term, order ID, status, date range
* **Limit Support**: Optional limit for lookup results
* **Query Parameters**: Automatically bound from URL query string

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

**File**: `GetShippingDetailsDto.cs`

```csharp
public partial class GetShippingDetailsDto : 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 bool IsActive { get; set; }
}
```

**What Happens:**

* **Lookup Data**: Contains essential fields for dropdown/lookup scenarios
* **Minimal Structure**: Only includes necessary fields for selection
* **Performance**: Lightweight DTO for fast loading

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

**File**: `GetShippingDetailsMapperConfiguration.cs`

```csharp
public partial class GetShippingDetailsMapperConfiguration : FlexMapperProfile
{
    public GetShippingDetailsMapperConfiguration() : base()
    {
        CreateMap<Shipping, GetShippingDetailsDto>()
            .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
* **Lookup Optimization**: Maps only necessary fields for lookup scenarios

## Key Differences from Get Paged List

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

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

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

1. **Simple List**: Returns basic `IEnumerable<T>` without pagination
2. **Lookup Optimized**: Designed for dropdown/lookup scenarios
3. **Lightweight**: Minimal data transfer for performance
4. **No Pagination**: All results returned in single response
5. **Fast Loading**: Optimized for quick data retrieval

### **Common Use Cases**

* **Dropdown Lists**: Populate dropdown controls
* **Lookup Tables**: Search and select scenarios
* **Reference Data**: Load reference data for forms
* **Auto-complete**: Provide suggestions for input fields
* **Quick Filters**: Fast filtering options

## 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. **Response** → HTTP 200 OK with simple list

### **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);
    }
    
    // Apply limit if specified
    if (_params.Limit.HasValue)
    {
        query = query.Take(_params.Limit.Value);
    }
    
    return query;
}
```

### **Advanced Query Building**

```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);
    }
    
    // Sorting for consistent results
    query = query.OrderByDescending(s => s.CreatedDate);
    
    // Apply limit for performance
    if (_params.Limit.HasValue)
    {
        query = query.Take(_params.Limit.Value);
    }
    else
    {
        // Default limit for lookup scenarios
        query = query.Take(100);
    }
    
    return query;
}
```

## Performance Considerations

### **Optimization Strategies**

1. **Limit Results**: Always apply reasonable limits for lookup scenarios
2. **Selective Fields**: Only return necessary fields in DTO
3. **Indexing**: Ensure proper database indexes on filter fields
4. **Caching**: Consider caching for frequently accessed lookup data
5. **Lazy Loading**: Use lazy loading for related entities when appropriate

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

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

## Key Benefits

* **Performance**: Fast loading for small datasets
* **Simplicity**: Simple list without pagination complexity
* **Lookup Optimized**: Perfect for dropdown/lookup scenarios
* **Lightweight**: Minimal data transfer
* **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 GetShippingDetails example demonstrates how FlexBase enables clean, maintainable, and scalable list operations optimized for lookup and dropdown scenarios!** 🚀


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.flexbase.in/solution-structure/getting-started/features/rest-services/get-list-example.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
