npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ticatec/restful_service_api

v0.1.7

Published

A lightweight TypeScript RESTful API client for browsers with error handling.

Downloads

3

Readme

@ticatec/restful_service_api

Version License: MIT

A lightweight TypeScript RESTful API client for browsers with comprehensive error handling and interceptor support.

中文版 | English

Features

  • 🚀 Lightweight: Zero dependencies, built for modern browsers
  • 🔧 TypeScript Support: Full type safety with TypeScript definitions
  • 🛡️ Error Handling: Built-in error handling with custom ApiError class
  • Interceptors: Pre and post request interceptors for authentication and data processing
  • 🎯 Flexible: Support for custom headers, timeouts, and data processors
  • 🌐 Browser-First: Designed specifically for frontend applications

Installation

npm install @ticatec/restful_service_api

Quick Start

import RestService from '@ticatec/restful_service_api';

// Your implementation of RestService interface
class MyApiClient implements RestService {
    async get(url: string, params?: any) {
        // Implementation here
    }

    async post(url: string, data: any, params?: any, contentType?: string) {
        // Implementation here
    }

    // ... other methods
}

const api = new MyApiClient();

// Make requests
const users = await api.get('/users');
const newUser = await api.post('/users', { name: 'John Doe' });

API Reference

RestService Interface

The main interface that defines the contract for REST operations:

interface RestService {
    get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any>;
    post(url: string, data: any, params?: any, contentType?: string, dataProcessor?: DataProcessor): Promise<any>;
    put(url: string, data: any, params?: any, contentType?: string, dataProcessor?: DataProcessor): Promise<any>;
    del(url: string, data: any, params?: any, contentType?: string, dataProcessor?: DataProcessor): Promise<any>;
    upload(url: string, params: any, file: File, fileKey?: string, dataProcessor?: DataProcessor): Promise<any>;
    asyncUpload(url: string, params: any, file: File, callback: UploadCallback, fileKey?: string): Promise<UploadProgress>;
    download(url: string, filename: string, params: any, method?: string, formData?: any): Promise<any>;
}

Methods

get(url, params?, dataProcessor?)

  • url: The endpoint URL
  • params: Query parameters (optional)
  • dataProcessor: Function to process response data (optional)

post(url, data, params?, contentType?, dataProcessor?)

  • url: The endpoint URL
  • data: Request payload
  • params: Query parameters (optional)
  • contentType: Content-Type header (optional, defaults to application/json)
  • dataProcessor: Function to process response data (optional)

put(url, data, params?, contentType?, dataProcessor?)

Similar to POST but for update operations.

del(url, data, params?, contentType?, dataProcessor?)

For delete operations with optional request body.

upload(url, params, file, fileKey?, dataProcessor?)

  • url: The upload endpoint URL
  • params: Additional parameters for the upload request
  • file: The File object to upload
  • fileKey: Optional form field name for the file (defaults to 'file')
  • dataProcessor: Function to process response data (optional)

asyncUpload(url, params, file, callback, fileKey?)

  • url: The upload endpoint URL
  • params: Additional parameters for the upload request
  • file: The File object to upload
  • callback: Upload callback object with progress, error, and completion handlers
  • fileKey: Optional form field name for the file (defaults to 'file')
  • Returns: Promise that resolves to UploadProgress object for cancellation

download(url, filename, params, method?, formData?)

  • url: The download endpoint URL
  • filename: The name to save the downloaded file
  • params: Download request parameters
  • method: Optional HTTP method (defaults to GET)
  • formData: Optional form data for POST downloads

Error Handling

The library includes a custom ApiError class for handling API errors:

import { ApiError } from '@ticatec/restful_service_api';

try {
    const result = await api.get('/users');
} catch (error) {
    if (error instanceof ApiError) {
        console.log('Status:', error.status);
        console.log('Code:', error.code);
        console.log('Details:', error.details);
    }
}

Types and Interceptors

import {
    PreInterceptor,
    PostInterceptor,
    ErrorHandler,
    DataProcessor
} from '@ticatec/restful_service_api';

// Pre-interceptor for adding authentication headers
const preInterceptor: PreInterceptor = (method: string, url: string) => {
    return {
        headers: {
            'Authorization': 'Bearer ' + getToken(),
            'X-Request-ID': generateRequestId()
        },
        timeout: 30000
    };
};

// Post-interceptor for response processing
const postInterceptor: PostInterceptor = async (data: any) => {
    // Process response data
    return data;
};

// Error handler
const errorHandler: ErrorHandler = (error: Error) => {
    console.error('API Error:', error);
    return true; // Return true if error is handled
};

// Data processor
const dataProcessor: DataProcessor = (data: any) => {
    // Transform response data
    return data.results || data;
};

Content Types

Pre-defined content type constants:

import {
    CONTENT_TYPE_NAME,
    TYPE_JSON,
    TYPE_HTML,
    TYPE_TEXT
} from '@ticatec/restful_service_api';

// Usage
await api.post('/upload', data, {}, TYPE_JSON);

Implementation Example

Here's a complete example implementation using the native fetch API:

import RestService, {
    ApiError,
    PreInterceptor,
    PostInterceptor,
    TYPE_JSON
} from '@ticatec/restful_service_api';

class FetchRestService implements RestService {
    private baseURL: string;
    private preInterceptor?: PreInterceptor;
    private postInterceptor?: PostInterceptor;

    constructor(baseURL: string, preInterceptor?: PreInterceptor, postInterceptor?: PostInterceptor) {
        this.baseURL = baseURL;
        this.preInterceptor = preInterceptor;
        this.postInterceptor = postInterceptor;
    }

    async get(url: string, params?: any, dataProcessor?: DataProcessor): Promise<any> {
        const queryString = params ? '?' + new URLSearchParams(params).toString() : '';
        return this.request('GET', url + queryString, null, undefined, dataProcessor);
    }

    async post(url: string, data: any, params?: any, contentType: string = TYPE_JSON, dataProcessor?: DataProcessor): Promise<any> {
        return this.request('POST', url, data, contentType, dataProcessor);
    }

    async put(url: string, data: any, params?: any, contentType: string = TYPE_JSON, dataProcessor?: DataProcessor): Promise<any> {
        return this.request('PUT', url, data, contentType, dataProcessor);
    }

    async del(url: string, data: any, params?: any, contentType: string = TYPE_JSON, dataProcessor?: DataProcessor): Promise<any> {
        return this.request('DELETE', url, data, contentType, dataProcessor);
    }

    private async request(method: string, url: string, body?: any, contentType?: string, dataProcessor?: DataProcessor): Promise<any> {
        const fullUrl = this.baseURL + url;

        // Apply pre-interceptor
        const interceptorResult = this.preInterceptor?.(method, fullUrl) || { headers: {} };

        const headers = {
            ...interceptorResult.headers,
            ...(contentType && { 'Content-Type': contentType })
        };

        try {
            const response = await fetch(fullUrl, {
                method,
                headers,
                body: body ? JSON.stringify(body) : undefined,
                signal: interceptorResult.timeout ? AbortSignal.timeout(interceptorResult.timeout) : undefined
            });

            if (!response.ok) {
                const errorData = await response.json().catch(() => ({}));
                throw new ApiError(response.status, errorData);
            }

            let data = await response.json();

            // Apply post-interceptor
            if (this.postInterceptor) {
                data = await this.postInterceptor(data);
            }

            // Apply data processor
            if (dataProcessor) {
                data = dataProcessor(data);
            }

            return data;
        } catch (error) {
            if (error instanceof ApiError) {
                throw error;
            }
            throw new ApiError(0, { code: 'NETWORK_ERROR', message: error.message });
        }
    }
}

// Usage
const api = new FetchRestService('https://api.example.com');
const users = await api.get('/users');

File Upload and Download Examples

import RestService, { 
    UploadCallback, 
    UploadProgress 
} from '@ticatec/restful_service_api';

// Simple file upload
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
const file = fileInput.files[0];

try {
    const result = await api.upload('/upload', { userId: 123 }, file);
    console.log('Upload successful:', result);
} catch (error) {
    console.error('Upload failed:', error);
}

// Async upload with progress tracking
const uploadCallback: UploadCallback = {
    method: 'POST',
    progressUpdate: (uploadedBytes: number) => {
        console.log(`Uploaded: ${uploadedBytes} bytes`);
    },
    handleError: (error: Error) => {
        console.error('Upload error:', error);
    },
    onCompleted: (data: any) => {
        console.log('Upload completed:', data);
    }
};

const uploadProgress = await api.asyncUpload('/upload', { userId: 123 }, file, uploadCallback);

// Cancel upload if needed
setTimeout(() => {
    uploadProgress.cancel();
}, 5000);

// File download
try {
    await api.download('/files/document.pdf', 'my-document.pdf', { userId: 123 });
    console.log('Download completed');
} catch (error) {
    console.error('Download failed:', error);
}

// POST download with form data
const formData = { reportType: 'monthly', format: 'pdf' };
await api.download('/reports/generate', 'monthly-report.pdf', {}, 'POST', formData);

Utility Functions

The library includes utility functions for common operations:

import utils from '@ticatec/restful_service_api/utils';

// Convert object to query string
const queryString = utils.toQueryString({ name: 'John', age: 30 });
// Returns: "name=John&age=30"

// Combine URL with parameters
const fullUrl = utils.combineUrl('/api/users', { page: 1, limit: 10 });
// Returns: "/api/users?page=1&limit=10"

// Generate HTTP request options
const options = utils.generateRequestOptions('POST', { id: 1 }, { name: 'John' });
// Returns: { method: 'POST', headers: {}, params: { id: 1 }, data: { name: 'John' } }

// Clean parameters (removes null, undefined, empty strings, trims values)
const cleanedParams = utils.cleanParams({ name: ' John ', age: null, email: '' });
// Returns: { name: 'John' }

// Function utilities
utils.invokeFunction(callback, arg1, arg2); // Safely invoke function if it exists
const isFunc = utils.isFunction(someValue); // Check if value is a function

Available Utility Functions

  • toQueryString(obj): Converts an object to URL query string
  • combineUrl(url, params): Combines URL with query parameters
  • generateRequestOptions(method, params, data): Generates HTTP request options
  • cleanParams(params): Cleans parameters by removing null/empty values and trimming strings
  • isFunction(value): Checks if a value is a function
  • invokeFunction(func, ...args): Safely invokes a function if it exists

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see the LICENSE file for details.

Author

Henry Feng


For more examples and advanced usage, please check the documentation.