> 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-by-id-example.md).

# Get By Id Example

## Overview

This document demonstrates the complete **Get By ID flow** using the **GetShippingInfoById** 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 single entity by its unique identifier.

## 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 (Single Entity)
```

## Step-by-Step Implementation

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

**File**: `ShippingController_GetShippingInfoById.cs`

```csharp
[HttpGet()]
[Route("GetShippingInfoById/{id}")]
[ProducesResponseType(typeof(GetShippingInfoByIdDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetShippingInfoById(string id)
{
    GetShippingInfoByIdParams parameters = new GetShippingInfoByIdParams();
    parameters.Id = id;

    return RunQuerySingleService<GetShippingInfoByIdParams, GetShippingInfoByIdDto>(
                parameters, _processShippingService.GetShippingInfoById);
}
```

**What Happens:**

* **HTTP Method**: `GET /api/Shipping/GetShippingInfoById/{id}`
* **Input**: Shipping ID from URL parameter
* **Parameter Creation**: Creates `GetShippingInfoByIdParams` with the ID
* **Action**: Calls the service layer to process the query
* **Response**: HTTP 200 OK with `GetShippingInfoByIdDto` or 404 Not Found

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

**File**: `ProcessShippingService_GetShippingInfoById.cs`

```csharp
public GetShippingInfoByIdDto GetShippingInfoById(GetShippingInfoByIdParams @params)
{
    return _flexHost.GetFlexiQuery<GetShippingInfoById>().AssignParameters(@params).Fetch();
}
```

**What Happens:**

* **Query Resolution**: Gets the FlexiQuery instance for GetShippingInfoById
* **Parameter Assignment**: Assigns query parameters to the query handler
* **Query Execution**: Calls the Fetch() method to execute the query
* **Result**: Returns single shipping or null if not found

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

**File**: `GetShippingInfoById.cs`

```csharp
public class GetShippingInfoById : FlexiQueryBridge<Shipping, GetShippingInfoByIdDto>
{
    protected readonly ILogger<GetShippingInfoById> _logger;
    protected GetShippingInfoByIdParams _params;
    protected readonly ShippingRESTClient _restClient;

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

    public virtual GetShippingInfoById AssignParameters(GetShippingInfoByIdParams @params)
    {
        _params = @params;
        return this;
    }

    public override GetShippingInfoByIdDto Fetch()
    {
        try
        {
            // Convert internal parameters to Request DTO
            GetShippingInfoByIdRequestDto requestParams = new GetShippingInfoByIdRequestDto
            {
                Id = _params.Id
            };

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

            if (response.IsSuccessStatusCode)
            {
                var responseContent = response.Content.ReadAsStringAsync().Result;
                var responseDto = JsonConvert.DeserializeObject<GetShippingInfoByIdResponseDto>(responseContent);
                
                // Convert Response DTO to Internal DTO
                var result = new GetShippingInfoByIdDto
                {
                    Id = responseDto.Id,
                    OrderId = responseDto.OrderId,
                    ShippingAddress = responseDto.ShippingAddress,
                    TrackingNumber = responseDto.TrackingNumber,
                    Status = ParseShippingStatus(responseDto.Status),
                    StatusDescription = responseDto.StatusDescription,
                    TotalWeight = responseDto.TotalWeight,
                    TotalVolume = responseDto.TotalVolume,
                    CreatedDate = responseDto.CreatedDate,
                    LastModifiedDate = responseDto.LastModifiedDate,
                    CreatedBy = responseDto.CreatedBy,
                    LastModifiedBy = responseDto.LastModifiedBy,
                    ShippingItems = responseDto.ShippingItems?.Select(x => new ShippingItemDto
                    {
                        ProductId = x.ProductId,
                        Quantity = x.Quantity,
                        Weight = x.Weight,
                        Volume = x.Volume
                    }).ToList()
                };

                _logger.LogDebug("Shipping info retrieved successfully for ID: {Id}", _params.Id);
                return result;
            }
            else
            {
                _logger.LogWarning("Shipping not found for ID: {Id}. Status: {StatusCode}", _params.Id, response.StatusCode);
                return null;
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error retrieving shipping info for ID: {Id}", _params.Id);
            return null;
        }
    }

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

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

**File**: `GetShippingInfoByIdParams.cs`

```csharp
public class GetShippingInfoByIdParams : DtoBridge
{
    public string Id { get; set; }
}
```

**What Happens:**

* **ID Parameter**: Contains the unique identifier for the entity
* **Simple Structure**: Minimal parameters for single entity lookup
* **URL Binding**: ID is automatically bound from URL parameter

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

**File**: `GetShippingInfoByIdDto.cs`

```csharp
public partial class GetShippingInfoByIdDto : 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 decimal TotalVolume { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime? LastModifiedDate { get; set; }
    public string CreatedBy { get; set; }
    public string LastModifiedBy { get; set; }
    public ICollection<ShippingItemDto> ShippingItems { get; set; }
}
```

**What Happens:**

* **Complete Data**: Contains all relevant fields for the entity
* **Detailed Structure**: Includes all properties for full entity display
* **Related Data**: May include related entity information (ShippingItems)
* **Audit Fields**: Includes creation and modification tracking

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

**File**: `GetShippingInfoByIdMapperConfiguration.cs`

```csharp
public partial class GetShippingInfoByIdMapperConfiguration : FlexMapperProfile
{
    public GetShippingInfoByIdMapperConfiguration() : base()
    {
        CreateMap<Shipping, GetShippingInfoByIdDto>()
            .ForMember(d => d.StatusDescription, opt => opt.MapFrom(s => s.Status.ToString()))
            .ForMember(d => d.ShippingItems, opt => opt.MapFrom(s => s.ShippingItems));
    }
}
```

**What Happens:**

* **Entity to DTO Mapping**: Maps domain entities to DTOs
* **Custom Mappings**: Handles complex property transformations
* **Related Data**: Maps related entity properties
* **Computed Fields**: Handles calculated properties

## Key Differences from Other Query Operations

### **Get By ID vs Other Query Characteristics**

| Aspect                | Get By ID                  | Get List                     | Get Paged List               |
| --------------------- | -------------------------- | ---------------------------- | ---------------------------- |
| **Return Type**       | `T` (single entity)        | `IEnumerable<T>`             | `FlexiPagedList<T>`          |
| **Input**             | ID from URL                | Query parameters             | Query parameters             |
| **Result Count**      | 0 or 1                     | 0 to many                    | 0 to many (paginated)        |
| **Use Case**          | Single entity details      | Dropdown/lookup              | Data grids/tables            |
| **Performance**       | Very fast (indexed lookup) | Fast for small datasets      | Optimized for large datasets |
| **Controller Method** | `RunQuerySingleService`    | `RunQueryListService`        | `RunQueryPagedService`       |
| **Query Base**        | `FlexiQueryBridge`         | `FlexiQueryEnumerableBridge` | `FlexiQueryPagedListBridge`  |
| **HTTP Status**       | 200 OK or 404 Not Found    | 200 OK                       | 200 OK                       |

### **Get By ID-Specific Features**

1. **Single Entity**: Returns one entity or null
2. **ID-Based Lookup**: Uses unique identifier for fast retrieval
3. **404 Handling**: Returns 404 when entity not found
4. **Complete Data**: Returns all entity details
5. **Fast Performance**: Optimized for indexed lookups

### **Common Use Cases**

* **Entity Details**: Display detailed information about a specific shipping
* **Edit Forms**: Load shipping data for editing
* **View Pages**: Show complete shipping information
* **API Integration**: Retrieve specific shipping for external systems
* **Validation**: Check if shipping exists before operations

## Flow Summary

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

1. **GET Request** → Controller receives request with ID parameter
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 entity or 404 Not Found

### **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>().Where(t => t.Id == _params.Id);
    return query;
}
```

### **Advanced Query Building**

```csharp
protected override IQueryable<T> Build<T>()
{
    _repoFactory.Init(_params);
    IQueryable<T> query = _repoFactory.GetRepo().FindAll<T>();
    
    // Filter by ID
    query = query.Where(t => t.Id == _params.Id);
    
    // Exclude soft deleted items
    query = query.Where(t => !t.IsSoftDeleted);
    
    // Include related entities if needed
    // query = query.Include(t => t.ShippingItems);
    
    return query;
}
```

### **Error Handling Patterns**

```csharp
public override GetShippingInfoByIdDto Fetch()
{
    var result = Build<Shipping>().SelectTo<GetShippingInfoByIdDto>().FirstOrDefault();
    
    if (result == null)
    {
        _logger.LogWarning("Shipping with ID {ShippingId} not found", _params.Id);
    }
    else
    {
        _logger.LogDebug("Shipping with ID {ShippingId} retrieved successfully", _params.Id);
    }
    
    return result;
}
```

## Performance Considerations

### **Optimization Strategies**

1. **Database Indexing**: Ensure ID field is properly indexed
2. **Selective Fields**: Only return necessary fields in DTO
3. **Related Data**: Use Include() judiciously for related entities
4. **Caching**: Consider caching for frequently accessed entities
5. **Query Optimization**: Use FirstOrDefault() for single entity retrieval

### **When to Use Get By ID vs Other Queries**

| Scenario                | Use Get By ID | Use Get List | Use Get Paged List |
| ----------------------- | ------------- | ------------ | ------------------ |
| **Entity Details Page** | ✅ Yes         | ❌ No         | ❌ No               |
| **Edit Form Loading**   | ✅ Yes         | ❌ No         | ❌ No               |
| **API Integration**     | ✅ Yes         | ❌ No         | ❌ No               |
| **Dropdown Population** | ❌ No          | ✅ Yes        | ❌ No               |
| **Data Grids**          | ❌ No          | ❌ No         | ✅ Yes              |
| **Search Results**      | ❌ No          | ✅ Yes        | ✅ Yes              |
| **Lookup Tables**       | ❌ No          | ✅ Yes        | ❌ No               |

## Error Handling

### **HTTP Status Codes**

* **200 OK**: Entity found and returned successfully
* **404 Not Found**: Entity with specified ID does not exist
* **400 Bad Request**: Invalid ID format or missing ID parameter
* **500 Internal Server Error**: Database or server error

### **Controller Error Handling**

```csharp
[HttpGet()]
[Route("GetShippingInfoById/{id}")]
[ProducesResponseType(typeof(GetShippingInfoByIdDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> GetShippingInfoById(string id)
{
    if (string.IsNullOrEmpty(id))
    {
        return BadRequest("Shipping ID is required");
    }
    
    GetShippingInfoByIdParams parameters = new GetShippingInfoByIdParams();
    parameters.Id = id;

    return RunQuerySingleService<GetShippingInfoByIdParams, GetShippingInfoByIdDto>(
                parameters, _processShippingService.GetShippingInfoById);
}
```

## Key Benefits

* **Performance**: Very fast retrieval using indexed ID lookup
* **Simplicity**: Simple single entity retrieval
* **Complete Data**: Returns full entity details
* **Type Safety**: Strongly typed DTOs and parameters
* **AutoMapper**: Automatic entity-to-DTO mapping
* **Error Handling**: Built-in 404 handling for missing entities
* **No Side Effects**: Read-only operations
* **Testable**: Each component can be tested independently
* **Maintainable**: Clear separation of concerns

***

**This GetShippingInfoById example demonstrates how FlexBase enables clean, maintainable, and scalable single entity retrieval operations with proper error handling and performance optimization!** 🚀
