The Only API You Need!

Written by lukaszwronski | Published 2023/03/02
Tech Story Tags: web-development | api | openai | artificial-intelligence | typescript | javascript | open-source | npm

TLDR"The Only API" is a strongly-typed, open-source SDK with an infinite number of methods. It can be used to query for anything you need and get your data in any format you prefer. It's a product as groundbreaking as the discovery of electricity in its time - a revolution in API consumption. But of course.. it has it's secrets.via the TL;DR App

My dear readers, it brings me great pleasure to introduce my latest invention! With unbridled pride and joy, I embark on an open-source journey that will secure my place in the annals of software history.

I'm confident that with the product I am about to unveil; legendary status is inevitable! So, without further ado, let's dive right into the details.

Let me ask you - do you often find it frustrating to juggle multiple APIs and SDKs in your project? It can be a real hassle managing different dependencies and working with inconsistent patterns.

And let's not forget the time-consuming hunt for the missing pieces of functionality you desperately need. If you're nodding your head in agreement, know that you're not alone.

I've been there too, and I understand the struggle. But fear not, my friends, because I bring great news! The solution to this problem is finally here.

What I'm about to show you is a game-changer. It's a product as groundbreaking as the discovery of electricity in its time - a true revolution in API consumption. You're looking at one API that rules them all! I'm thrilled to introduce you to "The Only API".

As of now, you can instantly replace all the APIs you use with "The Only API", and experience a simplified codebase simultaneously extended with functionality more powerful than ever before.

Lol, Wait… What? How Is It Even Possible?

The answer is simple. It's because "The Only API" is just a strongly-typed, open-source SDK with an infinite number of methods, enabling you to query for anything you need and get your data in any format you prefer!

Now, I understand that the notion of an infinite number of methods and compatibility with any data format may be difficult to grasp, and you may be skeptical that this is just another hoax.

So, let me present to you a few fascinating examples of how "The Only API" can be used in practice.

Having it installed in your project, you can start with something simple:

const result = await api.getTheAnswerToLifeTheUniverseAndEverything()
                        .AsType({ answer: Number });

// { answer: 42 }

As you can see, the answer, although a bit mysterious, is in line with the current scientific consensus and all the knowledge known to humans at the time of writing this article.

But what's even more interesting is that we can use the AsType method to retrieve our response in the exact format we desire.

Of course, “The Only API“ supports an infinite number of parameters, and all possible data formats can be used as an input, starting with something simple like:

const result = await api.getTheNameOfACapital({ country: "France" })
                        .AsType({ name: String });

// { name: 'Paris' }

And if we need more data, we just change the returned data type to something more complex like in the example below:

const result = await api.getTheNameOfACapital({ country: "France" })
                        .AsType({
                            name: String, 
                            population: Number, 
                            mostFamousBuilding: String
                        });

/* 

{
  name: 'Paris',
  population: 2148271,
  mostFamousBuilding: 'Eiffel Tower'
}

And if you think it can only return a single result, then try this:

const result = await api.getBestTVShows({ 
                            page: 1, 
                            perPage: 5, 
                            orderBy: "awesomeness" 
                        })
                        .AsType([{ 
                            name: String, 
                            top3Cast: [{ 
                                actorName: String,
                                charachterName: String
                            }]
                        }]);

/*

[
    {
        "name": "Game Of Thrones",
        "top3Cast": [
            {
                "actorName": "Peter Dinklage",
                "characterName": "Tyrion Lannister"
            },
            {
                "actorName": "Emilia Clarke",
                "characterName": "Daenerys Targaryen"
            },
            {
                "actorName": "Kit Harington",
                "characterName": "Jon Snow"
            }
        ]
    },
    {
        "name": "The Big Bang Theory",
        "top3Cast": [
            {
                "actorName": "Johnny Galecki",
                "characterName": "Leonard Hofstadter"
            },
            {
                "actorName": "Jim Parsons",
                "characterName": "Sheldon Cooper"
            },
            {
                "actorName": "Kaley Cuoco",
                "characterName": "Penny Hofstadter"
            }
        ]
    },
    {
        "name": "Friends",
        "top3Cast": [
            {
                "actorName": "Jennifer Aniston",
                "characterName": "Rachel Green"
            },
            {
                "actorName": "Matt LeBlanc",
                "characterName": "Joey Tribbiani"
            },
            {
                "actorName": "Matthew Perry",
                "characterName": "Chandler Bing"
            }
        ]
    },
    {
        "name": "Breaking Bad",
        "top3Cast": [
            {
                "actorName": "Bryan Cranston",
                "characterName": "Walter White"
            },
            {
                "actorName": "Anna Gunn",
                "characterName": "Skyler White"
            },
            {
                "actorName": "Aaron Paul",
                "characterName": "Jesse Pinkman"
            }
        ]
    },
    {
        "name": "Stranger Things",
        "top3Cast": [
            {
                "actorName": "Millie Bobby Brown",
                "characterName": "Eleven"
            },
            {
                "actorName": "Finn Wolfhard",
                "characterName": "Mike Wheeler"
            },
            {
                "actorName": "Winona Ryder",
                "characterName": "Joyce Byers"
            }
        ]
    }
]

And I know that Bay Watch should be on that list, but it’s still impressive, right? All these capabilities in a single API, but that’s just a tiny fraction of it.

The possibilities do not end there. In fact, they're infinite and only limited by our imagination. If you're curious to see how "The Only API" can solve more complex problems, check out a short video I made showcasing how it can be used while coding:

https://youtu.be/bXPOLoF5HjA?embedable=true

So, How Do I Start?

At this point, I'm certain you're as excited as I am and eager to start using "The Only API" immediately. I'm sure you can already imagine how cool it will be to replace all your old APIs with this simple, elegant, and powerful alternative.

The good news is that you can do it right now! It's already published on GitHub and available to download from npm. All you need to do is install the package in your TypeScript or JavaScript project using:

npm install theonlyapi

And then create an instance of “The Only API”:

import TheApi from "theonlyapi";

const api = TheAPI("sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXX");

And that’s all…

See? The bright future of your development careers is just one “npm install” away.

Thank’s for reading this article! See you next time!

Sorry, What? What Is the API Key? Well…

Okay… you got me. As much as we all wish to have an all-knowing universal API that can do anything we ask for, "The Only API" is not a standalone product by itself. It requires a powerful engine, and the parameter needed to initialize it is your personal key to the OpenAI API.

My apologies for getting your hopes up, but that being said, allow me to explain a bit more about this project and how I came up with the idea.

It was actually quite simple to make and is very enjoyable to use - you should give it a try! It only took one afternoon to code, and the most crucial aspect is the prompt that the library sends to OpenAI.

I had to experiment with different ways of phrasing my requests and try out various completion-generation engines provided by one of the hottest companies in the IT world. Finally, I came up with this:

Return a result of an API call to the hypothetical web method "addTwoNumbers" with parameters [“21“, “37”]. Format response to fit following object signature: { “answer”: number }. Print just a response JSON.

And just to correct some of the mistakes and edge cases, and also improve the overall efficiency of the API, I’ve added the following phrase:

If some of the input data will show in output do not modify it in any way. Keep the response short. Make it a single line answer without new line characters. Minify the JSON.

Essentially, this prompt is then sent to OpenAI's "createCompletion" endpoint. The engine I selected is the latest and greatest "text-davinci-003". I also set the "max_tokens" parameter to 1024 so that the average response JSON would fit within that limit.

It works pretty decently, returning proper JSON in 9 out of 10 cases, and as you can imagine, it makes tons of mistakes and returns a lot of made up information. If you’ve played with Chat GPT, you know it will always have an answer. It just might not always be correct.

It’s Strongly Typed You Know…

The biggest challenge I’ve had was to make this really feel like a strongly typed API. Despite being limited by TypeScript’s syntax, I needed to do a few unusual things:

  • Create an object that allows running any method with any name.

  • Allow using any parameters.

  • Allow to define any return type, and actually make the result strongly typed.

  • Be able to take all this information from user calls, and put it into my prompt.

I must give huge credit to my good friend Michał, who is the best TypeScript expert I know. He helped me tremendously in overcoming some of the challenges I faced and helped me shape the library almost exactly as I wanted it.

The most valuable advice he gave me was to use JavaScript's Proxy. It allows me to create a proxy for another object, which enabled intercepting and redefining fundamental operations for that object.

Thanks to that feature, and the good old arguments keyword, I could easily grab all the call information and put it into my OpenAI prompt.

The other issue was how to create a type allowing me to run any function on it and return my “AsType” function as a result. This turned out to be quite simple:

type TheApi = {
  [key: string]: (...args: any[]) => {
    AsType: AsTypeFunction;
  };

The “AsType“ function itself. I wanted users to define the return types inline, in a very simple manner. I assumed the user can define an object and use JavaScript types like String, Number or Boolean along with arrays and nested objects to define the response format. I started with this:

type AsTypeFunction = <T extends {}>(returnType: T) => Promise<T>;

But the problem was that, for example, Number is typed into NumberConstructor in Typescript. For my purpose, it needed to be just a simple number to be used with standard number operators and inside functions requiring a number as one of its parameters.

I needed to learn how to use some mapping in type definitions, but finally, I figured out this:

type SimpleValue<Type> = Type extends NumberConstructor ? number :
                         Type extends StringConstructor ? string :  
                         Type extends BooleanConstructor ? boolean :
                         SimplifyType<Type>;

type SimplifyType<Type> = Type extends [] 
                          ? [SimpleValue<any>] 
                          : { [Key in keyof Type]
                                   : SimpleValue<Type[Key]> } 


type AsTypeFunction = <T extends {}>(returnType: T) 
                            => Promise<SimplifyType<T>>

I understand that it may seem a bit complex, but essentially, it means that if the returned type is an array, we should treat it as an array of simple values. If the returned type is an object, we should treat it as an object with keys being simple values.

Now, what exactly is a simple value? It's either a simple type, in which case we should return a number, string, or boolean, or it's another "SimplifyType" if there is a nested object. We can then resolve it using the same rules as mentioned above.

I love TypeScript's flexibility when it comes to defining types. It always amazes me!

But Why?

Normally, the best ideas come to me when I'm in the shower, but this time, it was different. I don't want to claim someone else's famous quote, but "I had a dream." You know that moment when you wake up in the morning, but then you have those extra 5 minutes of sleep with vivid dreams?

Usually, I dream about something I love, and yes, you are right - I was dreaming about coding.

In this most beautiful dream, I imagined using a single API that would have all the functionalities I needed for a project. Usually, I forget my dreams right after getting out of bed, but this time, the thought of having one API for everything stuck in my mind for a whole day.

At some point, I thought - why not? OpenAI can simulate being anything, including an API. TypeScript is probably potent enough to provide a nice interface to use it. I gave it a shot.

I understand that this PoC has no value besides being a curiosity and yet another application of the revolutionary technology we were given last year, but when we think about it...

Advanced AI language models were just born and already amaze us. I can only imagine how quickly it will evolve. Now with Bing's version of Chat GPT also able to get information from outside sources, it could probably be improved.

Somewhere along the way, an API like this could become a product made by Microsoft or another big player... We'll see.

Thank you for reading!


Written by lukaszwronski | Developer, hacker, father of two, wannabe rockstar, internet troll and meme enthusiast...
Published by HackerNoon on 2023/03/02