efaturaefatura
Beta

Beta documentation. APIs may change before the stable release.

Vue Example

This Vue example calls the Fastify adapter from a single page application. It uses browser credentials so the server can authorize the request through the application session.

The createInvoice helper is shown in Fastify Invoice Payload.

<script setup lang="ts">
import { computed, ref } from 'vue';
import { createInvoice } from './invoice';

const apiBaseUrl = import.meta.env.VITE_EFATURA_API_URL ?? 'http://localhost:3000/efatura';
const invoice = computed(() => createInvoice());
const xml = ref('');
const error = ref<string | null>(null);

async function buildXml(): Promise<void> {
  error.value = null;

  try {
    const result = await postJson<{ xml: string }>('/dfe/xml', {
      invoice: invoice.value,
      options: { documentNumber: 1 },
    });

    xml.value = result.xml;
  } catch (requestError) {
    error.value = requestError instanceof Error ? requestError.message : 'Request failed.';
  }
}

async function openDfa(): Promise<void> {
  error.value = null;

  try {
    const currentXml =
      xml.value ||
      (
        await postJson<{ xml: string }>('/dfe/xml', {
          invoice: invoice.value,
          options: { documentNumber: 1 },
        })
      ).xml;
    const iud = requireIud(currentXml);
    const pdf = await postBinary('/dfa', {
      iud,
      invoice: invoice.value,
    });

    window.open(URL.createObjectURL(pdf), '_blank', 'noopener,noreferrer');
  } catch (requestError) {
    error.value = requestError instanceof Error ? requestError.message : 'Request failed.';
  }
}

async function postJson<T>(path: string, body: unknown): Promise<T> {
  const response = await fetch(`${apiBaseUrl}${path}`, {
    method: 'POST',
    credentials: 'include',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    throw new Error(await response.text());
  }

  return response.json() as Promise<T>;
}

async function postBinary(path: string, body: unknown): Promise<Blob> {
  const response = await fetch(`${apiBaseUrl}${path}`, {
    method: 'POST',
    credentials: 'include',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    throw new Error(await response.text());
  }

  return response.blob();
}

function requireIud(xmlContent: string): string {
  const iud = xmlContent.match(/<Dfe[^>]+Id="([^"]+)"/)?.[1];

  if (!iud) {
    throw new Error('Generated XML did not include a DFE Id.');
  }

  return iud;
}
</script>

<template>
  <main>
    <button type="button" @click="buildXml">Build XML</button>
    <button type="button" @click="openDfa">Open DFA PDF</button>
    <p v-if="error" role="alert">{{ error }}</p>
    <pre>{{ xml }}</pre>
  </main>
</template>