DEV Community

Koji (he/him)
Koji (he/him)

Posted on

Generate Types from Contentful

I'm developing an app with nextjs and Contentful.

https://fetools.vercel.app/

I think I implemented the basic functionality. So it is time to set up Typescript dev environment for this app.

In this post, I will introduce you how to generate types from Contentful data model.
Actually, the steps are quite straightforward if you read the repo carefully and follow the steps carefully.

GitHub logo intercom / contentful-typescript-codegen

Generate TypeScript interfaces from a Contentful environment

contentful-typescript-codegen

Generate typings from your Contentful environment.

  • Content Types become interfaces.
  • Locales (and your default locale) become string types.
  • Assets and Rich Text link to Contentful's types.

At Intercom, we use this in our marketing site to increase developer confidence and productivity ensure that breaking changes to our Content Types don't cause an outage, and because it's neat.

Usage

yarn add --dev contentful-typescript-codegen
Enter fullscreen mode Exit fullscreen mode

Then, add the following to your package.json:

{
  // ...
  "scripts": {
    "contentful-typescript-codegen": "contentful-typescript-codegen --output @types/generated/contentful.d.ts"
  }
}
Enter fullscreen mode Exit fullscreen mode

Feel free to change the output path to whatever you like.

Next, the codegen will expect you to have created a file called getContentfulEnvironment.js in the root of your project directory, and it should export a promise that resolves with your Contentful environment.

The reason for this is that you can do whatever you like to set up your Contentful Management Client. Here's an example:

const
Enter fullscreen mode Exit fullscreen mode

The steps are below.
Step1. Install packages
Step2. Add a script to package.json
Step3. Put tokens on .env file
Step4. Add getContentfulEnvironment.js
Step5. Run the command (from Step2)

Step1. Install packages

This step is very easy.

If you didn't install packages for TypeScript, you would need the following.

# yarn
$ yarn add -D typescript @types/react @types/react-dom @types/node 

# npm
$ npm i -D typescript @types/react @types/react-dom @types/node 
Enter fullscreen mode Exit fullscreen mode
# yarn
$ yarn add -D contentful-typescript-codegen contentful-management dotenv

# npm
$ npm i -D contentful-typescript-codegen contentful-management dotenv

Enter fullscreen mode Exit fullscreen mode

Step2. Add a script to package.json

This step is also easy.

If you use next.js, the last script may be lint. So, you just need add the below after the ,

"scripts": {
    "contentful-typescript-codegen": "contentful-typescript-codegen --output @types/generated/contentful.d.ts"
  }
Enter fullscreen mode Exit fullscreen mode

Here is mine. Basically, we won't need to execute this after generating types, so the long name is totally fine, but I like a simple command, so I set codegen as a command.
This is totally up to you.

 "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint src --ext .js",
    "format": "prettier --write --ignore-path .gitignore './**/*.{js,jsx,ts,tsx,json,css}'",
    "codegen": "contentful-typescript-codegen --output @types/generated/contentful.d.ts"
  },
Enter fullscreen mode Exit fullscreen mode

Step3. Put tokens on .env file

This step isn't difficult but I took some time to generate types because I didn't read the instruction/readme carefully.

In this step, we need to generate a new token.

Login Contentful > Settings > API Keys

If you use Contentful, you have Space ID, Content Delivery API - access token, Content Preview API - access token, and Environments & Environment Aliases

What we need to set to generate Types is Content management tokens. I used Content Delivery API instead of that and got 403 error. I was like whyyyyyyyyyyy 🤬 🤬 🤬 lol.

I believe the most important thing in this post is to generate Content management tokens lol.

AccessTokenInvalid: {
  "status": 403,
  "statusText": "Forbidden",
  "message": "The access token you sent could not be found or is invalid.",
  "details": {},
  "request": {
Enter fullscreen mode Exit fullscreen mode

Alt Text

After generating the token, you will need to add it to .env file.

CONTENTFUL_SPACE_ID=aaaaaa
CONTENTFUL_ACCESS_TOKEN=bbbbb
CONTENTFUL_ENVIRONMENT=master
NEXT_PUBLIC_GOOGLE_ANALYTICS=ccccc
CONTENTFUL_PREVIEW_TOKEN=ddddddd
CONTENTFUL_MANAGEMENT_API_ACCESS_TOKEN=eeeeee <- new!!!
Enter fullscreen mode Exit fullscreen mode

Step4. Add getContentfulEnvironment.js

getContentfulEnvironment.js needs three items from .env.

  • CONTENTFUL_MANAGEMENT_API_ACCESS_TOKEN
  • CONTENTFUL_SPACE_ID
  • CONTENTFUL_ENVIRONMENT
require('dotenv').config();
const contentfulManagement = require('contentful-management');

// console.log('accessToken', process.env.CONTENTFUL_ACCESS_TOKEN);

module.exports = function () {
  const contentfulClient = contentfulManagement.createClient({
    accessToken: process.env.CONTENTFUL_MANAGEMENT_API_ACCESS_TOKEN,
  });

  return contentfulClient
    .getSpace(process.env.CONTENTFUL_SPACE_ID)
    .then((space) => space.getEnvironment(process.env.CONTENTFUL_ENVIRONMENT));
};
Enter fullscreen mode Exit fullscreen mode

Step5. Run the command (from Step2)
We are almost there.

Finally we need to run the command.

# yarn
$ yarn codegen
# npm
$ npm run codegen
Enter fullscreen mode Exit fullscreen mode

The command works properly, you will see @types/generated/contentful.d.ts under the root folder.

The following is mine.

// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.

import { Asset, Entry } from 'contentful';
import { Document } from '@contentful/rich-text-types';

export interface IFeToolsFields {
  /** Title */
  title: string;

  /** Thumbnail */
  thumbnail?: Asset | undefined;

  /** Link */
  link: string;

  /** Tag */
  tag?: string[] | undefined;

  /** Description */
  description?: string | undefined;

  /** Category */
  category: 'font' | 'html/css' | 'image' | 'js/ts' | 'other';
}
Enter fullscreen mode Exit fullscreen mode

As I emphasized the very top, the process is very straightforward and easy if you read the instruction carefully. Hope you won't waste time like me 😜

Discussion (0)