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

apis-service

v0.0.15

Published

Create a service class for 3rd Party APIs wherein every API will be a function. The authentication will be handled internally

Readme

API Service 🚀

Do you want to interact with other microservices or third party APIs of applications such as Payment gateways, Analytics, Social media integration, Geolocation Services or any application seamlessly without having to worry about signing in & the token being expired?

  • Well, we can call any of the APIs by simply calling a function which will be calling the service's API under the hood. 😇
  • This package will take care of injecting headers, throwing the errors, parsing the data by use of a simple function. 🙀

Example

Application of the Service class 🔥

Here's an application of the Service class in the client's code. In this example, we will interact with the Blog Application. In your application, you will have to create an instance of the Blog & you will be able to call all of it's APIs.

   const blog = new Blog({
    'baseURL': 'https://reqres.in/api',
    "email": "[email protected]",
    "password": "cityslicka",
    saveDataFn: (..._args) => {
      // This function can be used for saving the newly generated token in to a file/database/storage  
    },
  })

We'll fetch a list of users with a function which will call the Blog's API under the hood. Even if the token is expired or not passed, the function will regenerate on it's own and call the API on it's own

try {    
   const getUserResult=await blog.getUser(2)
} catch (error) {
  if(error instanceof BlogClientError)  {
    // Write your code 
  } else if(error instanceof BlogInternalServerError)  {
    // Write your code 
  }
}

Implementation of Service Class ⚙️

Now, we will see how can we create a Blog class and implement the Service class to call the APIs under the hood. For better understanding, please refer to Blog.ts

1. Inheritance

We have inherited the Blog class from the Service class which will provide it's functionality by default

class Blog extends Service<BlogConfigI> {

}

2. Setting headers for authenticated APIs

Authenticated APIs require a token which you can include in the _headersInjector. Some APIs might not require a token then you can skip them with an if condition. _headersInjector() is optional because some APIs might not required tokens at all

 protected async _headersInjector(params: URLParamsI) {
    const headers: KeyStringStringI = {}
    if (![params.path.includes('/login'),params.path.includes('/register')].includes(true)) {
      headers['Authorization'] = `Bearer ${this._config.token!}`
    }
    return headers;
  }

3. GET Method's API Request

We are calling a get method's API, we're passing the method, path & id as arguments. Also, we have passed the response's interface as a generic type of the functions. After we receive the response, we are validating the data with zod. (optional). We will understand about the function in the catch block later on.

  public async getUser(id: number): Promise<GetUserResI> {
    try {
      const response = await this._apiCall<GetUserResI>({ method: 'GET', path: '/users', id })
      const { data: resData, error: resError } = GetUserResSchema.safeParse(response)
      if (resError) {
        throw new BlogResDataError(resError.errors)
      }
      return resData;
    } catch (error) {
      throw this._handleCatch(error)
    }
  }

3. POST Method's API Request

We're receiving a params which will be validated and passed as a payload in the _apiCall function have a param which is being validated before the API call. We are validating & returning the response from this function.

  public async createUser(params: CreateUserReqI): Promise<CreateUserResI> {
    try {
      const { data: reqData, error: reqError } = CreateUserReqSchema.safeParse(params)
      if (reqError) {
        throw new BlogReqDataError(reqError.errors)
      }
      const response = await this._apiCall<CreateUserResI>({ method: 'POST', path: '/users', body: reqData })
      const { data: resData, error: resError } = CreateUserResSchema.safeParse(response)
      if (resError) {
        throw new BlogResDataError(resError.errors)
      }
      return resData;
    } catch (error) {
      throw this._handleCatch(error)
    }
  }

4. We can create multiple error classes which we can use for conditional handling of the errors in the catch block

export class BlogClientError extends ServiceClientError {
  constructor(_status: number, _data: unknown | unknown[]) {
    super(_status, _data)
  }
}

5. We need to create this common _handleCatch() function for throwing the trackable errors which can be handled conditionally in that part of the code wherein this function is being called.

 protected _handleCatch(error: unknown): void {
    if (error instanceof BlogClientError) {
      const e = error as BlogClientError
      throw new BlogClientError(e.status, e.data)
    } else if (error instanceof BlogAuthError) {
      const e = error as BlogAuthError
      throw new BlogAuthError(e.status, e.data)

    } else if (error instanceof BlogReqDataError) {
      throw new BlogReqDataError(error)

    } else if (error instanceof BlogResDataError) {
      throw new BlogResDataError(error)

    } else {
      throw new BlogUnknownError(error)
    }
  }