Skip to content

ImagesModule

The NestJS ImagesModule is a module that provides an API for managing images and their renditions, allowing for the storage and retrieval of images and their associated metadata.

Each image in the Images API has multiple renditions representing different sizes, such as 1x, 2x, and small thumbnail sizes.

The Images API in conjunction with the ImageUploader from HopeUiKit provides a seamless integration for uploading images using @uppy/core and Companion. This combination streamlines the process of handling image uploads, ensuring a smooth user experience and simplifying the management of image resources within your application.

Entity Inheritance

NestKit provide base classes that can be inherited and customized with your needs. For entities we use TypeORM TableInheritance.

Key Components

The module provides a set of reusable components, including resolvers, services, and data access layers, that can be easily integrated into a NestJS project.

Image Entity

The Image is a data model in the Images API that represents an image and contains its unique identifier, associated metadata, and an array of related ImageRendition objects that represent specific sizes or formats of the image. It is used to manage the storage and retrieval of images in the database.

Image Renition Entity

The ImageRendition is an entity in the Images API that represents a rendition of an image and contains its unique ID, along with metadata such as the image URL, file size, and MIME type. It is associated with a parent Image entity and represents a specific size or format of the image.

NestJS Images Service

A ImagesService provides programmatic access to the Images API. It typically includes methods for creating, retrieving, updating, and deleting image entities.

NestJS Image Renditions Service

The ImageRenditionsService is a service in the Images API that provides methods for managing the image renditions associated with an Image entity. It allows for the creation, deletion, and retrieval of image renditions and their associated metadata, such as the image URL, file size, and MIME type.

GraphQL Images Resolver

The GraphQL ImagesResolver in NestKit provides a convenient way to retrieve and manipulate images data in a GraphQL API.

GraphQL Image Renditions Resolver

The GraphQL ImageRenditionsResolver in NestKit provides a convenient way to retrieve and manipulate image renditions data in a GraphQL API.

How to install ImagesModule to my app

To create a ImagesModule in NestJS, you can follow these steps:

  1. Install the required dependencies for BrandsModule:

  2. Create an images folder in your project's src/modules directory.

  3. Create an image-renditions folder in src/modules/images directory.

  4. Inside the image-renditions folder, create a image-rendition.entity.ts file and extends BaseImageRendition from NestKit with the following code:

    ts
    // src/modules/images/image-renditions/image-rendition.entity.ts
    
    import { BaseImageRendition } from '@deeepvision/nest-kit/dist/modules/images';
    import { ObjectType } from '@nestjs/graphql';
    import { ChildEntity } from 'typeorm';
    
    @ObjectType()
    @ChildEntity()
    export class ImageRendition extends BaseImageRendition {}
  5. Inside the image-renditions folder, create a image-renditions.service.ts file and extends BaseImageRenditionsService from NestKit with the following code:

    ts
    // src/modules/images/image-renditions/image-renditions.service.ts
    
    import { BaseImageRenditionsService } from '@deeepvision/nest-kit/dist/modules/images';
    import { ImageRendition } from './image-rendition.entity';
    
    export class ImageRenditionsService extends BaseImageRenditionsService<ImageRendition> {}
  6. Inside the image-renditions folder, create a image-renditions.resolver.ts file and extends BaseImageRenditionsResolver from NestKit with the following code:

    ts
    // src/modules/images/image-renditions/image-renditions.resolver.ts
    
    import { Resolver } from '@nestjs/graphql';
    import { ImageRendition } from './image-rendition.entity';
    import { BaseImageRenditionsResolver } from '@deeepvision/nest-kit/dist/modules/images';
    
    @Resolver(() => ImageRendition)
    export class ImageRenditionsResolver extends BaseImageRenditionsResolver(ImageRendition) {}
  7. Inside the images folder, create a image.entity.ts file and extends BaseImage from NestKit with the following code:

    ts
    // src/modules/images/image.entity.ts
    
    import { BaseImage } from '@deeepvision/nest-kit/dist/modules/images';
    import { ObjectType } from '@nestjs/graphql';
    import { ChildEntity } from 'typeorm';
    import { ImageRendition } from './image-renditions/image-rendition.entity';
    
    @ObjectType()
    @ChildEntity()
    export class Image extends BaseImage {
      renditions!: Promise<ImageRendition[]>;
    }
  8. Inside the images folder, create a images.service.ts file and extends BaseImagesService from NestKit with the following code:

    ts
    // src/modules/images/images.service.ts
    
    import { BaseImagesService } from '@deeepvision/nest-kit/dist/modules/images';
    import { Image } from './image.entity';
    
    
    export class ImagesService extends BaseImagesService<Image> {}
  9. Inside the images folder, create a images.resolver.ts file and extends BaseImageRenditionsResolver from NestKit with the following code:

    ts
    // src/modules/images/images.resolver.ts
    
    import { Resolver } from '@nestjs/graphql';
    import { BaseImagesResolver } from '@deeepvision/nest-kit/dist/modules/images';
    import { Image } from './image.entity';
    import { ImagesService } from './images.service';
    import { ImageRenditionsService } from './image-renditions/image-renditions.service';
    
    @Resolver(() => Image)
    export class ImagesResolver extends BaseImagesResolver(Image) {
      constructor(
        protected readonly imagesService: ImagesService,
        protected readonly imageRenditionsService: ImageRenditionsService,
      ) {
        super(imagesService, imageRenditionsService);
      }
    }
  10. Inside the images folder, create a images.module.ts file with the following code:

    ts
    // src/modules/images/images.module.ts
    
    import { Module } from '@nestjs/common';
    import { ImagesService } from './images.service';
    import { TypeOrmModule } from '@nestjs/typeorm';
    import { ImagesResolver } from './images.resolver';
    import { Image } from './image.entity';
    import { ImageRendition } from './image-renditions/image-rendition.entity';
    import { ImageRenditionsService } from './image-renditions/image-renditions.service';
    import { ImageRenditionsResolver } from './image-renditions/image-renditions.resolver';
    import { IMAGES_SERVICE_TOKEN, IMAGE_RENDITIONS_SERVICE_TOKEN } from '@deeepvision/nest-kit/dist/modules/images';
    
    @Module({
      imports: [
        TypeOrmModule.forFeature([Image, ImageRendition]),
      ],
      providers: [
        ImagesService,
        {
          provide: IMAGES_SERVICE_TOKEN,
          useExisting: ImagesService,
        },
        ImagesResolver,
        ImageRenditionsService,
        {
          provide: IMAGE_RENDITIONS_SERVICE_TOKEN,
          useExisting: ImageRenditionsService,
        },
        ImageRenditionsResolver,
      ],
      exports: [
        ImagesService,
        {
          provide: IMAGES_SERVICE_TOKEN,
          useExisting: ImagesService,
        },
        ImageRenditionsService,
        {
          provide: IMAGE_RENDITIONS_SERVICE_TOKEN,
          useExisting: ImageRenditionsService,
        },
      ],
    })
    export class ImagesModule {}
  11. Finally, import the ImagesModule into your main AppModule or another module:

    ts
    // src/modules/app.module.ts
    
    import { Module } from '@nestjs/common';
    import { ImagesModule } from './modules/images/images.module.ts';
    
    @Module({
      imports: [ImagesModule],
    })
    export class AppModule {}

    In this code, we are importing the ImagesModule and adding it to the imports array of our AppModule.

How to create new image

Call the create of ImagesService and pass in an object of CreateImageOptions:

ts
const image = await this.imagesService.create({
  renditions: [
    {
      type: ImageRenditionType.MAIN_2X,
      meta: {
        filesize: 2048,
        mimeType: 'image/webp',
        width: 1600,
        height: 1200,
      },
      url: 'https://cdn.holistic-cms.com/image_2x.webp',
    },
    {
      type: ImageRenditionType.MAIN,
      meta: {
        filesize: 1024,
        mimeType: 'image/webp',
        width: 800,
        height: 600,
      },
      url: 'https://cdn.holistic-cms.com/image.webp',
    },
    {
      type: ImageRenditionType.MAIN_LEGACY,
      meta: {
        filesize: 1024,
        mimeType: 'image/jpeg',
        width: 800,
        height: 600,
      },
      url: 'https://cdn.holistic-cms.com/image.jpg',
    },
    {
      type: ImageRenditionType.SMALL,
      meta: {
        filesize: 256,
        mimeType: 'image/webp',
        width: 200,
        height: 150,
      },
      url: 'https://cdn.holistic-cms.com/image_thumb.webp',
    },
  ],
});

The create method returns a Promise that resolves to the newly created image object.

Create new image with GraphQL

Here's an example GraphQL mutation to create a new image.

How to attach image to my entity

Firstly, you need to create an one-to-one relation between your and Image entities using TypeORM:

  1. First, define your entity (Post for example) with the @OneToOne() decorator to specify the relation to the Image entity:

    ts
    @Entity()
    export class Post {
      // ...
    
      @OneToOne(() => Image, {
        eager: true, // optional, will load the related image entity along with the post
        cascade: true, // optional, will automatically persist the related image entity when the post is saved
        onDelete: 'RESTRICT', // optional, throw an error if the related image will be attempted to delete
      })
      @JoinColumn() // use post.image_id column
      image: Image;
    }
  2. Define your Image entity with the @OneToOne() decorator to specify the reverse relation to the Post entity:

    ts
    @ObjectType()
    @ChildEntity()
    export class Image extends BaseImage {
      renditions!: Promise<ImageRendition[]>;
    
      @OneToOne(() => Post, post => post.image)
      post: Post;
    }
  3. Ensure that the imageId field is defined as a foreign key in your Post entity:

    ts
    @Entity()
    export class Post {
      // ...
    
      @OneToOne(() => Image, {
        eager: true,
        cascade: true,
        onDelete: 'SET NULL',
      })
      @JoinColumn()
      image: Image;
    
      @Column()
      imageId: string;
    }
  4. Use the save() method on your Post entity to persist it along with the related Image entity:

    ts
    // src/modules/posts/posts.service.ts
    
    interface CreatePostOptions {
      title: string;
      imageId: string; // image has already been created on frontend and only image Id passed
    }
    
    class PostsService {
      ...
    
      async create(opts: CreatePostOptions, ctx: ServiceMethodContext) {
        const post = this.postRepository.create(opts);
    
        try {
          return await this.postRepository.save(opts);
          ...
      }
    }

    This will create a new Post entity and attach Image entity with a one-to-one relation.

    Now, you can fetch an image for a post using relation:

ts
const post = await this.getOneOrFail(postId, ctx);

// post.image => Image

How to get image by ID

Use the getOne() method from your ImagesService to get a image by id in other parts of your application.

ts
const image = await this.imagesService.getOne('hcimg:xxxxxxxxxxx');

Use the getOneOrFail() method to retrieve a image by id or throw an error if the image is not found.

ts
const image = await this.imagesService.getOneOrFail('hcimg:xxxxxxxxxxx', ctx);

Fetch image by id with GraphQL

Here's an example GraphQL query to fetch image by id.

How to delete image

Call the delete method of the ImagesService and pass in the id of the image you want to delete:

ts
await this.imagesService.delete('hcimg:xxxxxxxxxxx');

Delete image with GraphQL

Here's an example GraphQL mutation to delete image.

Created by DeepVision Software.