All files / core/src/http http.ts

100% Statements 249/249
100% Branches 14/14
100% Functions 10/10
100% Lines 249/249

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 2501x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 1x 1x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 17x 17x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 1x 1x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 1x 1x 1x 1x 1x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 4x 4x 4x 4x 4x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 1x 1x 1x 1x 1x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 2x 2x 2x 2x 71x 71x 71x 71x 71x 71x 71x 1x 1x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 71x 27x 27x 27x 53x 27x 27x 1x 1x  
import { Observable } from 'rxjs';
import { ajax, AjaxConfig, AjaxResponse } from 'rxjs/ajax';
import { Linker } from '../linker/linker';
import { Alias } from '../typing/alias';
import { Proxy } from './proxy';
 
/**
 * The **Http** namespace contains types and interfaces used and intended to be
 * used in conjunction with the abstract {@link Http} class.
 *
 * @see {@link Http}
 */
export namespace Http {
 
  /**
   * The **Request** type alias references the {@link AjaxConfig} interface and
   * describes the shape of any {@link Http} **Request** parameters.
   */
  export type Request = Alias<AjaxConfig>;
 
  /**
   * The **Response** type alias references the {@link AjaxResponse} class and
   * describes the shape of any {@link Http} **Response**.
   *
   * @typeParam T - The **Response** type of a {@link Request}.
   */
  export type Response<T = any> = Alias<AjaxResponse<T>>;
 
  /**
   * The **Handler** interface enforces the {@link handle} method with
   * {@link ajax} compliant typing on the implementing class or object. This
   * contract is used by the {@link Proxy} to type-guard the next hops.
   */
  export interface Handler {
 
    /**
     * Generic **handle** method enforcing {@link ajax} compliant typing. The
     * method signature corresponds to that of the {@link ajax} method itself.
     *
     * @param request - Requesting {@link Request}.
     * @returns An {@link Observable} of the requested {@link Response}.
     */
    handle(request: Request): Observable<Response>;
 
  }
 
}
 
/**
 * The abstract **Http** class is a thin wrapper around the {@link ajax} method.
 * The main function of this wrapper is to pipe all requests through a chain of
 * classes extending the abstract {@link Proxy} class. Thereby interceptors for
 * various requests can be implemented to, e.g., provide API credentials etc.
 *
 * @see {@link Proxy}
 */
export abstract class Http implements Http.Handler {
 
  /**
   * Fires an {@link Http} **delete** request against the supplied `url` upon
   * subscription.
   *
   * @param url - The `url` to {@link Http} **delete**.
   * @typeParam T - The {@link Http.Response} type.
   * @returns An {@link Observable} of the {@link Http.Response}.
   *
   * @example
   * Fire an HTTP **delete** request against `https://example.com`:
   * ```ts
   * import { Http } from '@sgrud/core';
   *
   * Http.delete('https://example.com').subscribe(console.log);
   * ```
   */
  public static delete<T>(url: string): Observable<Http.Response<T>> {
    return this.prototype.handle<T>({ method: 'DELETE', url });
  }
 
  /**
   * Fires an {@link Http} **get** request against the supplied `url` upon
   * subscription.
   *
   * @param url - The `url` to {@link Http} **get**.
   * @typeParam T - The {@link Http.Response} type.
   * @returns An {@link Observable} of the {@link Http.Response}.
   *
   * @example
   * Fire an HTTP **GET** request against `https://example.com`:
   * ```ts
   * import { Http } from '@sgrud/core';
   *
   * Http.get('https://example.com').subscribe(console.log);
   * ```
   */
  public static get<T>(url: string): Observable<Http.Response<T>> {
    return this.prototype.handle<T>({ method: 'GET', url });
  }
 
  /**
   * Fires an {@link Http} **head** request against the supplied `url` upon
   * subscription.
   *
   * @param url - The `url` to {@link Http} **head**.
   * @typeParam T - The {@link Http.Response} type.
   * @returns An {@link Observable} of the {@link Http.Response}.
   *
   * @example
   * Fire an HTTP **head** request against `https://example.com`:
   * ```ts
   * import { Http } from '@sgrud/core';
   *
   * Http.head('https://example.com').subscribe(console.log);
   * ```
   */
  public static head<T>(url: string): Observable<Http.Response<T>> {
    return this.prototype.handle<T>({ method: 'HEAD', url });
  }
 
  /**
   * Fires an {@link Http} **patch** request against the supplied `url`
   * containing the supplied `body` upon subscription.
   *
   * @param url - The `url` to {@link Http} **patch**.
   * @param body - The `body` of the {@link Http.Request}.
   * @typeParam T - The {@link Http.Response} type.
   * @returns An {@link Observable} of the {@link Http.Response}.
   *
   * @example
   * Fire an HTTP **patch** request against `https://example.com`:
   * ```ts
   * import { Http } from '@sgrud/core';
   *
   * Http.patch('https://example.com', {
   *   data: 'value'
   * }).subscribe(console.log);
   * ```
   */
  public static patch<T>(
    url: string,
    body: unknown
  ): Observable<Http.Response<T>> {
    return this.prototype.handle<T>({ body, method: 'PATCH', url });
  }
 
  /**
   * Fires an {@link Http} **post** request against the supplied `url`
   * containing the supplied `body` upon subscription.
   *
   * @param url - The `url` to {@link Http} **post**.
   * @param body - The `body` of the {@link Http.Request}.
   * @typeParam T - The {@link Http.Response} type.
   * @returns An {@link Observable} of the {@link Http.Response}.
   *
   * @example
   * Fire an HTTP **post** request against `https://example.com`:
   * ```ts
   * import { Http } from '@sgrud/core';
   *
   * Http.post('https://example.com', {
   *   data: 'value'
   * }).subscribe(console.log);
   * ```
   */
  public static post<T>(
    url: string,
    body: unknown
  ): Observable<Http.Response<T>> {
    return this.prototype.handle<T>({ body, method: 'POST', url });
  }
 
  /**
   * Fires an {@link Http} **put** request against the supplied `url` containing
   * the supplied `body` upon subscription.
   *
   * @param url - The `url` to {@link Http} **put**.
   * @param body - The `body` of the {@link Http.Request}.
   * @typeParam T - The {@link Http.Response} type.
   * @returns An {@link Observable} of the {@link Http.Response}.
   *
   * @example
   * Fire an HTTP **put** request against `https://example.com`:
   * ```ts
   * import { Http } from '@sgrud/core';
   *
   * Http.put('https://example.com', {
   *   data: 'value'
   * }).subscribe(console.log);
   * ```
   */
  public static put<T>(
    url: string,
    body: unknown
  ): Observable<Http.Response<T>> {
    return this.prototype.handle<T>({ body, method: 'PUT', url });
  }
 
  /**
   * Fires a custom {@link Http.Request}. Use this method for more fine-grained
   * control over the outgoing {@link Http.Request}.
   *
   * @param request - The {@link Http.Request} to be **request**ed.
   * @typeParam T - The {@link Http.Response} type.
   * @returns An {@link Observable} of the {@link Http.Response}.
   *
   * @example
   * Fire an HTTP custom request against `https://example.com`:
   * ```ts
   * import { Http } from '@sgrud/core';
   *
   * Http.request({
   *   method: 'GET',
   *   url: 'https://example.com',
   *   headers: { 'x-example': 'value' }
   * }).subscribe(console.log);
   * ```
   */
  public static request<T>(
    request: Http.Request
  ): Observable<Http.Response<T>> {
    return this.prototype.handle(request);
  }
 
  /**
   * Private **constructor** (which should never be called).
   *
   * @throws A {@link TypeError} upon construction.
   */
  private constructor() {
    throw new TypeError('Http.constructor');
  }
 
  /**
   * Generic **handle** method, enforced by the {@link Http.Handler} interface.
   * Main method of the this class. Internally pipes the `request` through all
   * linked classes extending {@link Proxy}.
   *
   * @param request - The {@link Http.Request} to be **handle**d.
   * @typeParam T - The type of the **handle**d {@link Http.Response}.
   * @returns An {@link Observable} of the {@link Http.Response}.
   */
  public handle<T>(request: Http.Request): Observable<Http.Response<T>> {
    const proxies = new Linker<typeof Proxy>().getAll(Proxy);
 
    return (function handle(next: Http.Request): Observable<Http.Response<T>> {
      return proxies.shift()?.handle(next, { handle }) || ajax(next);
    })(request);
  }
 
}