Description Comment

src/controllers/BbsArticleController.ts
import { TypedBody, TypedParam, TypedRoute } from "@nestia/core";
import { Controller } from "@nestjs/common";
import { tags } from "typia";
 
import { IBbsArticle } from "../api/structures/IBbsArticle";
 
@Controller("bbs/articles")
export class BbsArticleController {
  /**
   * Create a new article.
   *
   * Writes a new article and archives it into the DB.
   *
   * @param input Information of the article to create
   * @returns Newly created article
   */
  @TypedRoute.Post()
  public async create(
    @TypedBody() input: IBbsArticle.ICreate
  ): Promise<IBbsArticle>;
 
  /**
   * Update an article.
   *
   * Updates an article with new content.
   *
   * @param id Target article's {@link IBbsArticle.id}
   * @param input New content to update
   */
  @TypedRoute.Put(":id")
  public async update(
    @TypedParam("id") id: string & tags.Format<"uuid">,
    @TypedBody() input: IBbsArticle.IUpdate,
  ): Promise<void>;
 
  /**
   * Erase an article.
   *
   * Erases an article from the DB.
   *
   * @param id Target article's {@link IBbsArticle.id}
   */
  @TypedRoute.Delete(":id")
  public async erase(
    @TypedParam("id") id: string & tags.Format<"uuid">,
  ): Promise<void>;
}

Write descriptions as comments on controller methods, and DTO interfaces.

The descrption comments would be transformed into the description, summary and title fields of the Swagger Document. And some special comment tags like @param and @returns would fill the adequate properties of the Swagger Document. If you’re using nestia for the the A.I. chatbot development purpose, such detailed descriptions are very important to teach the purpose of the function to the LLM (Language Large Model), and LLM actually determines which function to call by the description.

Also, OpenApi.IOperation type has two descriptive properties summary and description. And the OpenApi.IJsonSchema has similar categorized two properties title and description. Both summary and title can be filled with two ways. The first way is closing the first line of the description comment with a period (.). By the way, this way’s description property would be the entire description comment even including the first line composing the summary or title field.

If you don’t want that, you can adapt the second way that writing @summary {string} or @title {string} comment tag. In that case, the title value would not be contained in the description value. For reference, it is possible to fill the description property of the ILlmSchema by the comment tag @description, but you have to take care of the indentation like below.

src/api/structures/IMember.ts
export interface IMember {
  /**
   * Primary Key.
   * 
   * Above "Primary Key" would be the title of LLM schema. 
   */
  id: string;
 
  /**
   * Below "Age of the member" would be the title of LLM schema.
   * 
   * @title Age of the member
   */
  age: number;
 
  /**
   * @title Email address of the member
   * @description The description property also can be filled by 
   *              the comment tag `@description`. Instead, be
   *              careful about the indentation.
   */
  email: string;
}

Namespace Strategy

src/api/structures/IBbsArticle.ts
import { tags } from "typia";
 
/**
 * Article entity.
 *
 * `IBbsArticle` is an entity representing an article in the BBS (Bulletin Board System).
 */
export interface IBbsArticle extends IBbsArticle.ICreate {
  /**
   * Primary Key.
   */
  id: string & tags.Format<"uuid">;
 
  /**
   * Creation time of the article.
   */
  created_at: string & tags.Format<"date-time">;
 
  /**
   * Last updated time of the article.
   */
  updated_at: string & tags.Format<"date-time">;
}
export namespace IBbsArticle {
  /**
   * Information of the article to create.
   */
  export interface ICreate {
    /**
     * Title of the article.
     *
     * Representative title of the article.
     */
    title: string;
 
    /**
     * Content body.
     *
     * Content body of the article writtn in the markdown format.
     */
    body: string;
 
    /**
     * Thumbnail image URI.
     *
     * Thumbnail image URI which can represent the article.
     *
     * If configured as `null`, it means that no thumbnail image in the article.
     */
    thumbnail:
      | null
      | (string & tags.Format<"uri"> & tags.ContentMediaType<"image/*">);
  }
 
  /**
   * Information of the article to update.
   *
   * Only the filled properties will be updated.
   */
  export type IUpdate = Partial<ICreate>;
}

If you’re using nestia for the A.I. chatbot development purpose, the namespace strategy is very important.

When you compose an IHttpLlmApplication / IHttpLlmFunction schema from a Swagger Document, it copies the parent namespaced type description comment to the children types. If you utilize this namespace strategy properly, you can make the LLM function calling schema more informative and undeerstandable minimizing the duplicated description comments.

As you can see, above IBbsArticle.ICreate and IBbsArticle.IUpdate interfaces are the children of the IBbsArticle interface. And the IBbsArticle interface has a detailed description comment about the article. In this case, the description comment of the IBbsArticle interface would be copied to the IBbsArticle.ICreate and IBbsArticle.IUpdate interfaces. Therefore, you don’t need to write the same description comment on the children interfaces again.

Function Hiding

src/controllers/shoppings/customers/ShoppingCustomerSaleController.ts
import { HumanRoute, TypedBody, TypedParam, TypedRoute } from "@nestia/core";
import { Controller } from "@nestjs/common";
import { tags } from "typia";
 
import { IBbsArticle } from "../api/structures/IBbsArticle";
 
@Controller("bbs/articles")
export class BbsArticleController {
  /**
   * Read an article.
   * 
   * Reads an article from the DB.
   * 
   * @param id Target article's {@link IBbsArticle.id}
   * @returns The article
   */
  @TypedRoute.Get(":id")
  public async at(
    @TypedParam("id") id: string & tags.Format<"uuid">,
  ): Promise<IBbsArticle>;
 
  /**
   * Create a new article.
   *
   * Writes a new article and archives it into the DB.
   *
   * @param input Information of the article to create
   * @returns Newly created article
   * @hidden
   */
  @TypedRoute.Post()
  public async create(
    @TypedBody() input: IBbsArticle.ICreate
  ): Promise<IBbsArticle>;
 
  /**
   * Update an article.
   *
   * Updates an article with new content.
   *
   * @param id Target article's {@link IBbsArticle.id}
   * @param input New content to update
   * @internal
   */
  @TypedRoute.Put(":id")
  public async update(
    @TypedParam("id") id: string & tags.Format<"uuid">,
    @TypedBody() input: IBbsArticle.IUpdate,
  ): Promise<void>;
 
  /**
   * Erase an article.
   *
   * Erases an article from the DB.
   *
   * @param id Target article's {@link IBbsArticle.id}
   */
  @HumanRoute()
  @TypedRoute.Delete(":id")
  public async erase(
    @TypedParam("id") id: string & tags.Format<"uuid">,
  ): Promise<void>;
}

Hiding some API functions by comment tag.

If you write @hidden or @internal comment tag on a controller method, it would be hidden in the Swagger Document. And if you adjust @HumanRoute() decorator to a controller method, it would be shown in the Swagger Document, but would be hidden in the LLM Application Schema.

When you need to hide some internal functions from Swagger Document, or block A.I. chatbot to call some prohibited functions that must be called by human manually.

Specialization

src/api/structures/ISpecial.ts
import { tags } from "typia";
 
interface Special {
  /**
   * Deprecated tags are just used for marking.
   *
   * @title Unsigned integer
   * @deprecated
   */
  type: number & tags.Type<"int32">;
 
  /**
   * Internal tagged property never be shown in JSON schema.
   *
   * It even doesn't be shown in other `typia` functions like `assert<T>()`.
   *
   * @internal
   */
  internal: number[];
 
  /**
   * Hidden tagged property never be shown in JSON schema.
   *
   * However, it would be shown in other `typia` functions like `stringify<T>()`.
   *
   * @hidden
   */
  hidden: boolean;
 
  /**
   * You can limit the range of number.
   *
   * @exclusiveMinimum 19
   * @maximum 100
   */
  number?: number;
 
  /**
   * You can limit the length of string.
   *
   * Also, multiple range conditions are also possible.
   */
  string: string &
    (
      | (tags.MinLength<3> & tags.MaxLength<24>)
      | (tags.MinLength<40> & tags.MaxLength<100>)
    );
 
  /**
   * You can limit the pattern of string.
   *
   * @pattern ^[a-z]+$
   */
  pattern: string;
 
  /**
   * You can limit the format of string.
   *
   * @format date-time
   */
  format: string | null;
 
  /**
   * In the Array case, possible to restrict its elements.
   */
  array: Array<string & tags.Format<"uuid">> & tags.MinItems<3>;
}

You can utilize type tags (or validator’s comment tags) to constructing special fields of JSON schema.

If you write any comment on a property, it would fill the IJsonSchema.description value. Also, there’re special comment tags only for JSON schema definition that are different with validator’s comment tags like below.

  • @deprecated
  • @hidden
  • @internal
  • @title {string}

Let’s see how those type tags, comment tags and description comments are working with example code.