import Fastify from "fastify"; import cors from "@fastify/cors"; import sequelizePlugin from "./plugins/sequelize.js"; import dotenv from "dotenv"; import cors from "@fastify/cors"; import { executeQueryAsync, retrieveResultsAsync } from "./services/athena.js"; dotenv.config(); import * as dashboard from "./queries/dashboard.js"; import * as queries from "./queries/queries.js"; import * as dashboardQueries from "./queries/dashboard.js"; const server = Fastify({ logger: true }); await server.register(cors, { origin: "*", }); server.register(sequelizePlugin); await server.register(cors, { origin: "*", }); // await server.register(cors, { // origin: ["http://localhost:3000"], // }); server.get("/", async (request, reply) => { const [results, metadata] = await server.sequelize.query('SELECT 1 + 2 AS result'); console.log(results); console.log(metadata); return { hello: "world" }; }); server.get("/accounts", async (request, reply) => { const queryExecutionId = await executeQueryAsync(queries.accountsQuery); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/accounts/:accountId/regions", async (request, reply) => { const query = queries.regionsQuery.replace('%accountId%', request.params.accountId); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/accounts/:accountId/regions/:regionCode/products", async (request, reply) => { let regionCode = request.params.regionCode; if (!regionCode || regionCode === 'global') { regionCode = ''; } const query = queries.productsByRegionQuery .replace('%accountId%', request.params.accountId) .replace('%regionCode%', regionCode); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/accounts/:accountId/regions/:regionCode/products/:productCode", async (request, reply) => { let regionCode = request.params.regionCode; if (!regionCode || regionCode === 'global') { regionCode = ''; } const query = queries.productByRegionQuery .replace('%accountId%', request.params.accountId) .replace('%regionCode%', regionCode) .replace('%productCode%', request.params.productCode); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/accounts/:accountId/regions/:regionCode/products/:productCode/usage", async (request, reply) => { let regionCode = request.params.regionCode; if (!regionCode || regionCode === 'global') { regionCode = ''; } const query = queries.productUsageByRegionQuery .replace('%accountId%', request.params.accountId) .replace('%regionCode%', regionCode) .replace('%productCode%', request.params.productCode); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/accounts/:accountId/regions/:regionCode/products/:productCode/usage/:year", async (request, reply) => { let regionCode = request.params.regionCode; if (!regionCode || regionCode === 'global') { regionCode = ''; } const query = queries.productUsageByRegionYearQuery .replace('%accountId%', request.params.accountId) .replace('%regionCode%', regionCode) .replace('%productCode%', request.params.productCode) .replace('%year%', request.params.year); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/accounts/:accountId/regions/:regionCode/products/:productCode/usage/:year/:month", async (request, reply) => { let regionCode = request.params.regionCode; if (!regionCode || regionCode === 'global') { regionCode = ''; } const query = queries.productUsageByRegionYearMonthQuery .replace('%accountId%', request.params.accountId) .replace('%regionCode%', regionCode) .replace('%productCode%', request.params.productCode) .replace('%year%', request.params.year) .replace('%month%', request.params.month); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/products", async (request, reply) => { const query = queries.productQuery; const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/products/:productCode", async (request, reply) => { const query = queries.productByCodeQuery .replace('%productCode%', request.params.productCode); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/products/:productCode/usage", async (request, reply) => { const query = queries.productByCodeUsageQuery .replace('%productCode%', request.params.productCode); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/products/:productCode/usage/:year", async (request, reply) => { const query = queries.productByCodeUsageYearQuery .replace('%productCode%', request.params.productCode) .replace('%year%', request.params.year); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/products/:productCode/usage/:year/:month", async (request, reply) => { const query = queries.productByCodeUsageYearMonthQuery .replace('%productCode%', request.params.productCode) .replace('%year%', request.params.year) .replace('%month%', request.params.month); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/invoices", async (request, reply) => { const query = queries.invoices; const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/invoices/:invoiceId", async (request, reply) => { const query = queries.invoiceById .replace('%invoiceId%', request.params.invoiceId); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/invoices/:invoiceId/products", async (request, reply) => { const query = queries.invoiceByIdProducts .replace('%invoiceId%', request.params.invoiceId); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/invoices/:invoiceId/products/:productCode", async (request, reply) => { const query = queries.invoiceByProductCode .replace('%invoiceId%', request.params.invoiceId) .replace('%productCode%', request.params.productCode); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/invoices/:invoiceId/products/:productCode/usage", async (request, reply) => { const query = queries.invoiceByProductCodeUsage .replace('%invoiceId%', request.params.invoiceId) .replace('%productCode%', request.params.productCode); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/invoices/:invoiceId/accounts", async (request, reply) => { const query = queries.invoiceByIdAccounts .replace('%invoiceId%', request.params.invoiceId); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/invoices/:invoiceId/accounts/:accountId", async (request, reply) => { const query = queries.invoiceByIdAccount .replace('%invoiceId%', request.params.invoiceId) .replace('%accountId%', request.params.accountId); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/invoices/:invoiceId/accounts/:accountId/products/:productCode", async (request, reply) => { const query = queries.invoiceByIdAccountProducts .replace('%invoiceId%', request.params.invoiceId) .replace('%accountId%', request.params.accountId) .replace('%productCode%', request.params.productCode); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/invoices/:invoiceId/accounts/:accountId/products/:productCode/usage", async (request, reply) => { const query = queries.invoiceByIdAccountProductsUsage .replace('%invoiceId%', request.params.invoiceId) .replace('%accountId%', request.params.accountId) .replace('%productCode%', request.params.productCode); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/accounts/:accountId/regions/:regionCode/products/:productCode/resources/:resourceId/usage", async (request, reply) => { let regionCode = request.params.regionCode; if (!regionCode || regionCode === 'global') { regionCode = 'global'; } const query = dashboard.productResourceUsageQuery .replace('%accountId%', request.params.accountId) .replace('%regionCode%', regionCode) .replace('%productCode%', request.params.productCode) .replace('%resourceId%', request.params.resourceId); try { const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results ?? []; } catch (err) { request.log.error(err); return reply.status(500).send({ error: 'Failed to fetch resource usage', details: err.message, }); } }); server.get("/products/usage", async (request, reply) => { const query = dashboard.allProductUsageQuery; const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/accounts/cost-usage-summary", async (request, reply) => { const query = dashboard.accountCostUsageSummaryQuery; const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/dashboard/summary", async (request, reply) => { const [currentQueryId, previousQueryId] = await Promise.all([ executeQueryAsync(dashboardQueries.currentMonthSummary), executeQueryAsync(dashboardQueries.previousMonthSummary) ]); const [currentResults, previousResults] = await Promise.all([ retrieveResultsAsync(currentQueryId), retrieveResultsAsync(previousQueryId) ]); return { current: currentResults[0] || {}, previous: previousResults[0] || {} }; }); server.get("/dashboard/services", async (request, reply) => { const queryExecutionId = await executeQueryAsync(dashboardQueries.serviceBreakdown); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/dashboard/trends", async (request, reply) => { const queryExecutionId = await executeQueryAsync(dashboardQueries.dailyTrends); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/dashboard/accounts", async (request, reply) => { const queryExecutionId = await executeQueryAsync(dashboardQueries.topAccounts); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/dashboard/today", async (request, reply) => { const queryExecutionId = await executeQueryAsync(dashboardQueries.todaySpending); const results = await retrieveResultsAsync(queryExecutionId); return results[0] || {}; }); server.get("/dashboard/weekly", async (request, reply) => { const queryExecutionId = await executeQueryAsync(dashboardQueries.weeklyComparison); const results = await retrieveResultsAsync(queryExecutionId); return results; }); server.get("/dashboard/services/:serviceCode/accounts", async (request, reply) => { const { days = 30 } = request.query; const query = dashboardQueries.serviceAccountBreakdown .replace('%serviceCode%', request.params.serviceCode) .replace('%days%', days); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return { serviceCode: request.params.serviceCode, accounts: results, totalCost: results.reduce((sum, account) => sum + parseFloat(account.totalCost || 0), 0).toFixed(2) }; }); server.get("/dashboard/services/:serviceCode/trends", async (request, reply) => { const { days = 30 } = request.query; const query = dashboardQueries.serviceTrends .replace('%serviceCode%', request.params.serviceCode) .replace('%days%', days); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return { serviceCode: request.params.serviceCode, trends: results, totalCost: results.reduce((sum, day) => sum + parseFloat(day.dailyCost || 0), 0).toFixed(2) }; }); // Account drill-down routes server.get("/dashboard/accounts/:accountId/services", async (request, reply) => { const { days = 30 } = request.query; const query = dashboardQueries.accountServiceBreakdown .replace('%accountId%', request.params.accountId) .replace('%days%', days); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return { accountId: request.params.accountId, services: results, totalCost: results.reduce((sum, service) => sum + parseFloat(service.totalCost || 0), 0).toFixed(2) }; }); server.get("/dashboard/accounts/:accountId/trends", async (request, reply) => { const { days = 30 } = request.query; const query = dashboardQueries.accountTrends .replace('%accountId%', request.params.accountId) .replace('%days%', days); const queryExecutionId = await executeQueryAsync(query); const results = await retrieveResultsAsync(queryExecutionId); return { accountId: request.params.accountId, trends: results, totalCost: results.reduce((sum, day) => sum + parseFloat(day.dailyCost || 0), 0).toFixed(2) }; }); try { await server.listen({ port: 3000 }) } catch (err) { server.log.error(err); process.exit(1); }