Skip to content

davidparys/pdf-generator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PDF Generator Service

A microservice built with Express and Puppeteer that generates PDFs from web URLs. This service is designed to be deployed on Railway.

What It Does

This service provides an API endpoint to convert web pages into high-quality PDF documents. It uses Puppeteer, a headless Chrome browser, to render web pages with full CSS support and then exports them as PDFs.

Key features:

  • Creates PDFs from any web URL
  • Supports print-specific CSS media queries
  • Configurable page size, margins, and scaling
  • CORS protection for secure API access

Prerequisites

  • Node.js 18+
  • npm or yarn

Installation

  1. Clone the repository:
git clone <repository-url>
cd ixion-invoice-generator/railway
  1. Install dependencies:
npm install
  1. Set up environment variables:
    • Create a .env file in the root directory (or add to existing one)
    • Add the required environment variables:
PORT=3333
ALLOWED_ORIGINS=http://localhost:3000,https://yourapp.com

Running Locally

Development Mode

To run the service in development mode with hot reloading:

npm run dev

The service will be available at http://localhost:3333 (or the port specified in your .env file).

Production Mode

To run the service in production mode:

  1. Build the TypeScript files:
npm run build
  1. Start the service:
npm start

API Endpoints

Health Check

  • URL: /
  • Method: GET
  • Response:
    { "status": "ok", "message": "This app is running correctly." }

Generate PDF

  • URL: /generate-pdf
  • Method: POST
  • Body:
    {
      "url": "https://example.com/page-to-convert",
      "printPDF": false
    }
  • Response: PDF file as a downloadable attachment
  • Parameters:
    • url (required): The URL of the web page to convert to PDF
    • printPDF (optional): If true, adds a printPDF parameter to the URL

Integration Example

Here's an example of how to integrate this service in a Nuxt 3 application using a composable function:

// composables/usePdfGenerator.ts
export const usePdfGenerator = () => {
  const isGeneratingPdf = ref(false)
  const router = useRouter()
  
  // Create toast promise for showing status
  let resolveToast: (value: unknown) => void
  let rejectToast: (reason?: any) => void
  const toastPromise = new Promise((resolve, reject) => {
    resolveToast = resolve
    rejectToast = reject
  })
  
  // Toast notification to show generation status
  toast.promise(toastPromise, {
    loading: 'Generating PDF...',
    success: () => 'PDF generated successfully!',
    error: (err: Error) => `Failed to generate PDF: ${err.message}`
  })
  
  // Generate PDF function
  const generatePdf = async (documentId: string, options = { printPDF: true }) => {
    isGeneratingPdf.value = true
    
    try {
      // Get the current page URL or a shared URL
      const pageUrl = `${useRuntimeConfig().public.appUrl}${router.currentRoute.value.path}`
      
      // Use development or production endpoint
      const apiUrl = process.env.NODE_ENV === 'development' 
        ? 'http://localhost:3333/generate-pdf' 
        : 'https://your-railway-app-url.up.railway.app/generate-pdf'
      
      // Call the PDF generator service
      const response = await $fetch(apiUrl, {
        method: 'POST',
        body: {
          url: pageUrl,
          printPDF: options.printPDF
        },
        responseType: 'blob'
      }) as Blob
      
      if (!response) {
        throw new Error('Failed to generate PDF')
      }
      
      // Create and trigger download
      const url = window.URL.createObjectURL(response)
      const link = document.createElement('a')
      link.href = url
      link.download = `document-${documentId}.pdf`
      link.click()
      window.URL.revokeObjectURL(url)
      
      resolveToast(response)
      return response
    } catch (error) {
      console.error('Error generating PDF:', error)
      rejectToast(error)
      throw error
    } finally {
      isGeneratingPdf.value = false
    }
  }
  
  return {
    generatePdf,
    isGeneratingPdf
  }
}

Usage in a Component

<script setup>
const { generatePdf, isGeneratingPdf } = usePdfGenerator()

const handleDownloadPdf = async () => {
  try {
    await generatePdf('invoice-123')
  } catch (error) {
    // Error is already handled by the composable
  }
}
</script>

<template>
  <div>
    <button 
      @click="handleDownloadPdf" 
      :disabled="isGeneratingPdf"
    >
      {{ isGeneratingPdf ? 'Generating PDF...' : 'Download PDF' }}
    </button>
  </div>
</template>

Deployment

This service is configured for easy deployment on Railway.

  1. Connect your repository to Railway
  2. Set the required environment variables in the Railway dashboard
  3. Deploy your application

Security

The service implements CORS protection that restricts access to specified origins only. Make sure to properly configure the ALLOWED_ORIGINS environment variable in production.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published