Developing and Publishing a Typescript-based SDK
Published: 2023-05-08 21:56:28

A Software Development Kit (SDK) is a set of development tools, libraries, documentation, and sample code that allows developers to create applications for a specific platform or system. 

SDKs are used to make it easier and faster for developers to build applications that interact with a particular system, by providing pre-built components and APIs that abstract away the complexity of the system.

Say you want to interact with 3rd party APIs, if there was no SDK, you would have to write the HTTP client, manage authentication, do the error handling, and so on.

Having an SDK provides a better developer experience and it allows the developers to use your APIs in the right way.

TypeScript has gained popularity as a preferred language for building SDKs due to its strong typing and maintainability features. 

In this article, we will discuss how to develop a simple SDK with TypeScript. This SDK will connect to the JSON Placeholder API for fetching posts, creating and retrieving a particular post from the API. We will then also publish it on the npm registry.

**The full code implementation can be found on this [repo](https://github.com/jamesoyanna/typescript-sdk/tree/master/sdk)**

### Setting up our development environment:
The first step is to set up the development environment. This involves installing Node.js and TypeScript on your computer, as well as any other dependencies that you might need. 

Create a folder in your computer and name it `typescript-sdk`
Navigate into the folder and open your command line in it.

Create a new folder inside the `typescript-sdk` folder, call it sdk. Navigate into it from the command line by typing cd sdk.

Inside the sdk folder, initialize a new project using the command `npm init -y`.
A package.json file will automatically be created on it for you.

Now let install the dependencies we will be needing for this project using this commands:

`npm install microbundle`

`npm install typescript@latest -g`

`npm install isomorphic-unfetch`

 Microbundle- Microbundle is a tool used for bundling JavaScript code into a single, self-contained file that can be used in web applications or other software projects. 

It is particularly useful for developing libraries or modules that need to be distributed in a standalone format.

Now, lets add the necessary details to our package.json file.
Open the package.json file and update the following

Change `"main": "index.js",` to  `"main": "dist/index.js",`. 

In the script section, add this script:
`"build": "rm -rf dist && microbundle --tsconfig tsconfig.json --no-sourcemap",`

Now create a `tsconfig.json` file - You can either create it manually or by running this command:
`tsc --init`

Remove the default configuration in the `tsconfig.json` file and add the one below:

```

{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "allowSyntheticDefaultImports": true,
    "target": "es2017",
    "sourceMap": false,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "test", "lib", "**/*spec.ts"]
}
```
In your project folder create a new folder and name it `src`. Create two files - `index.ts` and `base.ts` inside the `src` folder.

Inside the base.ts file add the following code:
{% gist https://gist.github.com/jamesoyanna/a331330580d17597e2a59e2d8e6aba26 file=base.ts%}

Here in this code, we define a Base class which is to be used as a base class for other classes that need to make API requests. 

The class has two private properties, `apiKey` and `baseUrl`, and a constructor that takes a configuration object containing an API key and an optional base URL.

This Base class also has a protected method called request that makes an HTTP request to the API. The method takes an endpoint path and an optional `RequestInit` object, which can be used to pass additional options to the fetch function.

Inside the request method, the base URL and API key are used to construct the full URL for the API endpoint. 

A headers object is also created, which includes the API key and sets the content type to JSON.

The `Object.assign` method is then used to merge the options parameter with the headers object, creating a new config object that can be passed to the fetch function.

The fetch function is then called with the full URL and the config object, and the response is stored in the `response` variable. 

If the response is OK (i.e. the status code is in the 200-299 range), the JSON response data is extracted using the response.json() method and returned as the requested type T. 

If the response is not OK, an error is thrown with the response status text as the error message.

Now lets implement our post methods.

Inside your `src` folder, create another folder called posts and inside the posts folder you just created, add 2 files - index.ts and types.ts.
Open the types.ts file and add the following code:

{% gist https://gist.github.com/jamesoyanna/a79475fc005e621cf4c1863fe7717ca4 file=types.ts%}

Here in this code,we define two TypeScript types, `Post` and `NewPost`. 
The `Post` type is an object with four properties: id, title, body, and userId. Each property has a specific type: id is a number, title and body are strings, and userId is also a number.

The NewPost type is defined using TypeScript's Omit utility type, which takes an existing type and creates a new type by omitting one or more specified properties. 

In this case, we're using Omit to create a new type that's similar to Post, but with the id property omitted.
This is useful in situations where we need to create a new object that's similar to an existing object, but with some changes. 

Now, in the index.ts inside the posts folder, add the following code:
{% gist https://gist.github.com/jamesoyanna/05a7f2e88fbd5e96859f65dac2f1aea5 file=index.ts%}

Here in the code, we implemented the `Posts` API and we are using Typescript to define the types of the API responses and requests.

 The Posts class extends the Base class and implements the methods of the Posts API. 
We added a `getPostById` method that takes an ID and returns a single post with that ID. 

We also added a `getPosts` method which returns an array of all posts. 
Then we added `createPost` method that creates a new post by sending a POST request with the new post data as the request body. 
The API responses and requests are defined using the Post and `NewPost` types respectively. 

We define constant `resourceName` which is used as the resource name for the Posts API.

Each method sends a request to the API using the request() method inherited from the Base class, passing the appropriate URL and options. 
The methods return promises that resolve to the response data, which is typed according to the method's return type definition.


Now lets add mixins- Mixins are a programming concept that allows classes to inherit properties and methods from multiple sources.

In other words, mixins enable the creation of a new class by combining functionality from multiple classes without having to use inheritance.

In your `src` folder, create a file called utils.ts and add the following code:
{% gist https://gist.github.com/jamesoyanna/186fbbe02449a86a08749d1467d8af59 file=utils.ts%}

Here in this code we define a function called `applyMixins` which is used to apply properties and methods of multiple base classes to a single derived class. 

The function takes two parameters, `derivedCtor` which represents the derived class and `baseCtors` which is an array of base classes.

Inside the function, we use the forEach method to iterate over each base class in the `baseCtors `array. 

We then use the `getOwnPropertyNames` method to get all the property names of the prototype object of the base class. 

Then, for each property, the `defineProperty` method is used to define a new property on the prototype object of the derived class. 
This new property has the same name and property descriptor as the corresponding property on the base class.

Next, we will create a `index.ts` file in our `src` folder and the following code:
{% gist https://gist.github.com/jamesoyanna/2a54ae8de52cf879064bcbfcf6d544da file=index.ts%}

Here in this code, we define and exports the Typicode class as the default export of the module. 
The Typicode class extends the Base class and implements the Posts class. 

The Posts class provides methods to interact with the Posts API. The applyMixins function is used to add the methods and properties of the Posts class to the Typicode class. 

This is done using the interface keyword to declare that Typicode implements Posts and then calling applyMixins with Typicode and an array containing Posts. This allows Typicode to inherit the functionality of the Posts class and extend the functionality of the Base class.


Now before we publish our sdk to npm registry, lets make some changes to our package.json file.
Here is how  it should look like after the update.

{% gist https://gist.github.com/jamesoyanna/3f84acc7bb8bc36c3c44023a8c85d181 file=package.json%}

Now run `npm run build` to build our sdk. This would generate a dist file.

Now, let's publish our sdk.
You will have to create an account on the NPM website if you haven't already done so.

 Log in to your NPM account from the command line in your project directory by running `npm login` and providing your credentials.

You can test your package locally using the `npm link` command to create a symbolic link from your package to your local node_modules directory. 

We won't be doing any local testing here since everything appears to be functioning correctly.

Run the command `npm init --scope=oyanna`
Ensure you replace the scope value i.e `oyanna` with your name or any name you like before running the command.


Use the `npm publish --access-public` command to publish your package to the NPM registry. 
If your publishing works fine, you should see this on your npm account:

![npm-package](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/egnt66oxowuolrbv2oh9.PNG)

### How to use the SDK:
To use this SDK,create a folder called `sdk-test`
Inside the folder, initialize a new project by running `npm init -y` in the directory or folder you have just created. This would generate a `pakage.json` file in it.

Create a tsconfig.json file inside the folder and add the following code:

{% gist https://gist.github.com/jamesoyanna/0eee396afad35533698824849f806f04 file=tsconfig.json%}

Install the SDK package we have published by running the command:
`npm install @oyanna/typescript-sdk`
 
Create a new folder inside your project directory and add a new file called `run.ts`
Add the following code the the file:
{% gist https://gist.github.com/jamesoyanna/2d782836e2a515eaf494ce03845be459 file=run.ts%}

Here, we imported the `Typicode` class from our SK.

We then created a new instance of the `Typicode` is with an object that contains an API key as the property. We assigned this instance to a variable called `client`.

To make use of the API to get post from the `jsonplaceholder` api, we called the `getPosts` method on the client object, which retrieves a list of posts from the Typicode API. 

The result is a Promise which, when resolved, and logs the retrieved posts to the console.

To run the project and see the result in the console, add the following script to your package.json file. 
`
  "scripts": {
    "build": "tsc"
  },`

Now lets also make use of our SDK to create a post
 Run the following command:
`npm run build` . This command will build your SDK by creating a dist folder
Now run the command `tsc`
Then run the command: node run.js

You should see the following result log into command line:

![SDK-rest-result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pu5hcr0mok4y9ok6lig1.PNG)


The `createPost` method is called on the client object with a new post object that contains a title, body, and user ID. 

When the Promise returned by createPost resolves, a message is logged to the console indicating the ID of the newly created post.