@el_saintt/adapter-nextjs
v1.0.0
Published
Next.js adapter for @el_saintt/core - App Router and Pages Router support
Maintainers
Readme
@el_saintt/adapter-nextjs
Next.js adapter for Portfolio API - Supports both App Router (Next.js 13+) and Pages Router.
Installation
npm install @el_saintt/adapter-nextjs @el_saintt/core nextQuick Start
App Router (Next.js 13+)
Create a catch-all route handler in app/api/portfolio/[[...slug]]/route.ts:
import { PortfolioClient } from '@el_saintt/core';
import { githubPlugin } from '@el_saintt/plugin-github';
import { createPortfolioHandlers } from '@el_saintt/adapter-nextjs/app';
import { NextRequest } from 'next/server';
// Initialize client
const client = new PortfolioClient({
cache: {
provider: 'memory',
defaultTTL: 3600,
},
services: {
github: {
enabled: true,
credentials: {
username: process.env.GITHUB_USERNAME!,
},
},
},
});
// Register plugins
client.use(githubPlugin);
// Create handlers
const handlers = createPortfolioHandlers({
client,
enableCors: true,
});
// Export route handlers
export async function GET(
request: NextRequest,
context: { params: { slug?: string[] } }
) {
const slug = context.params.slug || [];
// Route to appropriate handler
if (slug[0] === 'services') {
if (!slug[1]) {
return handlers.getServices(request);
} else if (slug[2] === 'health') {
return handlers.getServiceHealth(request, { params: { service: slug[1] } });
} else {
return handlers.getService(request, { params: { service: slug[1] } });
}
} else if (slug[0] === 'content') {
if (!slug[1]) {
return handlers.getAllContent(request);
} else {
return handlers.getServiceContent(request, { params: { service: slug[1] } });
}
} else if (slug[0] === 'health') {
return handlers.getHealth(request);
} else if (slug[0] === 'validate') {
return handlers.validateConfig(request);
}
return new Response(JSON.stringify({ error: 'Not found' }), {
status: 404,
headers: { 'Content-Type': 'application/json' },
});
}
// Handle OPTIONS for CORS
export async function OPTIONS(request: NextRequest) {
return new Response(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
});
}Pages Router
Create a catch-all API route in pages/api/portfolio/[[...slug]].ts:
import { PortfolioClient } from '@el_saintt/core';
import { githubPlugin } from '@el_saintt/plugin-github';
import { createPortfolioApiRoute } from '@el_saintt/adapter-nextjs/pages';
// Initialize client
const client = new PortfolioClient({
cache: {
provider: 'memory',
defaultTTL: 3600,
},
services: {
github: {
enabled: true,
credentials: {
username: process.env.GITHUB_USERNAME!,
},
},
},
});
// Register plugins
client.use(githubPlugin);
// Create and export handler
export default createPortfolioApiRoute({
client,
enableCors: true,
});API Endpoints
Both routers create the same REST API endpoints:
Services
GET /api/portfolio/services
- List all configured services
- Response:
{ success: true, data: { services: [...] } }
GET /api/portfolio/services/:service
- Get information about a specific service
- Example:
/api/portfolio/services/github
GET /api/portfolio/services/:service/health
- Check health of a specific service
- Example:
/api/portfolio/services/github/health
Content
GET /api/portfolio/content
- Get all content from all services
- Query params:
limit,offset,since,until,skipCache
GET /api/portfolio/content/:service
- Get content from a specific service
- Example:
/api/portfolio/content/github?limit=5
Health & Validation
GET /api/portfolio/health
- Check health of all services
GET /api/portfolio/validate
- Validate configuration
Advanced Usage
Enable CORS
// App Router
const handlers = createPortfolioHandlers({
client,
enableCors: true,
corsOrigins: ['https://example.com'], // Or ['*'] for all origins
});
// Pages Router
export default createPortfolioApiRoute({
client,
enableCors: true,
corsOrigins: ['https://example.com'],
});Server-Side Data Fetching
App Router (Server Components)
import { PortfolioClient } from '@el_saintt/core';
import { githubPlugin } from '@el_saintt/plugin-github';
// In a Server Component
export default async function Page() {
const client = new PortfolioClient({ /* config */ });
client.use(githubPlugin);
const content = await client.fetch('github', { limit: 5 });
return (
<div>
{content.map(item => (
<div key={item.id}>{item.title}</div>
))}
</div>
);
}Pages Router (getServerSideProps)
import { GetServerSideProps } from 'next';
import { PortfolioClient } from '@el_saintt/core';
import { githubPlugin } from '@el_saintt/plugin-github';
export const getServerSideProps: GetServerSideProps = async () => {
const client = new PortfolioClient({ /* config */ });
client.use(githubPlugin);
const content = await client.fetch('github', { limit: 5 });
return {
props: {
content,
},
};
};Pages Router (getStaticProps)
import { GetStaticProps } from 'next';
import { PortfolioClient } from '@el_saintt/core';
import { githubPlugin } from '@el_saintt/plugin-github';
export const getStaticProps: GetStaticProps = async () => {
const client = new PortfolioClient({ /* config */ });
client.use(githubPlugin);
const content = await client.fetch('github', { limit: 5 });
return {
props: {
content,
},
revalidate: 3600, // ISR: revalidate every hour
};
};Response Format
All responses follow a consistent format:
Success Response
{
"success": true,
"data": { ... },
"meta": {
"timestamp": "2024-10-10T12:00:00.000Z",
"count": 10,
"service": "github"
}
}Error Response
{
"success": false,
"error": {
"message": "Service not found",
"code": "SERVICE_NOT_FOUND",
"details": { ... }
},
"meta": {
"timestamp": "2024-10-10T12:00:00.000Z"
}
}TypeScript Support
Full TypeScript support with proper types:
import {
PortfolioResponse,
PortfolioAPIOptions,
createPortfolioHandlers,
} from '@el_saintt/adapter-nextjs';
// All exports are fully typedEnvironment Variables
# Example .env.local
GITHUB_USERNAME=your-username
GITHUB_TOKEN=ghp_your_token_here
MEDIUM_USERNAME=@your-username
YOUTUBE_API_KEY=AIza_your_api_key
YOUTUBE_CHANNEL_ID=UC_your_channel_idExamples
License
MIT
