DEV Community

Cover image for Creating contract package using Typescript and Github Packages
Natalia
Natalia

Posted on • Updated on

Creating contract package using Typescript and Github Packages

Imagine you have cool frontend app that is connected with your awesomome backend application that serves an API. The API is obviously expecting some input data in some of the requests, and sometimes it returns some data in response. I say some, because your web app is not aware what kind of data is supposed to send and what should expect in return. So today I will show you how to create contract package with Typescript and deploy it in Github Packages.

NOTE: We won't be covering here how to create backend nor frontend application, so the contract package will be in seperate repository. You could create monorepo with api and contracts.

You will need:

Outline

Let's say we have a website in which the user must be logged in order to use it. Frontend wants to fetch basic info about the user. The API is providing such endpoint and it returns an object of type UserOutput

interface UserOutput { 
  username: string;
  email: string;
}
Enter fullscreen mode Exit fullscreen mode

What should we do so that web app has access to given type?

Creating new project

Let's go straight to the point.

First create a directory for new project

mkdir my-project-contracts
cd my-project-contracts
Enter fullscreen mode Exit fullscreen mode

Initialize new npm project with git and typescript (for now skip all the settings in package.json)

git init
npm init
npm i typescript --save-dev
npx tsc --init
Enter fullscreen mode Exit fullscreen mode

Create UserOutput.ts file and add inside your first contract

export default interface UserOutput {
  username: string;
  email: string;
}
Enter fullscreen mode Exit fullscreen mode

Create index.ts file and import your contract

import UserOutput from "./UserOutput";
export { UserOutput };
Enter fullscreen mode Exit fullscreen mode

Now we tweak tsconfig.json. For contracts it's sufficient to emit only declaration files. We specify output directory to dist folder. So our config file should look like this

{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig to read more about this file */
    /* Emit */
    "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
    "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
    "outDir": "dist",                                   /* Specify an output folder for all emitted files. */
  }
}
Enter fullscreen mode Exit fullscreen mode

Let's not forget about .gitignore in order to not publish unnecessary folders

/dist
/node_modules
Enter fullscreen mode Exit fullscreen mode

So far so good!

Now it's time to prepare our project to enable it for publishing as a package in Github Package registry with usage of Github Actions.

Before we go forward we need to set up personal access token (classic). To do that follow the steps here.
Make sure you select the scopes which define the access for personal tokens.
IMPORTANT: Keep your token for later! We're gonna use it ;)

Scopes

Ok, when it's done, we come back to our project once again to finish the setup.

Change your package.json so that:

  • name follows @YOUR-USERNAME/YOUR-REPOSITORY
  • set the test script to exit 0
  • set build command to build *.d.ts files
  • tell npm which scope and registry to publish packages by specifying the publishConfig key
  • specify version of the package
  • use files key to indicate with files should be included when publishing (read more about here) in my case it looks like this:
{
  "name": "@gh-username/my-project-contracts",
  "version": "1.0.0",
  "description": "Example of creating package with contracts usin Github Packages",
  "types": "./dist/index.d.ts",
  "publishConfig": {
    "gh-username:registry": "https://npm.pkg.github.com"
  },
  "files": [
    "dist"
  ],
  "scripts": {
    "test": "exit 0",
    "build": "npx tsc"
  },
  "author": "me",
  "devDependencies": {
    "typescript": "^5.1.3"
  }
}
Enter fullscreen mode Exit fullscreen mode

And the last thing to do in our project is to set up pipeline for building and publishing it. So, following Quickstart example:

  1. create a .github/workflows directory. In that directory, create a file named release-package.yml.

  2. copy the following YAML content into the release-package.yml file.

name: My package with contracts

on:
  release:
    types: [created]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
      - run: npm ci
      - run: npm run build
      - run: npm test

  publish-gpr:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      packages: write
      contents: read
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
          registry-url: https://npm.pkg.github.com/
      - run: npm ci
      - run: npm run build
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

Enter fullscreen mode Exit fullscreen mode

As you can see, the aceess token we set up earlier, is used to check up permissions for package registries.

Aaaand looks like we've done! Well, almost, now you have to create a repository in Github and push your changes.

Create release

If you finished creating new repo for contracts, you'd be ready to create a release and build your new package.

  1. On GitHub.com, navigate to the main page of the repository.
  2. To the right of the list of files, click Releases.
  3. At the top of the page, click Draft a new release.
  4. Choose a tag and a title for the release.
  5. Click Publish release.
  6. Go to the Actions tab and see you release action

release action

After it finishes, in the main page of repository you should see your package

packages

NOTE: For more detailed description about creating releases, check official documentation.

Final touch: Use contract package in your project

We almost there! In the project you want to use the contract package, set .npmrc file with information about github registry

//npm.pkg.github.com/:_authToken={GITHUB_TOKEN}
@gh-username:registry=https://npm.pkg.github.com
Enter fullscreen mode Exit fullscreen mode

NOTE: Create new GITHUB_TOKEN only with read:packages scope.

If you use npm, install your packages with npm i @YOUR-USERNAME/YOUR-REPOSITORY --save-dev.

If you use yarn you will have to point with url to your repository, check conversation on Stack Overflow.

And that's it! Thank you for taking your time :)

Top comments (0)