Integração completa para geração de PDFs em Golang
go mod init myapp
go mod tidy
Copie o código da seção abaixo
client := cloud2pdf.NewClient("seu_token_aqui")
result, err := client.GenerateAsync("<h1>Hello!</h1>", "ref-123")
Crie cloud2pdf/client.go
package cloud2pdf
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
const defaultAPIURL = "https://api.cloud2pdf.com/v1"
type Client struct {
APIUrl string
APIToken string
HTTPClient *http.Client
}
type GenerateAsyncRequest struct {
HTML string `json:"html"`
IsDisk bool `json:"is_disk"`
Reference string `json:"reference,omitempty"`
Options map[string]interface{} `json:"options"`
}
type GenerateAsyncResponse struct {
PdfID int `json:"pdf_id"`
JobID string `json:"job_id"`
Status string `json:"status"`
Reference string `json:"reference"`
}
type StatusResponse struct {
Status string `json:"status"`
PdfID int `json:"pdf_id"`
PublicLink map[string]interface{} `json:"public_link,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Error string `json:"error,omitempty"`
}
func NewClient(apiToken string) *Client {
return &Client{
APIUrl: defaultAPIURL,
APIToken: apiToken,
HTTPClient: &http.Client{
Timeout: 30 * time.Second,
},
}
}
func (c *Client) GenerateAsync(html, reference string, options ...map[string]interface{}) (*GenerateAsyncResponse, error) {
opts := map[string]interface{}{
"format": "A4",
"landscape": false,
}
if len(options) > 0 {
for k, v := range options[0] {
opts[k] = v
}
}
req := GenerateAsyncRequest{
HTML: html,
IsDisk: true,
Reference: reference,
Options: opts,
}
body, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
httpReq, err := http.NewRequest("POST", c.APIUrl+"/pdf/generate-async", bytes.NewBuffer(body))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
httpReq.Header.Set("Authorization", "Bearer "+c.APIToken)
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Accept", "application/json")
resp, err := c.HTTPClient.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusAccepted {
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
var result GenerateAsyncResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
return &result, nil
}
func (c *Client) CheckStatus(pdfID int) (*StatusResponse, error) {
url := fmt.Sprintf("%s/pdf/status/%d", c.APIUrl, pdfID)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.APIToken)
req.Header.Set("Accept", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
var result StatusResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
return &result, nil
}
func (c *Client) WaitForCompletion(pdfID int, maxAttempts int, delay time.Duration) (*StatusResponse, error) {
for i := 0; i < maxAttempts; i++ {
status, err := c.CheckStatus(pdfID)
if err != nil {
return nil, err
}
if status.Status == "completed" {
return status, nil
}
if status.Status == "failed" {
return nil, fmt.Errorf("PDF generation failed: %s", status.Error)
}
time.Sleep(delay)
}
return nil, fmt.Errorf("PDF generation timeout")
}
func (c *Client) Download(pdfID int) ([]byte, error) {
url := fmt.Sprintf("%s/pdf/download/%d", c.APIUrl, pdfID)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.APIToken)
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
return io.ReadAll(resp.Body)
}
func (c *Client) DownloadAndSave(pdfID int, filename string) error {
content, err := c.Download(pdfID)
if err != nil {
return err
}
return os.WriteFile(filename, content, 0644)
}
package main
import (
"fmt"
"log"
"time"
"myapp/cloud2pdf"
)
func main() {
// Criar cliente
client := cloud2pdf.NewClient("seu_token_aqui")
// HTML para converter
html := `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
h1 { color: #004aad; }
</style>
</head>
<body>
<h1>Invoice #12345</h1>
<p>Customer: John Doe</p>
<p>Amount: $1,234.56</p>
</body>
</html>
`
// Gerar PDF assíncrono
fmt.Println("Generating PDF...")
result, err := client.GenerateAsync(html, "invoice-12345", map[string]interface{}{
"format": "A4",
"landscape": false,
"margins": map[string]string{
"top": "20mm",
"right": "15mm",
"bottom": "20mm",
"left": "15mm",
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("PDF ID: %d, Status: %s\n", result.PdfID, result.Status)
// Aguardar conclusão
fmt.Println("Waiting for completion...")
completed, err := client.WaitForCompletion(result.PdfID, 60, 5*time.Second)
if err != nil {
log.Fatal(err)
}
fmt.Printf("PDF Ready! Status: %s\n", completed.Status)
if publicLink, ok := completed.PublicLink["url"].(string); ok {
fmt.Printf("Public URL: %s\n", publicLink)
}
// Download do PDF
fmt.Println("Downloading PDF...")
err = client.DownloadAndSave(result.PdfID, "invoice-12345.pdf")
if err != nil {
log.Fatal(err)
}
fmt.Println("PDF saved successfully!")
}
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"time"
"myapp/cloud2pdf"
)
var pdfClient *cloud2pdf.Client
func init() {
pdfClient = cloud2pdf.NewClient("seu_token_aqui")
}
type GenerateRequest struct {
InvoiceID int `json:"invoice_id"`
HTML string `json:"html"`
}
type GenerateResponse struct {
PdfID int `json:"pdf_id"`
Status string `json:"status"`
StatusURL string `json:"status_url"`
}
func generatePDFHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var req GenerateRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request", http.StatusBadRequest)
return
}
// Gerar PDF assíncrono
result, err := pdfClient.GenerateAsync(
req.HTML,
fmt.Sprintf("invoice-%d", req.InvoiceID),
)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Salvar PDF ID no banco (exemplo)
// db.SavePdfID(req.InvoiceID, result.PdfID)
// Retornar resposta
response := GenerateResponse{
PdfID: result.PdfID,
Status: result.Status,
StatusURL: fmt.Sprintf("/pdf/status/%d", result.PdfID),
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
func checkStatusHandler(w http.ResponseWriter, r *http.Request) {
// Extrair PDF ID da URL
var pdfID int
fmt.Sscanf(r.URL.Path, "/pdf/status/%d", &pdfID)
status, err := pdfClient.CheckStatus(pdfID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(status)
}
func downloadPDFHandler(w http.ResponseWriter, r *http.Request) {
var pdfID int
fmt.Sscanf(r.URL.Path, "/pdf/download/%d", &pdfID)
content, err := pdfClient.Download(pdfID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/pdf")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=document-%d.pdf", pdfID))
w.Write(content)
}
func main() {
http.HandleFunc("/pdf/generate", generatePDFHandler)
http.HandleFunc("/pdf/status/", checkStatusHandler)
http.HandleFunc("/pdf/download/", downloadPDFHandler)
log.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
package main
import (
"fmt"
"log"
"sync"
"time"
"myapp/cloud2pdf"
)
type PDFJob struct {
ID int
HTML string
Reference string
}
func processPDFJob(client *cloud2pdf.Client, job PDFJob, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Processing job %d...\n", job.ID)
// Gerar PDF
result, err := client.GenerateAsync(job.HTML, job.Reference)
if err != nil {
log.Printf("Job %d failed: %v\n", job.ID, err)
return
}
// Aguardar conclusão
completed, err := client.WaitForCompletion(result.PdfID, 60, 5*time.Second)
if err != nil {
log.Printf("Job %d timeout: %v\n", job.ID, err)
return
}
fmt.Printf("Job %d completed! PDF ID: %d\n", job.ID, result.PdfID)
// Salvar no banco ou processar
// db.UpdatePDFStatus(job.ID, completed)
}
func main() {
client := cloud2pdf.NewClient("seu_token_aqui")
// Lista de jobs
jobs := []PDFJob{
{ID: 1, HTML: "<h1>Invoice 1</h1>", Reference: "inv-1"},
{ID: 2, HTML: "<h1>Invoice 2</h1>", Reference: "inv-2"},
{ID: 3, HTML: "<h1>Invoice 3</h1>", Reference: "inv-3"},
}
var wg sync.WaitGroup
// Processar jobs em paralelo
for _, job := range jobs {
wg.Add(1)
go processPDFJob(client, job, &wg)
}
// Aguardar todos os jobs
wg.Wait()
fmt.Println("All jobs completed!")
}
Processe múltiplos PDFs simultaneamente
Use context.Context para controle de timeouts
Sempre verifique erros retornados
Use worker pools para controlar concorrência