import axios, { AxiosInstance } from 'axios';
export interface Recipe {
id: number;
name: string;
description?: string;
url?: string;
image?: string;
category?: string;
keywords?: string[];
recipeYield?: number;
prepTime?: string;
cookTime?: string;
totalTime?: string;
nutrition?: any;
tools?: string[];
recipeIngredient?: string[];
recipeInstructions?: string[];
dateCreated?: string;
dateModified?: string;
}
export interface RecipeStub {
recipe_id: number;
name: string;
keywords: string;
dateCreated: string;
dateModified: string;
imageUrl: string;
imagePlaceholderUrl: string;
}
export interface Category {
name: string;
recipe_count: number;
}
export class NextcloudCookbookClient {
private client: AxiosInstance;
private baseUrl: string;
constructor(baseUrl: string, username: string, password: string) {
this.baseUrl = baseUrl.replace(/\/$/, ''); // Remove trailing slash
this.client = axios.create({
baseURL: `${this.baseUrl}/apps/cookbook`,
auth: {
username,
password,
},
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
});
}
/**
* Get API version
*/
async getVersion(): Promise<any> {
const response = await this.client.get('/api/version');
return response.data;
}
/**
* List all recipes (returns recipe stubs)
*/
async listRecipes(): Promise<RecipeStub[]> {
const response = await this.client.get('/api/v1/recipes');
return response.data;
}
/**
* Search recipes by query
*/
async searchRecipes(query: string): Promise<RecipeStub[]> {
const response = await this.client.get(`/api/v1/search/${encodeURIComponent(query)}`);
return response.data;
}
/**
* Get recipe details by ID
*/
async getRecipe(id: number): Promise<Recipe> {
const response = await this.client.get(`/api/v1/recipes/${id}`);
return response.data;
}
/**
* Create a new recipe
*/
async createRecipe(recipe: Partial<Recipe>): Promise<Recipe> {
const response = await this.client.post('/api/v1/recipes', recipe);
return response.data;
}
/**
* Update an existing recipe
*/
async updateRecipe(id: number, recipe: Partial<Recipe>): Promise<Recipe> {
const response = await this.client.put(`/api/v1/recipes/${id}`, recipe);
return response.data;
}
/**
* Delete a recipe
*/
async deleteRecipe(id: number): Promise<void> {
await this.client.delete(`/api/v1/recipes/${id}`);
}
/**
* Get recipe image URL
*/
getRecipeImageUrl(id: number, size: 'full' | 'thumb' | 'thumb16' = 'full'): string {
return `${this.baseUrl}/apps/cookbook/api/v1/recipes/${id}/image?size=${size}`;
}
/**
* Import recipe from URL
*/
async importRecipe(url: string): Promise<Recipe> {
const response = await this.client.post('/api/v1/import', { url });
return response.data;
}
/**
* List all categories
*/
async listCategories(): Promise<Category[]> {
const response = await this.client.get('/api/v1/categories');
return response.data;
}
/**
* List all keywords
*/
async listKeywords(): Promise<string[]> {
const response = await this.client.get('/api/v1/keywords');
return response.data;
}
/**
* Get recipes by keyword
*/
async getRecipesByKeyword(keyword: string): Promise<RecipeStub[]> {
const response = await this.client.get(`/api/v1/tags/${encodeURIComponent(keyword)}`);
return response.data;
}
}