73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
import { Router } from 'express';
|
|
import { z } from 'zod';
|
|
import { UrlImportService } from '../services/UrlImportService.js';
|
|
import { SchemaOrgRecipeParserService } from '../services/SchemaOrgRecipeParserService.js';
|
|
import { HeuristicRecipeParserService } from '../services/HeuristicRecipeParserService.js';
|
|
|
|
const importUrlSchema = z.object({
|
|
url: z.string().url('A valid URL is required'),
|
|
});
|
|
|
|
export function createImportRoutes(): Router {
|
|
const router = Router();
|
|
const urlImportService = new UrlImportService();
|
|
const schemaOrgParser = new SchemaOrgRecipeParserService();
|
|
const heuristicParser = new HeuristicRecipeParserService();
|
|
|
|
/**
|
|
* POST /api/import/url
|
|
* Fetch an external recipe page and return imported, normalized Recipe (if found)
|
|
*/
|
|
router.post('/url', async (req, res) => {
|
|
try {
|
|
const { url } = importUrlSchema.parse(req.body);
|
|
const result = await urlImportService.fetchFromUrl(url);
|
|
|
|
// Try to parse and normalize Recipe from JSON-LD blocks
|
|
let draft: any = null;
|
|
for (const block of result.json_ld_blocks) {
|
|
draft = schemaOrgParser.parseJsonLdBlock(block);
|
|
if (draft) break;
|
|
}
|
|
|
|
// Fallback: heuristic HTML parser when Schema.org data is missing/invalid
|
|
if (!draft) {
|
|
draft = heuristicParser.parseHtml(result.html, result.source_url);
|
|
}
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
data: { ...result, draft_recipe: draft },
|
|
error: null,
|
|
});
|
|
} catch (error) {
|
|
if (error instanceof z.ZodError) {
|
|
res.status(400).json({
|
|
success: false,
|
|
data: null,
|
|
error: error.errors,
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (error instanceof Error) {
|
|
const status = error.message.includes('timed out') ? 504 : 400;
|
|
res.status(status).json({
|
|
success: false,
|
|
data: null,
|
|
error: error.message,
|
|
});
|
|
return;
|
|
}
|
|
|
|
res.status(500).json({
|
|
success: false,
|
|
data: null,
|
|
error: 'Internal server error',
|
|
});
|
|
}
|
|
});
|
|
|
|
return router;
|
|
}
|