mirror of
https://gitlab.com/foxixus/neomovies-api.git
synced 2025-10-28 01:48:51 +05:00
198 lines
6.3 KiB
JavaScript
198 lines
6.3 KiB
JavaScript
require('dotenv').config();
|
||
const express = require('express');
|
||
const cors = require('cors');
|
||
const swaggerJsdoc = require('swagger-jsdoc');
|
||
const path = require('path');
|
||
const TMDBClient = require('./config/tmdb');
|
||
const healthCheck = require('./utils/health');
|
||
|
||
const app = express();
|
||
|
||
// Определяем базовый URL для документации
|
||
const BASE_URL = process.env.NODE_ENV === 'production'
|
||
? 'https://neomovies-api.vercel.app'
|
||
: 'http://localhost:3000';
|
||
|
||
// Swagger configuration
|
||
const swaggerOptions = {
|
||
definition: {
|
||
openapi: '3.0.0',
|
||
info: {
|
||
title: 'Neo Movies API',
|
||
version: '1.0.0',
|
||
description: 'API для поиска и получения информации о фильмах с поддержкой русского языка',
|
||
contact: {
|
||
name: 'API Support',
|
||
url: 'https://gitlab.com/foxixus/neomovies-api'
|
||
}
|
||
},
|
||
servers: [
|
||
{
|
||
url: BASE_URL,
|
||
description: process.env.NODE_ENV === 'production' ? 'Production server' : 'Development server'
|
||
}
|
||
],
|
||
tags: [
|
||
{
|
||
name: 'movies',
|
||
description: 'Операции с фильмами'
|
||
},
|
||
{
|
||
name: 'health',
|
||
description: 'Проверка работоспособности API'
|
||
}
|
||
],
|
||
components: {
|
||
schemas: {
|
||
Movie: {
|
||
type: 'object',
|
||
properties: {
|
||
id: {
|
||
type: 'integer',
|
||
description: 'ID фильма'
|
||
},
|
||
title: {
|
||
type: 'string',
|
||
description: 'Название фильма'
|
||
},
|
||
overview: {
|
||
type: 'string',
|
||
description: 'Описание фильма'
|
||
},
|
||
release_date: {
|
||
type: 'string',
|
||
format: 'date',
|
||
description: 'Дата выхода'
|
||
},
|
||
vote_average: {
|
||
type: 'number',
|
||
description: 'Средняя оценка'
|
||
},
|
||
poster_path: {
|
||
type: 'string',
|
||
description: 'URL постера'
|
||
},
|
||
backdrop_path: {
|
||
type: 'string',
|
||
description: 'URL фонового изображения'
|
||
}
|
||
}
|
||
},
|
||
Error: {
|
||
type: 'object',
|
||
properties: {
|
||
error: {
|
||
type: 'string',
|
||
description: 'Сообщение об ошибке'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
apis: [path.join(__dirname, 'routes', '*.js'), __filename]
|
||
};
|
||
|
||
const swaggerDocs = swaggerJsdoc(swaggerOptions);
|
||
|
||
// CORS configuration
|
||
app.use(cors({
|
||
origin: true,
|
||
credentials: true,
|
||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||
allowedHeaders: ['X-Requested-With', 'Content-Type', 'Authorization', 'Accept']
|
||
}));
|
||
|
||
// Handle preflight requests
|
||
app.options('*', cors());
|
||
|
||
// Middleware
|
||
app.use(express.json());
|
||
app.use(express.static(path.join(__dirname, 'public')));
|
||
|
||
// TMDB client middleware
|
||
app.use((req, res, next) => {
|
||
const token = process.env.TMDB_ACCESS_TOKEN || 'eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJkOWRlZTY5ZjYzNzYzOGU2MjY5OGZhZGY0ZjhhYTNkYyIsInN1YiI6IjY1OTVkNmM5ODY5ZTc1NzJmOTY1MjZiZiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.Wd_tBYGkAoGPVHq3A5DwV1iLs_eGvH3RRz86ghJTmU8';
|
||
if (!token) {
|
||
return res.status(500).json({ error: 'TMDB_ACCESS_TOKEN is not set' });
|
||
}
|
||
req.tmdb = new TMDBClient(token);
|
||
next();
|
||
});
|
||
|
||
// API Documentation routes
|
||
app.get('/api-docs', (req, res) => {
|
||
res.sendFile(path.join(__dirname, 'public', 'api-docs', 'index.html'));
|
||
});
|
||
|
||
app.get('/api-docs/swagger.json', (req, res) => {
|
||
res.setHeader('Content-Type', 'application/json');
|
||
res.send(swaggerDocs);
|
||
});
|
||
|
||
// API routes
|
||
app.use('/movies', require('./routes/movies'));
|
||
|
||
/**
|
||
* @swagger
|
||
* /health:
|
||
* get:
|
||
* tags: [health]
|
||
* summary: Проверка работоспособности API
|
||
* description: Возвращает подробную информацию о состоянии API, включая статус TMDB, использование памяти и системную информацию
|
||
* responses:
|
||
* 200:
|
||
* description: API работает нормально
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* status:
|
||
* type: string
|
||
* enum: [ok, error]
|
||
* tmdb:
|
||
* type: object
|
||
* properties:
|
||
* status:
|
||
* type: string
|
||
* enum: [ok, error]
|
||
*/
|
||
app.get('/health', async (req, res) => {
|
||
try {
|
||
const health = await healthCheck.getFullHealth(req.tmdb);
|
||
res.json(health);
|
||
} catch (error) {
|
||
res.status(500).json({
|
||
status: 'error',
|
||
error: error.message
|
||
});
|
||
}
|
||
});
|
||
|
||
// Error handling
|
||
app.use((err, req, res, next) => {
|
||
console.error('Error:', err);
|
||
res.status(500).json({
|
||
error: 'Internal Server Error',
|
||
message: process.env.NODE_ENV === 'development' ? err.message : undefined
|
||
});
|
||
});
|
||
|
||
// Handle 404
|
||
app.use((req, res) => {
|
||
res.status(404).json({ error: 'Not Found' });
|
||
});
|
||
|
||
// Export the Express API
|
||
module.exports = app;
|
||
|
||
// Start server only in development
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
const port = process.env.PORT || 3000;
|
||
app.listen(port, () => {
|
||
console.log(`Server is running on port ${port}`);
|
||
console.log(`Documentation available at http://localhost:${port}/api-docs`);
|
||
});
|
||
}
|