JET-FETCH::REST APIs' developers' new girlfriend
Developed and maintained by the author of this article.
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!
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!!
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.
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.
Level of customization, I usually find a hard time trying to customize most of the HTTP libraries and staying minimal to the point!!
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.
- 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()
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!!
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 thelocalStorage
asbearer
, 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>
.If your backend does not expect this token as
Bearer
maybe asJWT
orToken
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 )
If your token is not stored as
Bearer
in your local storage but maybe asmy_key
and you want to tell jet-fetch to look formy_key
instead of looking forBearer
, you can add one more extra parameter.let jet = new Jet( baseUrl = "http:localhost:8080/api/v1/", interceptWithJWTAuth = true, tokenBearerKey="my_key" // notice this )
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 thetoken
and trust it to return the JWT. But remember, with the above, the token will be sent asBearer
to change that, you can now use our previously illustratedsendTokenAs
and pass in how you want your backend to receive the token as, but this is in most common instances sent asBearer
, the default in the package too!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:-
data
: This is the actual from the server, as an object.response
: This hole the entire request data, from theurl
,status
,headers
. You can read more about thefetch
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.
The first param is the
endpoint
. This can theabsolute
URL if thebaseUrl
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 thehttp:localhost:8080/api/v1/
formhttp:localhost:8080/api/v1/users
as your endpoint.data
: This is the request body, defaults, tojson
but if you understand tweakingfetch
, you can tweak it here too. But preferred isjson
.headers
: In the first versions, these were part of theconfig
and even now if you defined aconfig
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.config
: This contains any other validfetch
config you would want to add to play with your API. As said above, passing theheaders
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
Fork the repository, don't forget to star it too :).
Open an issue, and we discuss your update before you start working on it.
Submit your PR which will be discussed, don't forget to test it locally before you submit it.
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!