Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/controllers/geoBreakdownController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { firestoreOld } from '../utils/db.js';
const firestore = firestoreOld;

import {
getLatestDate,
handleControllerError,
validateArrayParameter
} from '../utils/controllerHelpers.js';

const TABLE = 'core_web_vitals';
const DATA_FIELD = 'vitals';

/**
* List CWV data for all geographies for a given technology.
* Unlike /cwv, this endpoint omits the geo filter so all geographies
* are returned, allowing a geographic breakdown chart to be built.
*
* Query params:
* technology (required)
* rank (default: ALL)
* start (optional; 'latest' resolves to the most recent date)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it doesn’t make sense to support this. It should be according to a single month of data and not multiple months probably.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on your visualization example it seems that a single monthly snapshot is sufficient.
1 month of CWV data is 15Kb btw.

* end (optional)
*/
export const listGeoBreakdownData = async (req, res) => {
try {
const params = req.query;
const technologyParam = params.technology || 'ALL';
const rankParam = params.rank || 'ALL';

const techArray = validateArrayParameter(technologyParam, 'technology');

let startDate = params.start;
if (startDate === 'latest') {
startDate = await getLatestDate(firestore, TABLE);
}

let query = firestore.collection(TABLE);

// Filter by rank and technology; intentionally no geo filter
query = query.where('rank', '==', rankParam);
query = query.where('technology', 'in', techArray);

if (startDate) query = query.where('date', '>=', startDate);
if (params.end) query = query.where('date', '<=', params.end);

// Include geo in the projection so callers can group by geography
query = query.select('date', 'technology', 'geo', DATA_FIELD);

const snapshot = await query.get();
const data = [];
snapshot.forEach(doc => data.push(doc.data()));

res.statusCode = 200;
res.end(JSON.stringify(data));

} catch (error) {
handleControllerError(res, error, 'fetching geo breakdown data');
}
};
7 changes: 7 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const controllers = {
ranks: null,
geos: null,
versions: null,
geoBreakdown: null,
static: null
};

Expand Down Expand Up @@ -42,6 +43,9 @@ const getController = async (name) => {
case 'versions':
controllers[name] = await import('./controllers/versionsController.js');
break;
case 'geoBreakdown':
controllers[name] = await import('./controllers/geoBreakdownController.js');
break;
case 'static':
controllers[name] = await import('./controllers/cdnController.js');
break;
Expand Down Expand Up @@ -140,6 +144,9 @@ const handleRequest = async (req, res) => {
} else if (pathname === '/v1/versions' && req.method === 'GET') {
const { listVersions } = await getController('versions');
await listVersions(req, res);
} else if (pathname === '/v1/geo-breakdown' && req.method === 'GET') {
const { listGeoBreakdownData } = await getController('geoBreakdown');
await listGeoBreakdownData(req, res);
} else if (pathname.startsWith('/v1/static/') && req.method === 'GET') {
// GCS proxy endpoint for reports files
const filePath = decodeURIComponent(pathname.replace('/v1/static/', ''));
Expand Down