mirror of
https://gitlab.com/foxixus/neomovies-api.git
synced 2025-10-28 01:48:51 +05:00
Update 4 files
- /src/index.js - /src/routes/movies.js - /src/config/tmdb.js - /vercel.json
This commit is contained in:
@@ -7,13 +7,27 @@ class TMDBClient {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
},
|
||||
timeout: 10000 // 10 секунд таймаут
|
||||
});
|
||||
|
||||
// Добавляем интерцептор для обработки ошибок
|
||||
this.client.interceptors.response.use(
|
||||
response => response,
|
||||
error => {
|
||||
console.error('TMDB API Error:', {
|
||||
status: error.response?.status,
|
||||
data: error.response?.data,
|
||||
message: error.message
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async makeRequest(method, endpoint, params = {}) {
|
||||
try {
|
||||
const response = await this.client.request({
|
||||
const response = await this.client({
|
||||
method,
|
||||
url: endpoint,
|
||||
params: {
|
||||
@@ -22,10 +36,12 @@ class TMDBClient {
|
||||
region: 'RU'
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error(`TMDB API Error: ${error.message}`);
|
||||
throw error;
|
||||
if (error.response) {
|
||||
throw new Error(`TMDB API Error: ${error.response.data.status_message || error.message}`);
|
||||
}
|
||||
throw new Error(`Network Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,71 +51,55 @@ class TMDBClient {
|
||||
}
|
||||
|
||||
async searchMovies(query, page = 1) {
|
||||
const data = await this.makeRequest('GET', '/search/movie', {
|
||||
const response = await this.makeRequest('GET', '/search/movie', {
|
||||
query,
|
||||
page,
|
||||
include_adult: false
|
||||
});
|
||||
|
||||
const data = response.data;
|
||||
|
||||
// Фильтруем результаты
|
||||
data.results = data.results.filter(movie =>
|
||||
movie.poster_path &&
|
||||
movie.overview &&
|
||||
movie.vote_average > 0
|
||||
);
|
||||
|
||||
// Добавляем полные URL для изображений
|
||||
data.results = data.results.map(movie => ({
|
||||
).map(movie => ({
|
||||
...movie,
|
||||
poster_path: this.getImageURL(movie.poster_path, 'w500'),
|
||||
backdrop_path: this.getImageURL(movie.backdrop_path, 'w1280')
|
||||
backdrop_path: this.getImageURL(movie.backdrop_path, 'original')
|
||||
}));
|
||||
|
||||
return data;
|
||||
return response;
|
||||
}
|
||||
|
||||
async getMovie(id) {
|
||||
const movie = await this.makeRequest('GET', `/movie/${id}`);
|
||||
const response = await this.makeRequest('GET', `/movie/${id}`);
|
||||
const movie = response.data;
|
||||
return {
|
||||
...movie,
|
||||
poster_path: this.getImageURL(movie.poster_path, 'w500'),
|
||||
backdrop_path: this.getImageURL(movie.backdrop_path, 'w1280')
|
||||
backdrop_path: this.getImageURL(movie.backdrop_path, 'original')
|
||||
};
|
||||
}
|
||||
|
||||
async getPopularMovies(page = 1) {
|
||||
const data = await this.makeRequest('GET', '/movie/popular', { page });
|
||||
const response = await this.makeRequest('GET', '/movie/popular', { page });
|
||||
const data = response.data;
|
||||
data.results = data.results.map(movie => ({
|
||||
...movie,
|
||||
poster_path: this.getImageURL(movie.poster_path, 'w500'),
|
||||
backdrop_path: this.getImageURL(movie.backdrop_path, 'w1280')
|
||||
backdrop_path: this.getImageURL(movie.backdrop_path, 'original')
|
||||
}));
|
||||
return data;
|
||||
return response;
|
||||
}
|
||||
|
||||
async getTopRatedMovies(page = 1) {
|
||||
const data = await this.makeRequest('GET', '/movie/top_rated', { page });
|
||||
const response = await this.makeRequest('GET', '/movie/top_rated', { page });
|
||||
const data = response.data;
|
||||
data.results = data.results.map(movie => ({
|
||||
...movie,
|
||||
poster_path: this.getImageURL(movie.poster_path, 'w500'),
|
||||
backdrop_path: this.getImageURL(movie.backdrop_path, 'w1280')
|
||||
backdrop_path: this.getImageURL(movie.backdrop_path, 'original')
|
||||
}));
|
||||
return data;
|
||||
}
|
||||
|
||||
async getUpcomingMovies(page = 1) {
|
||||
const data = await this.makeRequest('GET', '/movie/upcoming', { page });
|
||||
data.results = data.results.map(movie => ({
|
||||
...movie,
|
||||
poster_path: this.getImageURL(movie.poster_path, 'w500'),
|
||||
backdrop_path: this.getImageURL(movie.backdrop_path, 'w1280')
|
||||
}));
|
||||
return data;
|
||||
}
|
||||
|
||||
async getMovieExternalIDs(id) {
|
||||
return await this.makeRequest('GET', `/movie/${id}/external_ids`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TMDBClient;
|
||||
return response;
|
||||
|
||||
22
src/index.js
22
src/index.js
@@ -10,8 +10,8 @@ const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
// Определяем базовый URL для документации
|
||||
const BASE_URL = process.env.VERCEL_URL
|
||||
? `https://${process.env.VERCEL_URL}`
|
||||
const BASE_URL = process.env.NODE_ENV === 'production'
|
||||
? 'https://neomovies-api.vercel.app'
|
||||
: `http://localhost:${port}`;
|
||||
|
||||
// Swagger configuration
|
||||
@@ -30,7 +30,7 @@ const swaggerOptions = {
|
||||
servers: [
|
||||
{
|
||||
url: BASE_URL,
|
||||
description: process.env.VERCEL_URL ? 'Production server' : 'Development server',
|
||||
description: process.env.NODE_ENV === 'production' ? 'Production server' : 'Development server',
|
||||
},
|
||||
],
|
||||
tags: [
|
||||
@@ -207,22 +207,26 @@ const swaggerDocs = swaggerJsdoc(swaggerOptions);
|
||||
|
||||
// CORS configuration
|
||||
app.use(cors({
|
||||
origin: '*',
|
||||
origin: true, // Разрешаем все origins в development
|
||||
credentials: true,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization'],
|
||||
credentials: true
|
||||
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) => {
|
||||
if (!process.env.TMDB_ACCESS_TOKEN) {
|
||||
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(process.env.TMDB_ACCESS_TOKEN);
|
||||
req.tmdb = new TMDBClient(token);
|
||||
next();
|
||||
});
|
||||
|
||||
@@ -268,5 +272,5 @@ app.use((err, req, res, next) => {
|
||||
// Start server
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running on port ${port}`);
|
||||
console.log(`Documentation available at https://neomovies-api/api-docs`);
|
||||
console.log(`Documentation available at https://neomovies-api.vercel.app/api-docs`);
|
||||
});
|
||||
@@ -62,30 +62,34 @@ const { formatDate } = require('../utils/date');
|
||||
router.get('/search', async (req, res) => {
|
||||
try {
|
||||
const { query, page = 1 } = req.query;
|
||||
|
||||
if (!query) {
|
||||
return res.status(400).json({ error: "query parameter is required" });
|
||||
return res.status(400).json({ error: 'Query parameter is required' });
|
||||
}
|
||||
|
||||
const results = await req.tmdb.searchMovies(query, page);
|
||||
const response = await req.tmdb.searchMovies(query, page);
|
||||
|
||||
const response = {
|
||||
page: results.page,
|
||||
total_pages: results.total_pages,
|
||||
total_results: results.total_results,
|
||||
results: results.results.map(movie => ({
|
||||
id: movie.id,
|
||||
title: movie.title,
|
||||
overview: movie.overview,
|
||||
release_date: formatDate(movie.release_date),
|
||||
vote_average: movie.vote_average,
|
||||
poster_path: movie.poster_path,
|
||||
backdrop_path: movie.backdrop_path
|
||||
}))
|
||||
};
|
||||
if (!response || !response.data) {
|
||||
throw new Error('Failed to fetch data from TMDB');
|
||||
}
|
||||
|
||||
res.json(response);
|
||||
const { results, ...rest } = response.data;
|
||||
|
||||
const formattedResults = results.map(movie => ({
|
||||
...movie,
|
||||
release_date: formatDate(movie.release_date)
|
||||
}));
|
||||
|
||||
res.json({
|
||||
...rest,
|
||||
results: formattedResults
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: error.message });
|
||||
console.error('Search movies error:', error);
|
||||
res.status(500).json({
|
||||
error: 'Failed to search movies',
|
||||
details: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
35
vercel.json
35
vercel.json
@@ -9,14 +9,43 @@
|
||||
"routes": [
|
||||
{
|
||||
"src": "/api-docs/(.*)",
|
||||
"dest": "src/index.js"
|
||||
"headers": {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "X-Requested-With, Content-Type, Accept"
|
||||
},
|
||||
"dest": "/src/index.js"
|
||||
},
|
||||
{
|
||||
"src": "/movies/(.*)",
|
||||
"headers": {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "X-Requested-With, Content-Type, Accept"
|
||||
},
|
||||
"dest": "/src/index.js"
|
||||
},
|
||||
{
|
||||
"src": "/health",
|
||||
"headers": {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "X-Requested-With, Content-Type, Accept"
|
||||
},
|
||||
"dest": "/src/index.js"
|
||||
},
|
||||
{
|
||||
"src": "/(.*)",
|
||||
"dest": "src/index.js"
|
||||
"headers": {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "X-Requested-With, Content-Type, Accept"
|
||||
},
|
||||
"dest": "/src/index.js"
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"NODE_ENV": "production"
|
||||
"NODE_ENV": "production",
|
||||
"TMDB_ACCESS_TOKEN": "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJkOWRlZTY5ZjYzNzYzOGU2MjY5OGZhZGY0ZjhhYTNkYyIsInN1YiI6IjY1OTVkNmM5ODY5ZTc1NzJmOTY1MjZiZiIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.Wd_tBYGkAoGPVHq3A5DwV1iLs_eGvH3RRz86ghJTmU8"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user