Skip to content

frontendnetwork/veganify-api-wrapper

Repository files navigation

Veganify API logo

Veganify API Wrapper 2.0

A modern, type-safe wrapper for the official Veganify API with built-in validation, caching, and comprehensive error handling.

TypeScript Testing NPM Version

Features

  • 🎯 Type Safety: Full TypeScript support with Zod validation
  • 🚀 Performance: Built-in caching system
  • 🛡️ Robust Error Handling: Custom error types for different scenarios
  • Framework Agnostic: Works with any JavaScript framework
  • 🔄 Modern Architecture: Singleton pattern with configurable instances

Installation

You can install the package via npm, yarn, or pnpm, bun, etc.:

# Using npm
npm install @frontendnetwork/veganify

# Using yarn
yarn add @frontendnetwork/veganify

# Using pnpm
pnpm add @frontendnetwork/veganify

Quick Start

import Veganify from "@frontendnetwork/veganify";

// Get an instance with default configuration
const veganify = Veganify.getInstance();

// Example: Check if ingredients are vegan
async function checkIngredients() {
  try {
    const result = await veganify.checkIngredientsListV1("water, sugar, milk");
    console.log("Is vegan:", result.data.vegan);
    console.log("Non-vegan ingredients:", result.data.not_vegan);
  } catch (error) {
    if (error instanceof ValidationError) {
      console.error("Invalid ingredients format:", error.message);
    }
  }
}

Configuration

interface VeganifyConfig {
  baseUrl?: string; // Custom API base URL
  cacheTTL?: number; // Cache time-to-live in milliseconds
  staging?: boolean; // Use staging environment
}

// Example: Configure with custom settings
const veganify = Veganify.getInstance({
  cacheTTL: 3600000, // 1 hour cache
  staging: true, // Use staging environment
});

API Reference

Product Information

getProductByBarcode(barcode: string): Promise<ProductResponse>

Retrieves detailed product information using a barcode number. This method queries multiple databases to gather comprehensive vegan and ethical product data.

Parameters:

  • barcode: A string containing the product barcode (must contain only digits)

Returns:

A promise that resolves to a ProductResponse object containing the response type.

try {
  const product = await veganify.getProductByBarcode("4066600204404");
  console.log(product.product.vegan); // true/false/"n/a"
  console.log(product.product.productname); // "Product Name"
} catch (error) {
  if (error instanceof NotFoundError) {
    console.error("Product not found");
  } else if (error instanceof ValidationError) {
    console.error("Invalid barcode format");
  }
}

Response Type:

interface ProductResponse {
  status: number;
  product: {
    productname: string;
    genericname?: string;
    vegan?: boolean | "n/a";
    vegetarian?: boolean | "n/a";
    animaltestfree?: boolean | "n/a";
    palmoil?: boolean | "n/a";
    nutriscore?: string;
    grade?: string;
  };
  sources: {
    processed: boolean;
    api: string;
    baseuri: string;
  };
}

Ingredients Analysis

checkIngredientsListV1(ingredientsList: string, preprocessed?: boolean): Promise<IngredientsCheckResponseV1>

Analyzes a list of ingredients to determine their vegan status. The method categorizes ingredients into different groups based on certainty of their vegan status.

Parameters:

  • ingredientsList: A string containing comma-separated ingredients
  • preprocessed: (Optional) Boolean indicating whether to preprocess the ingredients list (defaults to true)

Returns:

A promise that resolves to an IngredientsCheckResponseV1 return type.

try {
  const result = await veganify.checkIngredientsListV1("water, sugar, milk");
  console.log("Is vegan:", result.data.vegan);
  console.log("Surely vegan:", result.data.surely_vegan);
  console.log("Not vegan:", result.data.not_vegan);
  console.log("Maybe not vegan:", result.data.maybe_not_vegan);
  console.log("Unknown:", result.data.unknown);
} catch (error) {
  if (error instanceof ValidationError) {
    console.error("Invalid ingredients format");
  }
}

Response Type:

interface IngredientsCheckResponseV1 {
  code: string;
  status: string;
  message: string;
  data: {
    vegan: boolean;
    surely_vegan: string[];
    not_vegan: string[];
    maybe_not_vegan: string[];
    unknown: string[];
  };
}

PETA Cruelty-Free Brands

getPetaCrueltyFreeBrands(): Promise<PetaCrueltyFreeResponse>

Retrieves the current list of PETA-certified cruelty-free brands.

Returns: A promise that resolves to a PetaCrueltyFreeResponse object:

interface PetaCrueltyFreeResponse {
  LAST_UPDATE: string; // Last database update timestamp
  PETA_DOES_NOT_TEST: string[]; // Array of cruelty-free brand names
}
try {
  const brands = await veganify.getPetaCrueltyFreeBrands();
  console.log("Last update:", brands.LAST_UPDATE);
  console.log("Cruelty-free brands:", brands.PETA_DOES_NOT_TEST);
} catch (error) {
  console.error("Failed to fetch PETA brands:", error.message);
}

Error Handling

The package provides custom error classes for different scenarios:

import {
  ValidationError,
  NotFoundError,
  VeganifyError,
} from "@frontendnetwork/veganify";

try {
  // Your code here
} catch (error) {
  if (error instanceof ValidationError) {
    // Handle validation errors (400)
  } else if (error instanceof NotFoundError) {
    // Handle not found errors (404)
  } else if (error instanceof VeganifyError) {
    // Handle other API errors
  } else {
    // Handle unexpected errors
  }
}

Framework Examples

React Example

import { useState } from "react";
import Veganify, { ValidationError } from "@frontendnetwork/veganify";

const IngredientsChecker = () => {
  const [ingredients, setIngredients] = useState("");
  const [result, setResult] = useState(null);
  const [error, setError] = useState("");
  const veganify = Veganify.getInstance();

  const handleCheck = async (e) => {
    e.preventDefault();
    try {
      const analysis = await veganify.checkIngredientsListV1(ingredients);
      setResult(analysis);
      setError("");
    } catch (error) {
      setResult(null);
      if (error instanceof ValidationError) {
        setError("Please enter valid ingredients");
      } else {
        setError("An error occurred while checking ingredients");
      }
    }
  };

  return (
    <div>
      <form onSubmit={handleCheck}>
        <input
          value={ingredients}
          onChange={(e) => setIngredients(e.target.value)}
          placeholder="Enter ingredients (comma-separated)"
        />
        <button type="submit">Check Ingredients</button>
      </form>

      {error && <div className="error">{error}</div>}

      {result && (
        <div>
          <h3>Analysis Results:</h3>
          <p>Vegan: {result.data.vegan ? "Yes" : "No"}</p>
          {result.data.not_vegan.length > 0 && (
            <p>Non-vegan ingredients: {result.data.not_vegan.join(", ")}</p>
          )}
          {result.data.maybe_not_vegan.length > 0 && (
            <p>
              Potentially non-vegan: {result.data.maybe_not_vegan.join(", ")}
            </p>
          )}
        </div>
      )}
    </div>
  );
};

export default IngredientsChecker;

Vue Example

<template>
  <div>
    <form @submit.prevent="checkIngredients">
      <input
        v-model="ingredients"
        placeholder="Enter ingredients (comma-separated)"
      />
      <button type="submit">Check</button>
    </form>

    <div v-if="error" class="error">{{ error }}</div>

    <div v-if="result">
      <h3>Analysis Results:</h3>
      <p>Vegan Status: {{ result.data.vegan ? "Vegan" : "Not Vegan" }}</p>
      <p v-if="result.data.not_vegan.length">
        Non-vegan ingredients: {{ result.data.not_vegan.join(", ") }}
      </p>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
import Veganify, { ValidationError } from "@frontendnetwork/veganify";

const veganify = Veganify.getInstance();
const ingredients = ref("");
const result = ref(null);
const error = ref("");

async function checkIngredients() {
  try {
    result.value = await veganify.checkIngredientsListV1(ingredients.value);
    error.value = "";
  } catch (e) {
    result.value = null;
    if (e instanceof ValidationError) {
      error.value = "Please enter valid ingredients";
    } else {
      error.value = "An error occurred while checking ingredients";
    }
  }
}
</script>

Advanced Features

Caching

The package includes a built-in caching system with configurable TTL:

const veganify = Veganify.getInstance({
  cacheTTL: 1800000, // 30 minutes, set to 0 to disable caching
});

// Clear cache if needed
veganify.clearCache();

// The next API call will fetch fresh data
const product = await veganify.getProductByBarcode("4066600204404");

Ingredient Preprocessing

The package exports a utility function that cleans and standardizes ingredient lists for analysis.

Parameters:

  • ingredientsList: Raw ingredient list string

Returns:

An array of cleaned and normalized ingredient names

import { preprocessIngredients } from "@frontendnetwork/veganify";

const cleanIngredients = preprocessIngredients(
  "water 100%, sugar (organic), salt:"
);
// Result: ['water', 'sugar', 'organic', 'salt']

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT © FrontEndNet.work, Philip Brembeck