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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@klient/core

v1.5.2

Published

Extendable library able to build advanced http client

Downloads

5

Readme

Klient

badge-coverage


Introduction

Concept

Klient is a very light weight library able to build any kind of http client. It's wrapping the amazing Axios library for executing requests. Klient purposes to emit events before and after a request execution, whose allows to customize request or perform action in specific moment of request lifecycle.

During an event propagation, the listeners are called one by one sorted by their own defined priority. They can access to current request, the current response or eventual errors. In specific cases, a listener can also suspend temporary the request process to realize an async task (for exemple, to refresh credentials).

Klient is modulable by using extensions, parameters and services, a way to reuse features across all of your projects. Fully configurable, Klient is perfect to build the most adapted client for your target webservice.

Why should I use Klient ?

  • I need to make http requests on my website or in a node project

  • I need a way to make my http requests evolutive

  • I want to work on my front project but the target webservice is not ready yet

  • I love to enable many features by using extensions simply

  • I want to produce readable and reusable code

  • My project is using Typescript

See below the list of official extensions, useful to configure a Klient instance quickly :

| Name | Description | Available | |-----------------------------------------------------|--------------------------------------------------|------------| | @klient/jwt | Manage authentication using JWT | ✅ | | @klient/rest | Manage resources for REST API | ✅ | | @klient/mock | Mock responses for specific requests | ✅ | | @klient/cache | Limit api calls by caching responses | ❌ | | @klient/offline | Purpose an offline mode | ❌ | | @klient/graphql | Perform graphql queries | ❌ | | @klient/soap | Consume SOAP APIs | ❌ |

Requirements

Installation

Install core package with your favorite package manager :

# As axios is many used, we recommand you to install it in your dependencies
# to avoid reference conflict between multiple version used by node_modules packages
# npm install axios@0

# With NPM
$ npm install @klient/core

# With YARN
$ yarn add @klient/core

All in one example

You can also refer to official example project of Klient packages, used in a web project based on React which consumes a fully mocked REST API

import Klient from '@klient/core';

//
// Import practical extensions we will use
//
import '@klient/rest';
import '@klient/jwt';



//
// -> @klient/core : Execute listenable HTTP Request
//

//
// We need to configure a Klient instance for the target webservice
// The klient object will representing like an "SDK" of your API
// Usually we will need one Klient instance per host to consume
//
const klient = new Klient({
  url: 'http://example.rest/api',                   // Target host
  debug: true,                                      // Debug mode
  extensions: ['@klient/jwt', '@klient/rest'],      // Optionally specify extensions to load
  request: {                                        // Static Axios request config for every request
    headers: {
      'Content-Type': 'application/json',
    }
  }
});


//
// Listen for requests made with a klient instance
// 'request' event is dispatched before request execution
//
klient.on('request', event => {
  console.log(
    event.request,  // Request Promise object
    event.config,   // Axios request config
    event.context,  // Request context
  );

  // For example, customize request config by appending an header to all requests
  event.config.headers.RequestedWith = 'Klient';
});

//
// Listen for other events
//
// klient.on('request:success', e => {...});   // After execution in success case   (contains response)
// klient.on('request:error', e => {...});     // After execution in failure case   (contains error)
// klient.on('request:done', e => {...});      // Last event dispatched             (contains result)


//
// Execute requests in same way as you do with Axios instance (will invoke listeners !)
//
klient
  .request({
    url: '/posts',
    method: 'GET',
    context: {                   // context is special key usable by listeners
      someCustomValue: '...'     // where you can define any useful value
    }
  })
  .then(axiosResponse => {
    console.log(
      axiosResponse.data,    // Get response content
      axiosResponse.status,  // Get response status
      // ...
      // Please refer to Axios documentation for more details
    );
  })
  .catch(axiosError => {
    console.log(
      axiosError.response,  // Get Response
      axiosError.request,   // Get Request configuration
      // ...
      // Please refer to Axios documentation for more details
    );
  })
;

//
// Others useful request methods (see Klient API for more details)
//
// klient.get('/posts');
// klient.post('/posts', { title: 'How to win 150K $ in 5 minutes' });
// klient.put('/posts/1', { title: 'Who would win between a lion and a tiger' });
// klient.delete('/posts/1');
//
// ... + all verbs provided by Axios API (head, options, ...)

//
// Special method for retrieving server file as Blob object
//
klient.file('/medias/pie_recipe.pdf').then(blob => {
  // Make user download file ?
});



//
// -> @klient/rest : Configure "resource" for consuming REST API
//

//
// Step 1 - Register a resource
//
// We will register a "Resource", usable after as a service. It will be the "repository" of a single resource in API.
// By default, it allows to you to perform create|read|list|update|delete actions according to REST principles.
//
klient.register('Post', '/posts');


//
// Step 2 - Call any resource CRUD action, automatically configured. Don't reinvent the wheel...
//
klient
  .resource('Post')
  .create({
    title: 'My first post',
    description: 'Not in the mood, I should ask Chat GPT to handle this part...'
  })
  .then((responseData) => {
    // Hide a form, show a success message, redirect user, sell data to China ? 
  })
  .catch((axiosError) => {
    // Display an error, handle validation error, tell the user it is his fault ? 
  })
;


//
// Optionally listen for request executed with a Resource instance
//
klient.on('request', event => {
  const { action, rest, resource } = event.context;

  if (action === 'create' && rest === true && resource === 'Post') {
    // A Post is going to be created
  }
});


//
// -> Add custom actions for some resources ? No Problemo !
//

//
// Step 1 - Create a resource class
//
// A Resource is a service usable anywhere in your code, supposed to manage a single resource in API
// It can be considerated as a "repository". The "Resource" class contains the default create|read|list|update|delete methods.
//
import { Resource } from '@klient/rest';

class PostResource extends Resource {
  constructor() {
    // Alias, entrypoint
    super('Post', '/posts');
  }

  //
  // Defines as many methods you need in your resource
  //
  enable(itemOrId, enable = true) {
    return this.request({                     // This method returns a Promise fulfilled with Response.data result
      url: this.uri(itemOrId, 'enable'),      // Build the entrypoint uri like /posts/<id>/enable
      data: { enable },                       // Request body content
      method: 'PUT',                          // The expected method
      context: {                              // Set context values usable by listeners
        action: 'enable'
      }
    });
  }
}


//
// Step 2 - Register your custom resource
//
klient.register(new PostResource());


//
// Step 3 - just call any custom action defined in your Resource class
//
klient
  .resource('Post')
  .enable(1, true)
  .then(() => {
    console.log('We enabled the post #1 !');
  })
;



//
// -> @klient/jwt : Authenticate your request with JWT
//

//
// Step 1 - Configure request made for authentication
//
// Please refer to @klient/jwt documentation for more details
//
klient.parameters.set('jwt', {
  // Configure token entrypoint (can be fully overrided using "map" and "configure" option)
  login: {
    url: '/auth',
    method: 'POST',
  },
  // Configure refresh token entrypoint (optional) (can be fully overrided as login)
  refresh: {
    url: '/auth/refresh',
    method: 'POST',
  },
  // Persist authentication state in a cookie (optional)
  storage: {
    type: 'cookie',        // Also available : localStorage | static
    options: {             // See @klient/storage for available options per storage type
      name: 'auth_token',
      path: '/'
    }
  }
});


//
// Step 2 - Optionally listen for JWT events
//
klient
  .on('jwt:authenticate', () => {
    // My user has getting a new token, maybe we should make him appear as logged in my app
  })
  .on('jwt:expired', () => {
    // Oops, credentials has been detected as expired, maybe we should redirect user to login page ?
  })
;


//
// Step 3 - Log the user in!
//
klient
  // Fetch a token with credentials as expected in your API
  .login({ username: '...', password: '...' })
  .then(() => {
    // At this point, the event "jwt:authenticate" has been emitted
    // and every new request will contains the fetched token in header "Authorization"
    // Tt will be added by a listener (on request event) declared by @klient/jwt extension
    // The automatic request authentication can be disabled by defining context.authenticate to false.
  })
;


//
// Step 4 - Automatically execute authenticated request
//
// The request config will be hydrated as below :
//
// {
//   url: '/private',
//   method: 'GET',
//   headers: {
//     'Authorization': 'Bearer <token>',
//     'Content-Type': 'application/json',
//   }
// }
//
klient
  .get('/private')
  .then(axiosResponse => {
    // Too much posts fetched with so few lines, Mouahaha
  })
  .catch(axiosError => {
    // No way ! My user is certainly authenticated, so what's happening now !?
  })
;

TOC   >   Introduction   >   Usage   >   Events   >   Request   >   Extensions   >   Utilities   >   API