or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

http-client.mdi18n.mdindex.mdlocale.mdmenu.mdpipes.mdsettings.mdui-helpers.mdutilities.md
tile.json

http-client.mddocs/

HTTP Client

Enhanced HTTP client with loading state management, request utilities, decorator-based API support, and comprehensive request/response handling for Angular applications.

Capabilities

_HttpClient

Enhanced HTTP client service with loading state tracking and utility methods.

/**
 * Enhanced HTTP client with loading state and utilities
 * Extends Angular HttpClient with additional features
 */
class _HttpClient {
  /** Whether any HTTP request is currently loading */
  readonly loading: boolean;
  /** Current number of active HTTP requests */
  readonly loadingCount: number;
  
  /** Perform GET request */
  get<T>(url: string, params?: any, options?: any): Observable<T>;
  /** Perform POST request */
  post<T>(url: string, body?: any, params?: any, options?: any): Observable<T>;
  /** Perform DELETE request */
  delete<T>(url: string, params?: any, options?: any): Observable<T>;
  /** Perform PATCH request */
  patch<T>(url: string, body?: any, params?: any, options?: any): Observable<T>;
  /** Perform PUT request */
  put<T>(url: string, body?: any, params?: any, options?: any): Observable<T>;
  /** Perform form-encoded request */
  form<T>(url: string, body?: any, params?: any, options?: any): Observable<T>;
  /** Perform JSONP request */
  jsonp(url: string, params?: any, callbackParam?: string): Observable<any>;
  /** Generic request method */
  request<T>(method: string, url: string, options?: any): Observable<T>;
  
  /** Parse parameters into HttpParams */
  parseParams(params: any): HttpParams;
  /** Apply parameters to URL */
  appliedUrl(url: string, params?: any): string;
  /** Clear loading count manually */
  cleanLoading(): void;
}

Usage Examples:

import { Component, inject } from "@angular/core";
import { _HttpClient } from "@delon/theme";

interface User {
  id: number;
  name: string;
  email: string;
}

interface CreateUserRequest {
  name: string;
  email: string;
}

@Component({
  selector: "user-service",
  template: `
    <div class="loading-indicator" *ngIf="http.loading">
      Loading... ({{ http.loadingCount }} requests)
    </div>
    
    <button (click)="loadUsers()">Load Users</button>
    <button (click)="createUser()">Create User</button>
  `
})
export class UserServiceComponent {
  http = inject(_HttpClient);
  users: User[] = [];
  
  loadUsers() {
    // GET request with query parameters
    this.http.get<User[]>('/api/users', {
      page: 1,
      limit: 10,
      search: 'john'
    }).subscribe(users => {
      this.users = users;
      console.log('Loaded users:', users);
    });
  }
  
  createUser() {
    const userData: CreateUserRequest = {
      name: 'John Doe',
      email: 'john@example.com'
    };
    
    // POST request with body
    this.http.post<User>('/api/users', userData).subscribe(newUser => {
      this.users.push(newUser);
      console.log('Created user:', newUser);
    });
  }
  
  updateUser(id: number, updates: Partial<User>) {
    // PATCH request for partial updates
    this.http.patch<User>(`/api/users/${id}`, updates).subscribe(updatedUser => {
      const index = this.users.findIndex(u => u.id === id);
      if (index >= 0) {
        this.users[index] = updatedUser;
      }
    });
  }
  
  deleteUser(id: number) {
    // DELETE request
    this.http.delete(`/api/users/${id}`).subscribe(() => {
      this.users = this.users.filter(u => u.id !== id);
      console.log('Deleted user:', id);
    });
  }
  
  uploadFile(file: File) {
    const formData = new FormData();
    formData.append('file', file);
    formData.append('description', 'User avatar');
    
    // Form request for file upload
    this.http.form<{ url: string }>('/api/upload', formData).subscribe(result => {
      console.log('File uploaded:', result.url);
    });
  }
  
  searchWithJsonp(query: string) {
    // JSONP request for cross-origin requests
    this.http.jsonp('/api/search', { q: query }, 'callback').subscribe(results => {
      console.log('Search results:', results);
    });
  }
}

HTTP Decorators

Decorator-based API for creating type-safe HTTP services with automatic parameter binding.

/**
 * Base class for decorator-based HTTP APIs
 * Extend this class to create declarative HTTP services
 */
class BaseApi {
  constructor(protected http: _HttpClient) {}
}

/** Set base URL for all requests in the class */
function BaseUrl(url: string): ClassDecorator;
/** Set default headers for all requests in the class */
function BaseHeaders(headers: any): ClassDecorator;

/** Mark parameter as URL path parameter */
function Path(key?: string): ParameterDecorator;
/** Mark parameter as query string parameter */
function Query(key?: string): ParameterDecorator;
/** Mark parameter as request body */
function Body(): ParameterDecorator;
/** Mark parameter as headers */
function Headers(key?: string): ParameterDecorator;
/** Mark parameter as payload (auto-detects body vs query) */
function Payload(): ParameterDecorator;

/** HTTP method decorators */
function GET(url?: string, options?: any): MethodDecorator;
function POST(url?: string, options?: any): MethodDecorator;
function PUT(url?: string, options?: any): MethodDecorator;
function DELETE(url?: string, options?: any): MethodDecorator;
function PATCH(url?: string, options?: any): MethodDecorator;
function HEAD(url?: string, options?: any): MethodDecorator;
function OPTIONS(url?: string, options?: any): MethodDecorator;
function JSONP(url?: string, options?: any): MethodDecorator;
function FORM(url?: string, options?: any): MethodDecorator;

Usage Examples:

import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { 
  BaseApi, 
  BaseUrl, 
  BaseHeaders,
  GET, 
  POST, 
  PUT, 
  DELETE,
  Path, 
  Query, 
  Body, 
  Headers
} from "@delon/theme";

// Define API service using decorators
@Injectable()
@BaseUrl('/api/v1')
@BaseHeaders({
  'Content-Type': 'application/json',
  'Accept': 'application/json'
})
export class UserApiService extends BaseApi {
  
  @GET('/users')
  getUsers(
    @Query('page') page: number,
    @Query('limit') limit: number,
    @Query('search') search?: string
  ): Observable<User[]> {
    return null as any; // Implementation handled by decorator
  }
  
  @GET('/users/{id}')
  getUserById(@Path('id') id: number): Observable<User> {
    return null as any;
  }
  
  @POST('/users')
  createUser(@Body() user: CreateUserRequest): Observable<User> {
    return null as any;
  }
  
  @PUT('/users/{id}')
  updateUser(
    @Path('id') id: number,
    @Body() user: Partial<User>
  ): Observable<User> {
    return null as any;
  }
  
  @DELETE('/users/{id}')
  deleteUser(@Path('id') id: number): Observable<void> {
    return null as any;
  }
  
  @GET('/users/{id}/posts')
  getUserPosts(
    @Path('id') userId: number,
    @Query('published') publishedOnly?: boolean,
    @Headers('Authorization') authToken?: string
  ): Observable<Post[]> {
    return null as any;
  }
  
  @FORM('/users/{id}/avatar')
  uploadAvatar(
    @Path('id') id: number,
    @Body() formData: FormData
  ): Observable<{ url: string }> {
    return null as any;
  }
}

// Use the decorated service
@Component({
  selector: "user-manager",
  providers: [UserApiService]
})
export class UserManagerComponent {
  constructor(private userApi: UserApiService) {}
  
  ngOnInit() {
    // Decorated methods work like normal service methods
    this.userApi.getUsers(1, 10, 'john').subscribe(users => {
      console.log('Users from decorated API:', users);
    });
    
    this.userApi.getUserById(1).subscribe(user => {
      console.log('User details:', user);
    });
  }
  
  createNewUser() {
    const newUser: CreateUserRequest = {
      name: 'Jane Smith',
      email: 'jane@example.com'
    };
    
    this.userApi.createUser(newUser).subscribe(created => {
      console.log('Created user via decorator:', created);
    });
  }
}

HTTP Context Tokens

Special context tokens for customizing HTTP request behavior.

/**
 * HTTP context tokens for request customization
 * Use with HttpContext to modify request behavior
 */

/** Skip custom error handling for specific requests */
const CUSTOM_ERROR: HttpContextToken<boolean>;
/** Ignore API base URL prefix for specific requests */
const IGNORE_BASE_URL: HttpContextToken<boolean>;
/** Return raw response body without parsing */
const RAW_BODY: HttpContextToken<boolean>;

Usage Examples:

import { HttpContext } from "@angular/common/http";
import { _HttpClient, CUSTOM_ERROR, IGNORE_BASE_URL, RAW_BODY } from "@delon/theme";

@Component({})
export class HttpContextExample {
  constructor(private http: _HttpClient) {}
  
  skipErrorHandling() {
    // Skip custom error interceptor for this request
    const context = new HttpContext().set(CUSTOM_ERROR, true);
    
    this.http.get('/api/risky-endpoint', {}, { context }).subscribe({
      next: data => console.log('Success:', data),
      error: err => {
        // Handle error manually since custom handler was skipped
        console.error('Manual error handling:', err);
      }
    });
  }
  
  useExternalApi() {
    // Ignore base URL for external API calls
    const context = new HttpContext().set(IGNORE_BASE_URL, true);
    
    this.http.get('https://external-api.com/data', {}, { context })
      .subscribe(data => {
        console.log('External API data:', data);
      });
  }
  
  getRawResponse() {
    // Get raw response without JSON parsing
    const context = new HttpContext().set(RAW_BODY, true);
    
    this.http.get('/api/raw-data', {}, { context }).subscribe(raw => {
      console.log('Raw response:', raw);
      // Process raw response manually
    });
  }
  
  combinedContext() {
    // Use multiple context tokens
    const context = new HttpContext()
      .set(CUSTOM_ERROR, true)
      .set(IGNORE_BASE_URL, true)
      .set(RAW_BODY, true);
    
    this.http.get('https://external-api.com/raw', {}, { context })
      .subscribe(response => {
        console.log('Combined context response:', response);
      });
  }
}

HTTP Utilities

Utility methods for URL manipulation and parameter handling.

/**
 * Parse parameters into HttpParams object
 * Handles nested objects and arrays
 */
parseParams(params: any): HttpParams;

/**
 * Apply parameters to URL
 * Appends query string parameters to URL
 */
appliedUrl(url: string, params?: any): string;

/**
 * Clear loading count manually
 * Use when loading state gets out of sync
 */
cleanLoading(): void;

Usage Examples:

import { _HttpClient } from "@delon/theme";

@Component({})
export class HttpUtilitiesExample {
  constructor(private http: _HttpClient) {}
  
  demonstrateParseParams() {
    // Complex parameters
    const complexParams = {
      page: 1,
      filters: {
        category: 'books',
        price: { min: 10, max: 50 }
      },
      tags: ['fiction', 'mystery'],
      published: true
    };
    
    const httpParams = this.http.parseParams(complexParams);
    console.log('Parsed params:', httpParams.toString());
    // Output: page=1&filters.category=books&filters.price.min=10&filters.price.max=50&tags=fiction&tags=mystery&published=true
  }
  
  demonstrateAppliedUrl() {
    const baseUrl = '/api/search';
    const params = {
      q: 'angular',
      type: 'tutorial',
      limit: 10
    };
    
    const fullUrl = this.http.appliedUrl(baseUrl, params);
    console.log('Full URL:', fullUrl);
    // Output: /api/search?q=angular&type=tutorial&limit=10
  }
  
  handleLoadingState() {
    console.log('Current loading state:', this.http.loading);
    console.log('Active requests:', this.http.loadingCount);
    
    // If loading state gets stuck, manually clear it
    if (this.http.loadingCount > 0 && !this.http.loading) {
      this.http.cleanLoading();
      console.log('Loading state cleared');
    }
  }
  
  buildDynamicRequest() {
    const endpoint = '/api/products';
    const searchParams = {
      category: 'electronics',
      price_range: '100-500',
      in_stock: true
    };
    
    // Build URL with parameters
    const requestUrl = this.http.appliedUrl(endpoint, searchParams);
    
    // Make request
    this.http.get(requestUrl).subscribe(products => {
      console.log('Products:', products);
    });
  }
}