94 lines
3.5 KiB
JavaScript
94 lines
3.5 KiB
JavaScript
/**
|
|
* Posimai Tech Events - /api/events
|
|
*
|
|
* GET /api/events?q=keyword -> Connpass APIを呼び出して整形したイベント一覧を返す。
|
|
*
|
|
* Connpass API: https://connpass.com/about/api/
|
|
*/
|
|
|
|
export default async function handler(req, res) {
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
res.setHeader('Cache-Control', 's-maxage=1800, stale-while-revalidate=3600');
|
|
|
|
if (req.method === 'OPTIONS') {
|
|
return res.status(200).end();
|
|
}
|
|
|
|
if (req.method !== 'GET') {
|
|
return res.status(405).json({ error: 'Method not allowed' });
|
|
}
|
|
|
|
try {
|
|
const { q } = req.query;
|
|
// Search either specific query from UI or broad default queries for tech events
|
|
const fetchKeyword = q && q.trim().length > 0 ? q.trim() : 'IT,エンジニア,デザイン,Web,AI,アプリ';
|
|
const urlObj = new URL('https://connpass.com/api/v1/event/');
|
|
// ConnpassのOR検索仕様に合わせて keyword_or を使用する
|
|
urlObj.searchParams.append('keyword_or', fetchKeyword);
|
|
urlObj.searchParams.append('order', '2'); // 開催降順(新着イベント)
|
|
urlObj.searchParams.append('count', '50');
|
|
|
|
// Connpass APIはUser-Agentが必須
|
|
const response = await fetch(urlObj.toString(), {
|
|
headers: {
|
|
'User-Agent': 'PosimaiTechEvents/1.0 (https://posimai-tech-events.vercel.app)'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
console.error('Connpass API Error', await response.text());
|
|
res.status(502).json({ error: 'Failed to fetch events from Connpass' });
|
|
return;
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
// Map to Posimai Events structure
|
|
const events = (data.events || []).map(ev => {
|
|
const startStr = ev.started_at || '';
|
|
const endStr = ev.ended_at || '';
|
|
|
|
const startDate = startStr.slice(0, 10);
|
|
const startTime = startStr.slice(11, 16);
|
|
const endDate = endStr.slice(0, 10);
|
|
const endTime = endStr.slice(11, 16);
|
|
|
|
let location = ev.place || 'オンライン';
|
|
if (!ev.address && !ev.place) {
|
|
if (ev.event_url && ev.event_type === 'online') location = 'オンライン開催';
|
|
else location = '会場未定 / オンライン';
|
|
}
|
|
|
|
return {
|
|
id: String(ev.event_id),
|
|
title: ev.title,
|
|
startDate: startDate,
|
|
startTime: startTime,
|
|
endDate: endDate,
|
|
endTime: endTime,
|
|
location: location,
|
|
address: ev.address || '',
|
|
description: ev.catch || '詳細説明はリンク先をご覧ください。',
|
|
category: ev.series ? ev.series.title : 'IT/テック',
|
|
url: ev.event_url,
|
|
source: 'Connpass',
|
|
// To be enhanced: derive tags based on title/description
|
|
interestTags: [],
|
|
audienceTags: []
|
|
};
|
|
});
|
|
|
|
return res.status(200).json({
|
|
events: events,
|
|
updatedAt: new Date().toISOString(),
|
|
source: 'connpass'
|
|
});
|
|
|
|
} catch (e) {
|
|
console.error('API /events error:', e);
|
|
return res.status(500).json({ error: 'Internal Server Error' });
|
|
}
|
|
}
|