Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SPIKE] SDK: create a @dotcms/types package #31225

Closed
4 tasks
Tracked by #30943
rjvelazco opened this issue Jan 24, 2025 · 4 comments
Closed
4 tasks
Tracked by #30943

[SPIKE] SDK: create a @dotcms/types package #31225

rjvelazco opened this issue Jan 24, 2025 · 4 comments

Comments

@rjvelazco
Copy link
Contributor

rjvelazco commented Jan 24, 2025

Important

Time Frame: 1 day

Parent Issue

#30943

User Story

As a developer, I want to use the dotCMS SDK with TypeScript so that I can build applications with strongly typed frameworks like Angular or Next.js + ReactJS

Acceptance Criteria

Tasks

Preview Give feedback

Proposed Objective

Technical User Experience

Proposed Priority

Priority 2 - Important

Assumptions & Initiation Needs

  • We need to ensure developers avoid following the approach we used in the Astro example:

/* eslint-disable @dotcms/typescript-eslint/no-explicit-any */
// We need to make a types lib for this.
export interface DotCMSPageAsset {
canCreateTemplate: boolean;
containers: DotCMSPageAssetContainer;
layout: DotCMSLayout;
page: DotCMSPage;
site: DotCMSSite;
template: DotCMSTemplate;
viewAs: DotCMSViewAs;
vanityUrl?: {
pattern: string;
vanityUrlId: string;
url: string;
siteId: string;
languageId: number;
forwardTo: string;
response: number;
order: number;
temporaryRedirect: boolean;
permanentRedirect: boolean;
forward: boolean;
};
}
export interface DotPageAssetLayoutRow {
identifier: number;
value?: string;
id?: string;
columns: DotPageAssetLayoutColumn[];
styleClass?: string;
}
export interface DotPageAssetLayoutColumn {
preview: boolean;
containers: DotCMSContainer[];
widthPercent: number;
width: number;
leftOffset: number;
left: number;
styleClass?: string;
}
export interface DotCMSPageAssetContainer {
[key: string]: {
container: DotCMSContainer;
containerStructures: DotCMSContainerStructure[];
contentlets: {
[key: string]: DotCMSContentlet[];
};
};
}
export interface DotCMSContainer {
identifier: string;
uuid: string;
iDate: number;
type: string;
owner?: string;
inode: string;
source: string;
title: string;
friendlyName: string;
modDate: number;
modUser: string;
sortOrder: number;
showOnMenu: boolean;
code?: string;
maxContentlets: number;
useDiv: boolean;
sortContentletsBy?: string;
preLoop: string;
postLoop: string;
staticify: boolean;
luceneQuery?: string;
notes: string;
languageId?: number;
path?: string;
live: boolean;
locked: boolean;
working: boolean;
deleted: boolean;
name: string;
archived: boolean;
permissionId: string;
versionId: string;
versionType: string;
permissionType: string;
categoryId: string;
idate: number;
new: boolean;
acceptTypes: string;
contentlets: DotCMSContentlet[];
parentPermissionable: DotCMSSiteParentPermissionable;
}
export interface DotCMSContentlet {
archived: boolean;
baseType: string;
deleted?: boolean;
binary?: string;
binaryContentAsset?: string;
binaryVersion?: string;
contentType: string;
file?: string;
folder: string;
hasLiveVersion?: boolean;
hasTitleImage: boolean;
host: string;
hostName: string;
identifier: string;
inode: string;
image?: any;
languageId: number;
language?: string;
live: boolean;
locked: boolean;
mimeType?: string;
modDate: string;
modUser: string;
modUserName: string;
owner: string;
sortOrder: number;
stInode: string;
title: string;
titleImage: string;
text?: string;
url: string;
working: boolean;
body?: string;
contentTypeIcon?: string;
variant?: string;
__icon__?: string;
[key: string]: any; // This is a catch-all for any other custom properties that might be on the contentlet.
}
export interface DotcmsNavigationItem {
code?: any;
folder: string;
children?: DotcmsNavigationItem[];
host: string;
languageId: number;
href: string;
title: string;
type: string;
hash: number;
target: string;
order: number;
}
interface DotCMSTemplate {
iDate: number;
type: string;
owner: string;
inode: string;
identifier: string;
source: string;
title: string;
friendlyName: string;
modDate: number;
modUser: string;
sortOrder: number;
showOnMenu: boolean;
image: string;
drawed: boolean;
drawedBody: string;
theme: string;
anonymous: boolean;
template: boolean;
name: string;
live: boolean;
archived: boolean;
locked: boolean;
working: boolean;
permissionId: string;
versionId: string;
versionType: string;
deleted: boolean;
permissionType: string;
categoryId: string;
idate: number;
new: boolean;
canEdit: boolean;
}
interface DotCMSPage {
template: string;
modDate: number;
metadata: string;
cachettl: string;
pageURI: string;
title: string;
type: string;
showOnMenu: string;
httpsRequired: boolean;
inode: string;
disabledWYSIWYG: any[];
seokeywords: string;
host: string;
lastReview: number;
working: boolean;
locked: boolean;
stInode: string;
friendlyName: string;
live: boolean;
owner: string;
identifier: string;
nullProperties: any[];
friendlyname: string;
pagemetadata: string;
languageId: number;
url: string;
seodescription: string;
modUserName: string;
folder: string;
deleted: boolean;
sortOrder: number;
modUser: string;
pageUrl: string;
workingInode: string;
shortyWorking: string;
canEdit: boolean;
canRead: boolean;
canLock: boolean;
lockedOn: number;
lockedBy: string;
lockedByName: string;
liveInode: string;
shortyLive: string;
}

@fmontes
Copy link
Member

fmontes commented Jan 27, 2025

We should get a list of all (or a much as possible) of the types we need, also differentiate between actual public facing types and internal like props and, because this will be a public library so is important to expose what is actually public.

@KevinDavilaDotCMS KevinDavilaDotCMS self-assigned this Jan 27, 2025
@KevinDavilaDotCMS KevinDavilaDotCMS linked a pull request Jan 28, 2025 that will close this issue
@KevinDavilaDotCMS
Copy link
Contributor

KevinDavilaDotCMS commented Jan 28, 2025

Findings

Using DefinitelyTyped (@types/dotcms)

Initially, we considered using DefinitelyTyped to add something like @types/dotcms. However, after researching a bit more, we realized this wasn’t the best fit for our use case.

DefinitelyTyped is primarily intended for well-established libraries that weren’t originally written in TypeScript. Since our library is still in development and doesn’t have a stable version yet, it makes more sense to expose the interfaces in a separate package, like @dotcms/types. This approach is easier to manage and aligns with how we handle our SDKs.

About the @dotcms/types library

The @dotcms/types library will primarily export interfaces related to the PageAPI, such as NavAsset, PageAsset, and their related types. While the SDKs (like React, Angular, or others) only use a few of these interfaces—such as DotCMSPageAsset, DotCMSContentlet, and DotCMSNavigationAsset—we export all of them in case other SDKs or users might need them.

Currently, the SDKs have everything typed internally, but the types are defined within the SDK itself. For example:

In React, we have an inline PageAsset interface, and we access its subtypes using index types (e.g., PageAsset['page']).
In Angular, we have a models folder that contains the necessary types.

Migrating these types to a shared @dotcms/types library is straightforward because the types are essentially the same. The only change is where they’re stored and how they’re imported.

SDK-specific types (those that belong exclusively to a particular SDK, such as client types for Angular or React) will remain within their respective SDK packages. Only the interfaces related to the PageAPI will be centralized in @dotcms/types.

This setup simplifies type management across SDKs while keeping SDK-specific types localized. It also ensures that any shared types, like those related to the PageAPI, are easily reusable across projects and tools.

This is a PoC about the new @dotcms/types and how refactor the react sdk to use it

Rethinking the name for @dotcms/types

The name @dotcms/types is quite generic. After implementing the library, I realized it will mainly provide types for clients using the SDKs. Because of this, a more specific name might make sense, such as @dotcms/uve-types, @dotcms/sdk-types or something similar

The name @dotcms/types feels more connected to the core of dotCMS and could be better suited for a library containing internal core-web types (not exposed to developers).

@KevinDavilaDotCMS KevinDavilaDotCMS moved this from New to In Progress in dotCMS - Product Planning Jan 28, 2025
@fmontes
Copy link
Member

fmontes commented Jan 28, 2025

Now all this got me thinking... The types are specifically for the APIs. The APIs interact through the client library. If everything is going to be there, the API's interactions, etc. inside the client library, why do we need an external library? Can't we just export that from like @dotcms/client/types?

@KevinDavilaDotCMS
Copy link
Contributor

KevinDavilaDotCMS commented Jan 28, 2025

Now all this got me thinking... The types are specifically for the APIs. The APIs interact through the client library. If everything is going to be there, the API's interactions, etc. inside the client library, why do we need an external library? Can't we just export that from like @dotcms/client/types?

It’s a good alternative!

We discussed it with the Frontend team and decided to go with this option, mainly because @dotcms/client/types allows us to expose the same interfaces without the need to create a new library, avoiding the complexity that would involve.

This approach requires creating a new entry point in the @dotcms/client library to expose the same interfaces as in the PoC.
Here’s an example of how to add a new entry point

The SDKs (react, angular, vue) will then import these interfaces directly from @dotcms/client.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

4 participants