Introduction

Carrier JS is promise based http client for browsers. It is used to interact with servers with ultimate caching feature. You can retrieve data from a URL without having to do a full page refresh. This enables a Web page to update just part of a page without disrupting what the user is doing.

Features

  1. Make XMLHttpRequest from browser
  2. Supports All Browsers
  3. Enable IndexedDB Based Caching which can store 250MB of data
  4. Data will not expire unless explicit deletion of the database (persistent storage)
  5. It decreases server round trips for fetching data from the database by persisting data in the memory.

Browser Support

Chrome Edge Firefox Opera Safari

How it works internally

This diagram shows how carrierjs internally fulfill the request with its ultimate caching feature.

CarrierJs - code flow

Installation

Using NPM
						npm install --save carrierjs
						

Using YARN
						yarn add carrierjs
						

Using cdnjs CDN
						<script src="https://cdnjs.cloudflare.com/ajax/libs/carrierjs/2.5.0/carrier.js">
						

Using jsDelivr CDN
						<script src="https://cdn.jsdelivr.net/npm/carrierjs@latest/carrier.js">
						

Using unpkg CDN
						<script src="https://unpkg.com/carrierjs@latest/carrier.js">
						

Examples

Performing a GET request:


  import carrier from 'carrierjs';
  
  // Using Promise
  carrier.get('/todos').then((result) => {
   	console.log(result)
  }).catch((err) => {
	console.log(err)
  });

  ---------

  // Using Async/Await
  async function getUser() {
 	try {
	  const response = await carrier.get('/todos')
	  console.log(response);
	} catch (error) {
	  console.error(error);
	}
  }
							

Performing a POST request:


  import carrier from 'carrierjs';
  
  const data = {
	title: "delectus aut autem",
	completed: false
  }

  // Using Promise
  carrier.post('https://jsonplaceholder.typicode.com/todos', data).then((result) => {
	console.log(result)
  }).catch((err) => {
	console.log(err)
  });

  ---------

  // Using Async/Await
  async function createUser(data) {
	try {
	const response = await carrier.post('https://jsonplaceholder.typicode.com/todos', data)
	console.log(response);
	} catch (error) {
	console.error(error);
	}
  }

  createUser(data);
							

Performing a PUT request:


  import carrier from 'carrierjs';

  const data = {
	title: "delectus aut autem",
	completed: false
  }

  // Using Promise
  carrier.put('https://jsonplaceholder.typicode.com/todos/5', data).then((result) => {
	console.log(result)
  }).catch((err) => {
	console.log(err)
  });

  ---------

  // Using Async/Await
  async function updateUser(data) {
	try {
	const response = await carrier.put('https://jsonplaceholder.typicode.com/todos/5', data)
	console.log(response);
	} catch (error) {
	console.error(error);
	}
  }

  updateUser(data);
							

Performing a PATCH request:


  import carrier from 'carrierjs';

  const data = {
	title: "delectus aut autem",
	completed: false
  }

  // Using Promise
  carrier.patch('https://jsonplaceholder.typicode.com/todos/5', data).then((result) => {
	console.log(result)
  }).catch((err) => {
	console.log(err)
  });

  ---------

  // Using Async/Await
  async function updateUser(data) {
	try {
	const response = await carrier.patch('https://jsonplaceholder.typicode.com/todos/5', data)
	console.log(response);
	} catch (error) {
	console.error(error);
	}
  }

  updateUser(data);
							

Performing a DELETE request:


  import carrier from 'carrierjs';

  // Using Promise
  carrier.delete('https://jsonplaceholder.typicode.com/todos/5').then((result) => {
	console.log(result)
  }).catch((err) => {
	console.log(err)
  });

  ---------

  // Using Async/Await
  async function deleteUser(data) {
	try {
	const response = await carrier.delete('https://jsonplaceholder.typicode.com/todos/')
	console.log(response);
	} catch (error) {
	console.error(error);
	}
  }

  deleteUser(data);
							

Request Method Aliases

For your ease, aliases have been provided for request methods.

  • carrier.get(url, [refresh], [options])
  • carrier.post(url, [data], [options])
  • carrier.put(url, [data], [options])
  • carrier.patch(url, [data], [options])
  • carrier.delete(url, [data], [options])

Note - While using this methods, url is required and data is optional. refresh is by default false. If you want to get fresh data everytime from the server, you need to send true after url parameter.

Set Request Headers

Let's see how we can use it to add request headers to an HTTP request.

Now, there are multiple ways to set request headers. The most common way is to use the headers property of the carrier object like this:


  import carrier from 'carrierjs';

  const fetchTodos = async () => {
	const result = await carrier.get(
	  'https://jsonplaceholder.typicode.com/todos/',
	  true,
	  {
		headers: {
		  'header_1': 'value_1',
		  'header_2': 'value_2'
		}
	  }
	);
	return result.response;
  };
							


You can also add these headers using a config object for a cleaner code.


  import carrier from 'carrierjs';

  const fetchTodos = async () => {
	const config = {
	  headers: {
		'header_1': 'value_1',
		'header_2': 'value_2'
	  }
	};
	const result = await carrier.get(
		'https://jsonplaceholder.typicode.com/todos/',
		config
	);

	return result.response;
  };			
							

Headers limitations

Several headers are managed exclusively by the browser, e.g. Referer and Host. The full list is in the specification.


carrier not allowed to change them, for the sake of user safety and correctness of the request.

Can’t remove a header

Another peculiarity of carrier is that one can’t undo headers.


carrier not allowed to change them, for the sake of user safety and correctness of the request.

For instance:


  const config = {
	headers: {
		'header_1': 'value_1',
		'header_1': 'value_2'
	}
  };

  // the header will be:
  // header_1: value_1, value_2
							

Response Object

The response for a request contains the following information.


{
  // `response` is the response that was provided by the server
  response: {},

  // `status` is the HTTP status code from the server response
  status: statusCode,

  // `type` is the type of response recieved from the server eg. json, script
  type: '',

  // `headers` the HTTP headers that the server responded with headers
  headers: {},

  // `request` is the request that generated this response
  request: {}

  // `url` is the url to that request is generated
  url: {}
}
							

Handling Errors

To handle errors in a standard API calls, we use a try...catch block. For example, take a look at the following code,


  import carrier from 'carrierjs';

  const fetchTodos = async () => {
    try {
	  const res = await carrier.get(`https://jsonplaceholder.typicode.com/todos/`);
    } catch (error) {
	  // Do something with the error here
    }
  };
							

If an error occurs, the catch block captures it. We need to add some logic in this block to handle the errors. We have to take care of three scenarios of errors:

  • Request is made, but the server responds with an error.
  • Request is made, but no response is received from the server.
  • When an error occurs while setting up the request.

To handle these scenarios, we can use an if-else block like this:


  try {
	const res = await carrier.get(`https://jsonplaceholder.typicode.com/todos/`);
  } catch (error) {
	if (error.response) {
	  // Request made but the server responded with an error
	} else if (error.request) {
	  // Request made but no response is received from the server.
	} else {
	  // Error occured while setting up the request
	}
  }
							

It is critical to check for the request and response properties because there will be no response property if we do not receive a response. Similarly, there will be no request property if the request is not set up. Let's take a look at these properties.

error.response

If the request is made and the server gives an error response, the error object will have a response property. It means that a 4XX or 5XX error has occurred. The response object has many properties which we can log, like the status property, which has the status code of the error.

error.request

error.request is the request object of the HTTP request that the client made. It contains information such as the HTTP method, URL, and the headers sent with the request. For CarrierJs, it is an instance of XMLHttpRequest when running in the browser and an instance of http.ClientRequest when executed in Node.js. We use it when we do not receive a valid response from the API due to a poor network or unauthorized access.

Logging Errors

We can use these properties to log errors properly. It will look like this in code:


  try {
	const res = await carrier.get(`https://jsonplaceholder.typicode.com/todos/`);
  } catch (error) {
	if (error.response) {
	  // Request made but the server responded with an error
	  console.log(error.response.status);
	  console.log(error.response.headers);
	} else if (error.request) {
	  // Request made but no response is received from the server.
	  console.log(error.request);
	} else {
	  // Error occured while setting up the request
	  console.log('Error', error.message);
	}
  }								
							

Found a problem with this page?