JET-FETCH::REST APIs' developers' new girlfriend

JET-FETCH::REST APIs' developers' new girlfriend

Developed and maintained by the author of this article.

·

9 min read

So a few hours back, approximately 70 hours from now, we entertain the emersion of a new year -2023, I love calling it the new dawn of technology, to some forks, it is the chatGPT year :). 2022 was a beautiful year for me. To shortlist a few achievements I had below:-

  • Graduated with a bachelor's degree in Computer from one of the best universities in SSA -Mbarara University of Science and technology.

  • Got my first official job as a Senior Software Engineer with Service Cops Uganda LTD.

  • Got assigned the department of internship at the same company to do what I do best -share knowledge(my way of learning)

  • Became an independent citizen of the country-the pearl of Africa, which also comes at a cost of paying huge amounts of taxes I wasn't well informed of!

  • Learnt Golang(with gin and gorm frameworks), advanced my react native, and then learned the amazing two frameworks Yii2 and Spring Boot which am so glad I now know!

Sounds a lot, but here is the secret, the best part of my year is not among all the above, the day I published jet-fetch on npm was the most awesome!

Inspiration and background of jet-fetch.

Before I learned all those scary things shared above, I was a full-stack developer with incredible skills in JS(yeah, the current song of the day). I loved accomplishing my front-end using Vuejs - sweetest, most minimal, brief to the point(my reasons for choosing Vuejs) and Django RestFramework. I really love the combination of the two frameworks since they have almost similar docs and somehow similar syntax yet different architectures!!

With the two, I used to design my APIs and consume them using Axios - yes(apparently my third best HTTP library after ..... you guessed it right, jet-fetch and fetch itself). Axios has tried to solve almost 80% of my problems as a developer who is obsessed with speed, independency, code reuse, and add yours too... but somewhere somehow Axios started losing me!

  1. Constantly repeating myself on JWT authentication -- well I love interceptors in Axios but, they are ambiguous and in the hands of a beginner or bad developer, they may lead to catastrophic effects to the whole codebase yet for every project, I had to keep re-writing these interceptors to keep injecting JWT tokens from wherever I had kept them!!

  2. As my friends usually tell me, less is better, most of the fetch libraries have tried to implement a lot of features and ended up getting verbose.

  3. Fetch API just got better but not the best yet! This defines why most devs have not actually used fetch in most of their projects.

  4. Level of customization, I usually find a hard time trying to customize most of the HTTP libraries and staying minimal to the point!!

  5. Well just like everyone, I wanted my own! Add staff as I want, but now I have lost this as devs have tried to make me remake jet-fetch to their needs, but I keep mine in mind!

What is jet-fetch?

jet-fetch is a combination of two terms jet and fetch, jet is the nickname of the author which stands for my name, Junior Ezra Tumusiime(JET) but also a good term for reference to speed, or fast-moving! Fetch is an HTTP library in Js and Nodejs for performing HTTP requests, that is, communications between clients and Restful APIs.

Now you know the inspiration for the name, jet-fetch - faster fetch or better put, enhanced fetch API. It adds a small layer to fetch itself, and working with fetch itself in jet-fetch is surely seamless!

Getting started with jet-fetch

jet-fetch is available on npm and you can check it out by clicking here. It's in the dawn of its development and should be ready to work in all Nodejs projects.

Installation

With npm,

npm i jet-fetch

With yarn

yarn add jet-fetch

Importation and Initialization

You can import it as a normal node module as below

import Jet from "jet-fetch"

Then you can initialize the class with the defaults as illustrated below.

  1. Initialization without the baseUrl, implies that for each request, a full URL will be provided with both the relative and absolutes parts provided.
let jet = new Jet()
  1. Initialize with the baseUrl : This implies that all the requests have one origin and just pass the relative paths to the base to form the complete URL.

     let jet = new Jet(baseUrl = "http:localhost:8080/api/v1/")
    

    With JWT authentication in mind.

    Did I mention that I was tired of writing the same interceptors for every project I did while using Axios to add JWT authentication, well, here is how jet-fetch is saving me now!!

  2. If your application is using JWT authentication and you store this in the local storage as Bearer, then jet-fetch has got you covered. Please note the conditions defined, the JWT must be stored in the localStorage as bearer, but if that's not your case, then jump ahead.

     let jet = new Jet(
         baseUrl = "http:localhost:8080/api/v1/",
         interceptWithJWTAuth = true // notice this here!.
     )
    

    And that's it, with just that, jet-fetch will try to load the token from the local storage and send it to your backend in the headers as Authorization: Bearer <token> .

  3. If your backend does not expect this token as Bearer maybe as JWT or Token then you can add one more parameter to your class initialization.

     let jet = new Jet(
         baseUrl = "http:localhost:8080/api/v1/",
         interceptWithJWTAuth = true,
         sendTokenAs="Token" // notice this  
     )
    
  4. If your token is not stored as Bearer in your local storage but maybe as my_key and you want to tell jet-fetch to look for my_key instead of looking for Bearer, you can add one more extra parameter.

     let jet = new Jet(
         baseUrl = "http:localhost:8080/api/v1/",
         interceptWithJWTAuth = true,
         tokenBearerKey="my_key" // notice this
     )
    
  5. All the steps are very okay if your token is kept in local storage, but as you already know, it is not wise to keep your token in local storage, and anyway, we also have a lot of options for this job. We can choose to keep this key in sessionStorage, realmdb, or as a cokie.

    To customize this, you need to hand over a function to run on initialization to get the token, this function or parameter should when executed, return the token itself as below. Imagine, am keeping mine in sessionStorage.

     const my_hidden_token = sessionStorage.getitem("my_key");
     let jet = new Jet(
         baseUrl = "http:localhost:8080/api/v1/",
         interceptWithJWTAuth = true,
         token = my_hidden_token // notice this
     )
    

    Defining token tells jet-fetch not to check in localStorage for the token, but to execute the variable passed in the token and trust it to return the JWT. But remember, with the above, the token will be sent as Bearer to change that, you can now use our previously illustrated sendTokenAs and pass in how you want your backend to receive the token as, but this is in most common instances sent as Bearer, the default in the package too!

  6. You can then export this instance and start using it in your application with export default jet .

    The following will assume you have accomplished the initialization and you are ready to ride!!

Another note to take, jet-fetch by default supports five methods post, get, delete, put, patch and provides the most beautiful and powerful part of it, the custom method which lets you configure your own method with your knowledge of fetch API.

Also, by default, jet-fetch returns reponse as json .

Example get request with jet-fetch

//... 
import jet from "path-to-jet-class-initialization-file" // import your class definition
get(url="users", headers={}, config={})
  .then(res => console.log(res.data))
  .catch(err => console.debug(res.response.statusText))

The reason why I started with get is that, unlike other methods, get does not take up a body object.

Also, not that the response has two parts:-

  1. data : This is the actual from the server, as an object.

  2. response : This hole the entire request data, from the url , status , headers . You can read more about the fetch response body from MDN Docs here.

The rest of the request verbs are kinda the same, let's take a sample of the post before I describe for you the params taken up by the methods.

let data = {username: "jet", password:12345}

jet.
  post("users", data, headers={}, config={})
  .then(res => res.data)

Note that here we have added an extra field data which is your request body.

Let's understand these parameters.

  1. The first param is the endpoint. This can the absolute URL if the baseUrl was not defined on class initialization, but if it was, only paths that are relative to your baseUrl should be passed here. An example, users will be appended to the http:localhost:8080/api/v1/ form http:localhost:8080/api/v1/users as your endpoint.

  2. data : This is the request body, defaults, to json but if you understand tweaking fetch , you can tweak it here too. But preferred is json .

  3. headers : In the first versions, these were part of the config and even now if you defined a config as headers, they will be picked out and sorted out. This object contains the headers you want to define for your request. Separation of this is a result of trying to cater a feature update of defining default headers on the class instantiation.

  4. config : This contains any other valid fetch config you would want to add to play with your API. As said above, passing the headers in here is okay, as they will be picked out and merged with the other headers.

So the above methods are not doing what you want, then you can define your own as below using the custom method.

jet
  .custom(url, type, body = {}, headers={}, config = {})
  .then((res) => {
    // do something with the response
  })
  .catch((err) => {
    // do something with the error
  });

There is one more added parameter, and that is type , this is any valid request verb among those accepted by fetch you can define and use. This intends to help you to add any other verbs that were not added by default by the package itself.

Hooo! finally, you got a new era of communicating your APIs. But that's not all, if you are into Open Source, you can help us improve the package and even add your own new staff you would wish to see!

Contributing to jet-fetch.

First of all, I would like to extend my sincere appreciation to those who have already shown interest in the library by using it, contributing to it, advised on my socials. We really appreciate your contributions.

Currently, the library has moved from my own account to the OSCA-KAMPALA organization on GitHub and the repository is called jet-fetch

  1. Fork the repository, don't forget to star it too :).

  2. Open an issue, and we discuss your update before you start working on it.

  3. Submit your PR which will be discussed, don't forget to test it locally before you submit it.

  4. Then wait for that beautiful lucky day when your PR gets merged!!!

Thanks for reading up this far, any issues you find in the package, please go ahead and file an issue defined above.

Happy hacking, happy 2023!