Standalone, self-contained Hashnode GraphQL API client for Next.js and Node.js
npm install @jowinjohnchemban/hashnode-clientaxios)
hashnode/ folder to any project and it will work immediately.
src/lib/api/hashnode/
โโโ index.ts # Public API facade (barrel exports)
โโโ service.ts # Core service class (business logic)
โโโ queries.ts # GraphQL query builder
โโโ types.ts # TypeScript type definitions
โโโ config.ts # Configuration constants
โโโ graphql-client.ts # Internal GraphQL client (self-contained)
โโโ README.md # This file
`
โจ All dependencies are internal - no imports from outside this folder!
๐ฏ Purpose
Adapter/Handler that:
- โ
Abstracts Hashnode GraphQL API complexity
- โ
Provides type-safe TypeScript interfaces
- โ
Handles error management gracefully
- โ
Caches responses using Next.js ISR
- โ
Can be replaced without changing consuming code
๐ง Usage
$3
`typescript
import { getBlogPosts, getBlogPostBySlug, getPublication } from '@/lib/api/hashnode';
// Fetch blog posts
const posts = await getBlogPosts(10);
// Fetch single post
const post = await getBlogPostBySlug('my-blog-post');
// Fetch publication details
const publication = await getPublication();
`
$3
`typescript
import { hashnodeService } from '@/lib/api/hashnode';
// Use the singleton service directly
const posts = await hashnodeService.getBlogPosts(20);
const adjacentPosts = await hashnodeService.getAdjacentPosts('current-slug');
`
๐๏ธ Module Components
$3
- Role: Barrel export file exposing public API
- Pattern: Facade pattern - simplifies access to module functionality
- Exports: Convenience functions + service singleton
$3
- Role: Handles all Hashnode API interactions
- Pattern: Service/Repository pattern
- Responsibilities:
- GraphQL query execution
- Response transformation
- Error handling
- Caching coordination
$3
- Role: Centralized GraphQL query definitions
- Pattern: Builder pattern
- Benefits: Reusable query fragments, type safety
$3
- Role: TypeScript interfaces for all API data
- Pattern: Interface Segregation Principle
- Coverage: Posts, Authors, Tags, Responses, etc.
$3
- Role: Centralized configuration constants
- Pattern: Configuration object pattern
- Settings: API URLs, timeouts, defaults
$3
- Role: Network layer for GraphQL queries
- Pattern: Adapter pattern wrapping axios
- Benefits: Makes module self-contained and portable
- Error Handling: Custom GraphQLError class
๐ Data Flow
`
Page/Component (RSC)
โ
getBlogPosts() โ Convenience function (index.ts)
โ
HashnodeService โ Business logic (service.ts)
โ
GraphQL Query โ Query builder (queries.ts)
โ
GraphQL Client โ Internal network layer (graphql-client.ts) โจ
โ
Hashnode GraphQL API
`
Note: The GraphQL client is internal to this module, making it fully portable!
๐ก๏ธ Error Handling
All public functions return safe defaults on error:
- getBlogPosts() โ [] (empty array)
- getBlogPostBySlug() โ null
- getPublication() โ null
Errors are caught and logged internally. No exceptions leak to consuming code.
โก Performance
- ISR Caching: Next.js revalidates data every hour (revalidate: 3600)
- Timeout: 15s GraphQL request timeout
- Pagination: Cursor-based pagination support
- Optimized Queries: Only fetches required fields
๐ Replacing the Adapter
To switch from Hashnode to another blogging platform:
1. Keep the same exports in index.ts
2. Replace internal implementation in service.ts
3. Update types as needed
4. Consuming code remains unchanged โจ
Example:
`typescript
// Before: Hashnode
import { getBlogPosts } from '@/lib/api/hashnode';
// After: WordPress (same API)
import { getBlogPosts } from '@/lib/api/wordpress';
`
๐ Using as an Open-Source Library
$3
`bash
Copy the entire folder
cp -r src/lib/api/hashnode your-project/lib/api/hashnode
Install the only dependency
npm install axios
`
$3
`bash
git submodule add lib/api/hashnode
`
๐ Environment Variables
Required:
`env
NEXT_PUBLIC_HASHNODE_PUBLICATION_HOST="yourblog.hashnode.dev"
`
๐งช Testing
`typescript
// Mock the service for testing
jest.mock('@/lib/api/hashnode', () => ({
getBlogPosts: jest.fn().mockResolvedValue([/ mock posts /]),
getBlogPostBySlug: jest.fn().mockResolvedValue(/ mock post /),
}));
`
๐ API Reference
$3
Fetch multiple blog posts.
$3
Fetch a single post by slug (includes full content).
$3
Fetch publication metadata (for SEO, site info).
$3
Get previous/next posts relative to current slug.
๐ฆ Dependencies
Only one external dependency:
`json
{
"dependencies": {
"axios": "^1.13.2"
}
}
`
Everything else is self-contained within this module!
๐๏ธ Design Principles
- Single Responsibility: Each file has one clear purpose
- Dependency Inversion: Depends on abstractions (HttpClient)
- Open/Closed: Open for extension, closed for modification
- Interface Segregation: Minimal, focused interfaces
- DRY: Query fragments reused across queries
๐ Related Documentation
- Hashnode GraphQL API Docs
- Next.js ISR Documentation
---
๐ฆ Installation & Requirements
$3
- Node.js 18+ or 20+
- TypeScript 5.0+ (for TypeScript projects)
- Environment variable: HASHNODE_PUBLICATION_HOST (your Hashnode publication domain)
$3
Copy the folder to your project:
`bash
Copy entire hashnode folder to your project
cp -r src/lib/api/hashnode your-project/src/lib/api/
Install axios dependency
npm install axios
`
Set HASHNODE_PUBLICATION_HOST in your .env.local` and you're ready!