devdotto
devdotto is an API wrapper for the DEV API written in TypeScript. This module is still under development with full coverage of the DEV API.
Installation
Requires NodeJS 18.3 or higher
npm i devdotto
What's New
Added typings for podcasts, podcast videos and reading lists. Updated exports
Added the following functions:
- getEntityProfilePicture()
- getPodcastEpisodes()
- getTags()
- DEVClient
- .getMyReadingList()
- .inviteToDEV()
Example Usage
Fetching Articles
import { getArticles } from 'devdotto';
const articles = await getArticles({
perPage: 1
});
console.log(articles);
Output
Click to view
[
{
typeOf: 'article',
id: 1108433,
title: 'Getting Your Conference Talk Proposal Accepted 🎙' ,
description: 'Ever wonder what it takes to get your conference talk accepted? In this episode of DevDiscuss we talk...',
readablePublishDate: 'Jun 8',
slug: 'getting-your-conference-talk-proposal-accepted-1cb6',
path: '/devteam/getting-your-conference-talk-proposal-accepted-1cb6',
url: 'https://dev.to/devteam/getting-your-conference-talk-proposal-accepted-1cb6',
commentsCount: 0,
publicReactionsCount: 4,
collectionId: null,
publishedTimestamp: '2022-06-08T15:31:20Z',
positiveReactionsCount: 4,
coverImage: 'https://res.cloudinary.com/practicaldev/image/fetch/s--bBW3B-K6--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvyy0bbgzgepfipg93v3.png',
socialImage: 'https://res.cloudinary.com/practicaldev/image/fetch/s--oRDMUBIb--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvyy0bbgzgepfipg93v3.png',
canonicalUrl: 'https://dev.to/devteam/getting-your-conference-talk-proposal-accepted-1cb6',
createdAt: '2022-06-08T15:31:20Z',
editedAt: null,
crosspostedAt: null,
publishedAt: '2022-06-08T15:31:20Z',
lastCommentAt: '2022-06-08T15:31:20Z',
readingTimeMinutes: 1,
tagList: [ 'podcast', 'career', 'devrel', 'productivity' ],
tags: 'podcast, career, devrel, productivity',
user: {
name: 'Ben Halpern',
username: 'ben',
twitterUsername: 'bendhalpern',
githubUsername: 'benhalpern',
websiteUrl: 'http://benhalpern.com',
profileImage: 'https://res.cloudinary.com/practicaldev/image/fetch/s--nz-jndal--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/1/f451a206-11c8-4e3d-8936-143d0a7e65bb.png',
profileImage90: 'https://res.cloudinary.com/practicaldev/image/fetch/s--Ea1OGrCb--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/1/f451a206-11c8-4e3d-8936-143d0a7e65bb.png'
},
organization: {
name: 'The DEV Team',
username: 'devteam',
slug: 'devteam',
profileImage: 'https://res.cloudinary.com/practicaldev/image/fetch/s--CAGmUhNa--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://dev-to-uploads.s3.amazonaws.com/uploads/organization/profile_image/1/0213bbaa-d5a1-4d25-9e7a-10c30b455af0.png',
profileImage90: 'https://res.cloudinary.com/practicaldev/image/fetch/s--mbsgKaXh--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://dev-to-uploads.s3.amazonaws.com/uploads/organization/profile_image/1/0213bbaa-d5a1-4d25-9e7a-10c30b455af0.png'
}
}
]
Making Authenticated Requests
import { DEVClient } from 'devdotto';
const key = 'YOUR_API_KEY';
const client = new DEVClient();
await client.authorize(key);
client.createArticle({
title: 'My New Article',
description: 'Making a new article with devdotto!',
bodyMarkdown: '<h1>Hello World!</h1>',
tags: ['node'],
published: false
});
Result
Documentation (0.6.0)
Functions
- getArticles()
- getArticleById()
- getArticleByPath()
- getLatestArticles()
- getVideoArticles()
- getArticleComments()
- getCommentById()
- getListings()
- getListingById()
- getOrganizationByUsername()
- getOrganizationsUsers()
- getOrganizationsListings()
- getOrganizationsArticles()
- getPodcastEpisodes();
- getTags()
- getUserById()
- getEntityProfilePicture
Classes
Typings
getarticles
PageFetchOptions>):Promise<Page<Article>>
getArticles(options?:Partial<Fetches a page of articles.
const page = await getArticles({
perPage: 10
});
getarticlebyid
NumberResolvable):Promise<Article>
getArticleById(id:Fetches an article by it's id.
const article = await getArticleById('12345');
getarticlebypath
Article>
getArticleByPath(publisherName: string, slug:string):Promise<Fetches an article by it's username/slug path.
const article = await getArticleByPath('username', 'slug-here');
getlatestarticles
BaseFetchPageOptions):Promise<Page<Article>>
getLatestArticles(options?:Fetches the newest articles.
const page = await getLatestArticles({
perPage: 10
});
getvideoarticles
BaseFetchPageOptions):Promise<Page<VideoArticle>>
getVideoArticles(options?:Fetches video articles.
const page = await getVideoArticles({
perPage: 10
});
getarticlecomments
ArticleIdentifierOptions | PodcastIdentifierOptions):Promise<Comment[]>
getArticleComments(id:Fetches the comments of an article.
const articleComments = await getArticleComments({
aId: '12345'
});
const podcastComments = await getArticleComments({
pId: '12345'
});
getcommentbyid
NumberResolvable): Promise<Comment>
getCommentById(id:Fetches a comment by it's id.
const comment = await getCommentById('12345');
getlistings
CategorizedListingOptions):Promise<Listing[]>
getListings(options?:Fetches listings.
const listings = await getListings();
getlistingbyid
NumberResolvable):Promise<Listing>
getLisitngById(id:Fetches a listing by id. If the listing is unpublished and belongs to you use DEVClient.getMyListingById().
const listing = await getListingById('12345');
getorganizationbyusername
Organization>
getOrganizationByUsername(username:string):Promise<Fetches an organization by it's username
const organization = await getOrganizationByUsername('username-here');
getorganizationsusers
BaseFetchPageOptions):Promise<Page<User>>
getOrganizationsUsers(username:string, options?:Fetches the user's of an organization by organization username.
const users = await getOrganizationsUsers('org-username-here');
getorganizationslistings
CategorizedListingOptions):Promise<Page<Listing & { organization:Organization }>>
getOrganizationsListings(username: string, options?:Fetches the listings of an organization by organization username.
const listings = await getOrganizationsListings('org-username-here', {
perPage: 5,
page: 1,
category: '...'
});
getorganizationsarticles
BaseFetchPageOptions):Promise<Page<Article>>
getOrganizationsArticles(username: string, options?:Fetches the articles of an organization by organization username.
const articles = await getOrganizationsArticles('org-username-here', {
perPage: 5,
page: 1
});
getpodcastepisodes
BaseFetchPageOptions & Partial<UsernameBasedOptions>):Promise<Page<PodcastEpisode>>
getPodcastEpisodes(options?:Fetches podcast episodes.
const episodes = await getPodcastEpisodes({
perPage: 5,
page: 1,
username: '...'
});
getTags
BaseFetchPageOptions):Promise<Page<Tag>>
getTags(options?:Fetches all tags.
const tags = await getTags();
getuserbyid
NumberResolvable):Promise<User>
getUserById(id:Fetches a DEV user by their id.
const user = await getUserById('12345');
getentityprofilepicture
ProfileImage>
getEntityProfilePicture(username: string):Promise<Fetches the profile image of a user or organization.
const imageURL = (await getEntityProfilePicture('...')).profileImage;
DEVClient
DEVClient
Properties
.me
The user object of the owner of the API key.
Type: User | null
Methods
authorize(key:string, options?:AuthorizationOptions):void
Assigns an API key to the client and fetches the user object. This function must be awaited for the user object to be assigned.
const client = new DEVClient();
await client.authorize('api_key');
getMyArticles(options?:BaseFetchPageOptions):Promise<Article[]>
fetches the user's articles.
const myArticles = await client.getMyArticles();
getMyListingById(id:NumberResolvable):Promise<Listing>
Fetches your listing by id.
const myListing = await client.getMyListingById('12345');
getMyPublishedArticles(options?:BaseFetchPageOptions):Promise<Article[]>
fetches the user's published articles.
const myPublishedArticles = await client.getMyPublishedArticles();
getMyUnpublishedArticles(options?:BaseFetchPageOptions):Promise<Article[]>
fetches the user's unpublished articles.
const myUnpublishedArticles = await client.getMyUnpublishedArticles();
getAllMyArticles(options?:BaseFetchPageOptions):Promise<Article[]>
fetches all the user's articles.
const allMyArticles = await client.getAllMyArticles();
getMyFollowedTags():Promise<FollowedTags[]>
Fetches your followed tags.
const myFollowedTags = await client.getMyFollowedTags();
getMyFollowers(options?:Partial<SortedPageOptions>):Promise<Follower[]>
Fetches your followers.
const myFollowers = await DEVClient.getMyFollowers();
getMyReadingList(options?:BaseFetchPageOptions):Promise<Page<ReadingListItem>>
Fetches your reading list.
const myList = await DEVClient.getMyReadingList();
inviteToDEV(options:InvitationOptions):Promise
Triggers an invitation to the provided email.
await DEVClient.inviteToDEV({
email: 'example@email.com',
name: 'John Doe'
});
createArticle(data:NewArticleData):Promise<Article>
Creates a new article under the user's authentication.
const myNewArticle = await client.createArticle({
title: 'My New Article',
description: 'Making a new article with devdotto!',
bodyMarkdown: '<h1>Hello World!</h1>',
tags: ['node'],
published: false
});
updateArticleById(id:NumberResolvable, data:NewArticleData):Promise<Article>
Updates one of the user's articles by it's id.
client.updateArticleById('12345', {
title: 'Updating My Article',
description: 'Updating my article with devdotto!',
bodyMarkdown: '<h1>Goodbye World!</h1>',
tags: ['node'],
published: false
});
getMe():Promise<User>
const myUser = await client.getMe();
Fetches the authenticator's user.
Typings
Types
articlestate
type ArticleState = 'all' | 'fresh' | 'rising';
categorizedlistingoptions
type CategorizedListingOptions = BasePageOptions & ListingCategoryOptions;
endpoint
type EndPoint = `/${string}`;
numberresolvable
type NumberResolvable = number | `${number}`;
page
type Page<T> = T[];
basefetchpageoptions
type BaseFetchPageOptions = Partial<Pick<PageFetchOptions, 'perPage' | 'page'>>;
tags
type Tags = string;
typesofarticles
type TypeOfArticle = 'article' | 'video_article';
typeofmember
type TypeOfMember = 'user';
stringindex
type StringIndex<T> = { [key:string]: string };
sortedpageoptions
type SortedPageOptions = BasePageOptions & SortOptions;
videodurationformat
type VideoDurationFormat =
`${number}${number}:${number}${number}` |
`${number}${number}:${number}${number}:${number}${number}`;
Interfaces
authorizationoptions
interface AuthorizationOptions {
cacheMe: boolean;
}
basepagefetchoptions
interface BasePageFetchOptions {
page: NumberResolvable;
tag: Tags;
tags: Tags[];
username: string;
state: ArticleState;
top: NumberResolvable;
}
comment
interface Comment {
typeOf: 'comment';
idCode: string;
createdAt: string;
bodyHtml: string;
user: User;
children: Comment[] | null;
}
rawcomment
interface RawComment {
type_of: 'comment';
id_code: string;
created_at: string;
body_html: string;
user: RawUser;
children: RawComment[] | null;
}
devdottoerrorresponse
interface DevDotToErrorResponse {
error: string;
status: number;
}
pagefetchoptions
interface PageFetchOptions extends BasePageFetchOptions {
perPage: NumberResolvable;
tagsExclude: Tags[];
collectionId: NumberResolvable;
}
finalpagefetchoptions
interface FinalPageFetchOptions extends BasePageFetchOptions {
per_page: number;
tags_exclude: string;
collection_id: number;
}
basearticle
interface BaseArticle {
id: number;
title: number;
description: string;
tags: Tags[];
slug: string;
path: string;
url: string;
}
article
interface Article extends BaseArticle {
typeOf: TypeOfArticle;
coverImage: string | null;
readablePublishDate: string;
socialImage: string;
tagList: string;
canonicalUrl: string;
commentsCount: number;
positiveReactionsCount: number;
publicReactionsCount: number;
createdAt: string;
editedAt: string | null;
crosspostedAt: string | null;
publishedAt: string;
lastCommentAt: string;
publishedTimestamp: string;
bodyHtml?: string;
bodyMarkdown?: string;
readingTimeMinutes: number;
user: User;
organization: OrganizationCover;
flareTag: FlareTag;
}
rawarticle
interface RawArticle extends BaseArticle {
type_of: TypeOfArticle;
cover_image: string | null;
readable_publish_date: string;
social_image: string;
tag_list: string;
canonical_url: string;
comments_count: number;
positive_reactions_count: number;
public_reactions_count: number;
created_at: string;
edited_at: string | null;
crossposted_at: string | null;
published_at: string;
last_comment_at: string;
published_timestamp: string;
body_html: string;
reading_time_minutes: number;
user: RawUser;
organization: RawOrganizationCover;
flare_tag: RawFlareTag;
}
baseorganization
interface BaseOrganizationCover {
name: string;
username: string;
slug: string;
}
organization
interface OrganizationCover extends BaseOrganizationCover {
profileImage: string;
profileImage90: string;
}
raworganization
interface RawOrganizationCover extends BaseOrganizationCover {
profile_image: string;
profile_image_90: string;
}
basenewarticledata
interface BaseNewArticleData {
title: string;
published: boolean;
series?: string;
description: string;
tags: Tags[];
}
newarticledata
interface NewArticleData extends BaseNewArticleData {
bodyMarkdown: string;
mainImage?: string;
canonicalUrl?: string;
organizationId?: string;
}
rawnewarticledata
interface RawNewArticleData extends BaseNewArticleData {
body_markdown: string;
main_image: string;
canonical_url: string;
organization_id: string;
}
basenewlistingdata
export interface BaseNewListingData {
title: string;
category: ListingCategory;
tags: Tags[];
location: string;
// action: ListingAction;
}
newlistingdata
export interface NewListingData extends BaseNewListingData {
bodyMarkdown: string;
tagList: string;
expiresAt: string;
contactViaConnect: string;
}
rawnewlistingdata
export interface RawNewListingData extends BaseNewListingData {
body_markdown: string;
tag_list: string;
expires_at: string;
contact_via_connect: string;
}
postoptions
interface PostOptions {
method: 'GET' | 'POST' | 'PUT';
headers: {
'Content-Type'?: 'application/json' | string,
'api-key': string
},
body?: string;
}
baseuser
interface BaseUser {
id: number;
name: string;
username: string;
}
user
interface User extends BaseUser {
typeOf: TypeOfMember;
twitterUsername: string | null;
githubUsername: string | null;
websiteUrl: string | null;
profileImage: string;
profileImage90: string;
}
rawuser
interface RawUser extends BaseUser {
type_of: TypeOfMember;
twitter_username: string | null;
github_username: string | null;
website_url: string | null;
profile_image: string;
profile_image_90: string;
}
baseflaretag
interface BaseFlareTag {
name: string;
}
flaretag
interface FlareTag extends BaseFlareTag {
bgColorHex: string;
textColorHex: string;
}
rawflaretag
interface RawFlareTag extends BaseFlareTag {
bg_color_hex: string;
text_color_hex: string;
}
followedtags
export interface FollowedTags {
id: number;
name: Tags;
points: number;
}
basefollower
interface BaseFollower {
id: number;
name: string;
path: EndPoint;
username: string;
}
follower
interface Follower extends BaseFollower {
typeOf: 'user_follower';
createdAt: string;
profileImage: string;
}
rawfollower
interface RawFollower extends BaseFollower {
type_of: 'user_follower';
created_at: string;
profile_image: string;
}
baselisting
interface BaseListing {
id: number;
title: string;
slug: string;
tags: Tags[];
category: string;
published: boolean;
}
listing
interface Listing extends BaseListing {
typeOf: 'listing';
createdAt: string;
bodyMarkdown: string;
tagList: string;
processedHtml: string;
user: Omit<User, 'id'>;
}
rawlisting
interface RawListing extends BaseListing {
type_of: 'listing';
created_at: string;
body_markdown: string;
tag_list: string;
processed_html: string;
user: Omit<RawUser, 'id'>;
}
basevideoarticle
interface BaseVideoArticle {
id: string;
path: string;
title: string;
}
videoarticle
interface VideoArticle extends BaseVideoArticle {
typeOf: TypeOfArticle;
cloudinaryVideoUrl: string;
userId: string;
videoDurationInMinutes: VideoDurationFormat;
videoSourceUrl: string;
user: Pick<User, 'name'>;
}
rawvideoarticle
interface RawVideoArticle extends BaseVideoArticle {
type_of: TypeOfArticle;
cloudinary_video_url: string;
user_id: string;
video_duration_in_minutes: VideoDurationFormat;
video_source_url: string;
user: Pick<RawUser, 'name'>;
}
articleidentifieroptions
interface ArticleIdentifierOptions {
aId: NumberResolvable;
pId?: never;
}
finalarticleidentifieroptions
interface FinalArticleIdentifierOptions {
a_id: NumberResolvable;
}
podcastidentifieroptions
interface PodcastIdentifierOptions {
pId: NumberResolvable;
aId?: never;
}
finalpodcastidentifieroptions
interface FinalPodcastIdentifierOptions {
p_id: NumberResolvable;
}
basepodcast
export interface BasePodcast {
title: string;
slug: string;
}
podcast
export interface Podcast extends BasePodcast {
imageUrl: string;
}
rawpodcast
export interface RawPodcast extends BasePodcast {
image_url: string;
}
basepodcastepisode
export interface BasePodcastEpisode {
id: number;
path: EndPoint;
title: string;
}
podcastepisode
export interface PodcastEpisode extends BasePodcastEpisode {
typeOf: 'podcast_episodes';
imageUrl: string;
podcast: Podcast
}
rawpodcastepisode
export interface RawPodcastEpisode extends BasePodcastEpisode {
type_of: 'podcast_episodes';
image_url: string;
podcast: RawPodcast;
}
basetag
export interface BaseTag {
id: number;
name: string;
points: number;
}
tag
export interface Tag extends BaseTag {
bgColorHex: string;
textColorHex: string;
}
rawtag
export interface RawTag extends BaseTag {
bg_color_hex: string;
text_color_hex: string;
}
usernamebasedoptions
export interface UsernameBasedOptions {
username: string;
}
basereadinglistitem
export interface BaseReadingListItem {
id: number;
status: ReadingListItemStatus;
}
readinglistitem
export interface ReadingListItem extends BaseReadingListItem {
typeOf: 'string';
createdAt: string;
article: Article;
}
rawreadinglistitem
export interface RawReadingListItem extends BaseReadingListItem {
type_of: 'string';
created_at: string;
article: RawArticle;
}
invitationoptions
export interface InvitationOptions {
email: `${string}@${string}`;
name?: string;
}
profileimage
export interface ProfileImage {
typeOf: 'profile_image';
imageOf: 'user' | 'organization';
profileImage: string;
profileImage90: string;
}
rawprofileimage
export interface RawProfileImage {
type_of: 'profile_image';
image_of: 'user' | 'organization';
profile_image: string;
profile_image_90: string;
}