Lybron / health-auto-export

This repository provides documentation for the API Export feature of Health Auto Export.
https://healthyapps.dev
112 stars 5 forks source link

[Feature Request] - JSON export as array #19

Open ImLunaHey opened 7 months ago

ImLunaHey commented 7 months ago

I'm trying to send data directly to axiom via their ingest endpoint. This doesnt work since it's expecting an array of objects instead of an object with fields.

An example of how axiom ingests data.

[
  {
    "_time":"2021-02-04T03:11:23.222Z",
    "data":{"key1":"value1","key2":"value2"}
  },
  {
    "data":{"key3":"value3"},
    "attributes":{"key4":"value4"}
  },
  {
    "tags": {
      "server": "aws",
      "source": "wordpress"
    }
  }
]
ImLunaHey commented 7 months ago

Here is the script im currently using to remap the fields for axiom.

const port = Number(process.env.PORT ?? '3000');

type Data = {
  data: {
    metrics: (
      | {
          name: string;
          units: string;
          data: {
            source: string;
            date: string;
            qty: number;
          }[];
        }
      | {
          data: {
            source: string;
            qty: number;
            endDate: string;
            startDate: string;
            value: string;
          }[];
          units: string;
          name: string;
        }
    )[];
  };
};

const splitArrayIntoChunks = <T>(array: T[], chunkSize: number): T[][] => {
  const chunks = [];
  for (let i = 0; i < array.length; i += chunkSize) {
    chunks.push(array.slice(i, i + chunkSize));
  }
  return chunks;
};

const server = Bun.serve({
  port,
  async fetch(request) {
    const url = new URL(request.url).pathname.slice(1);
    const body = await request.json<Data>();

    const data = body.data.metrics.flatMap((metric) =>
      // @ts-expect-error TODO: fix this
      metric.data.map((d) => ({ ...d, name: metric.name, units: metric.units, _time: d.date ?? d.endDate ?? d.startDate })),
    );

    const chunks = splitArrayIntoChunks(data, 500);
    const responses = [];

    for (const chunk of chunks) {
      const response = await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': request.headers.get('Content-Type') ?? '',
          authorization: request.headers.get('authorization') ?? '',
        },
        body: JSON.stringify(chunk),
      });

      responses.push(await response.text());
    }

    return new Response(responses.join('\n'));
  },
});

console.info(`Listening on http://localhost:${server.port}`);
Lybron commented 7 months ago

Thanks for the this @ImLunaHey!

I'll get back to you when I have an implementation to test, or if I need more info.