mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-04-26 14:28:25 -04:00
clean up serverless functions
This commit is contained in:
parent
4da59e5e81
commit
6ff4bc52e5
@ -29,6 +29,6 @@ The [Vercel CLI](https://vercel.com/docs/cli) is not included as a project depen
|
||||
|
||||

|
||||
|
||||
Site content (everything in [`content/notes`](content/notes/)) is published under the [**Creative Commons Attribution 4.0 International License**](LICENSE.md) (CC-BY-4.0), which means that you can copy, redistribute, remix, transform, and build upon the content for any purpose as long as you give appropriate credit.
|
||||
Site content (everything in [`content/notes`](content/notes/)) is published under the [**Creative Commons Attribution 4.0 International License**](LICENSE) (CC-BY-4.0), which means that you can copy, redistribute, remix, transform, and build upon the content for any purpose as long as you give appropriate credit.
|
||||
|
||||
All original code in this repository is published under the [**MIT License**](https://opensource.org/licenses/MIT).
|
||||
|
@ -16,22 +16,17 @@ const { AIRTABLE_API_KEY, AIRTABLE_BASE } = process.env;
|
||||
const AIRTABLE_API_ENDPOINT = "https://api.airtable.com/v0/";
|
||||
|
||||
export default async (req, res) => {
|
||||
// disable caching on both ends
|
||||
res.setHeader("Cache-Control", "private, no-cache, no-store, must-revalidate");
|
||||
res.setHeader("Expires", 0);
|
||||
res.setHeader("Pragma", "no-cache");
|
||||
|
||||
// permissive access control headers
|
||||
res.setHeader("Access-Control-Allow-Methods", "POST");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
try {
|
||||
// some rudimentary error handling
|
||||
// permissive access control headers
|
||||
res.setHeader("Access-Control-Allow-Methods", "POST");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
// disable caching on both ends
|
||||
res.setHeader("Cache-Control", "private, no-cache, no-store, must-revalidate");
|
||||
res.setHeader("Expires", 0);
|
||||
res.setHeader("Pragma", "no-cache");
|
||||
|
||||
if (req.method !== "POST") {
|
||||
throw new Error(`Method ${req.method} not allowed.`);
|
||||
}
|
||||
if (!AIRTABLE_API_KEY || !AIRTABLE_BASE) {
|
||||
throw new Error("Airtable API credentials aren't set.");
|
||||
return res.status(405).send(); // 405 Method Not Allowed
|
||||
}
|
||||
|
||||
const { body } = req;
|
||||
@ -60,7 +55,7 @@ export default async (req, res) => {
|
||||
}
|
||||
|
||||
// return in JSON format
|
||||
res.status(200).json({ success: true });
|
||||
return res.status(200).json({ success: true });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@ -73,7 +68,8 @@ export default async (req, res) => {
|
||||
await Sentry.flush(2000);
|
||||
}
|
||||
|
||||
res.status(400).json({ success: false, message: message });
|
||||
// 500 Internal Server Error
|
||||
return res.status(500).json({ success: false, message: message });
|
||||
}
|
||||
};
|
||||
|
||||
|
18
api/hits.js
18
api/hits.js
@ -15,12 +15,12 @@ const BASE_URL = "https://jarv.is/";
|
||||
|
||||
export default async (req, res) => {
|
||||
try {
|
||||
// some rudimentary error handling
|
||||
// permissive access control headers
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
if (req.method !== "GET") {
|
||||
throw new Error(`Method ${req.method} not allowed.`);
|
||||
}
|
||||
if (!process.env.FAUNADB_SERVER_SECRET) {
|
||||
throw new Error("Database credentials aren't set.");
|
||||
return res.status(405).send(); // 405 Method Not Allowed
|
||||
}
|
||||
|
||||
const client = new faunadb.Client({
|
||||
@ -52,10 +52,7 @@ export default async (req, res) => {
|
||||
res.setHeader("Pragma", "no-cache");
|
||||
}
|
||||
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
res.status(200).json(result);
|
||||
return res.status(200).json(result);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@ -65,7 +62,8 @@ export default async (req, res) => {
|
||||
|
||||
const message = error instanceof Error ? error.message : "Unknown error.";
|
||||
|
||||
res.status(400).json({ success: false, message: message });
|
||||
// 500 Internal Server Error
|
||||
return res.status(500).json({ success: false, message: message });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -8,12 +8,12 @@ Sentry.init({
|
||||
|
||||
export default async (req, res) => {
|
||||
try {
|
||||
// some rudimentary error handling
|
||||
// permissive access control headers
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
if (req.method !== "GET") {
|
||||
throw new Error(`Method ${req.method} not allowed.`);
|
||||
}
|
||||
if (!process.env.GH_PUBLIC_TOKEN) {
|
||||
throw new Error("GitHub API credentials aren't set.");
|
||||
return res.status(405).send(); // 405 Method Not Allowed
|
||||
}
|
||||
|
||||
// allow custom limit, max. 24 results
|
||||
@ -33,10 +33,8 @@ export default async (req, res) => {
|
||||
|
||||
// let Vercel edge and browser cache results for 15 mins
|
||||
res.setHeader("Cache-Control", "public, max-age=900, s-maxage=900, stale-while-revalidate");
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
res.status(200).json(result);
|
||||
return res.status(200).json(result);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@ -46,7 +44,8 @@ export default async (req, res) => {
|
||||
|
||||
const message = error instanceof Error ? error.message : "Unknown error.";
|
||||
|
||||
res.status(400).json({ success: false, message: message });
|
||||
// 500 Internal Server Error
|
||||
return res.status(500).json({ success: false, message: message });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -23,17 +23,18 @@ const TOP_TRACKS_ENDPOINT = "https://api.spotify.com/v1/me/top/tracks?time_range
|
||||
|
||||
export default async (req, res) => {
|
||||
try {
|
||||
// some rudimentary error handling
|
||||
// permissive access control headers
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
if (req.method !== "GET") {
|
||||
throw new Error(`Method ${req.method} not allowed.`);
|
||||
}
|
||||
if (!process.env.SPOTIFY_CLIENT_ID || !process.env.SPOTIFY_CLIENT_SECRET || !process.env.SPOTIFY_REFRESH_TOKEN) {
|
||||
throw new Error("Spotify API credentials aren't set.");
|
||||
return res.status(405).send(); // 405 Method Not Allowed
|
||||
}
|
||||
|
||||
// default to top tracks
|
||||
let response;
|
||||
// get currently playing track (/music/?now), otherwise top 10 tracks
|
||||
|
||||
// get currently playing track (/api/tracks/?now), otherwise top 10 tracks
|
||||
if (typeof req.query.now !== "undefined") {
|
||||
response = await getNowPlaying();
|
||||
|
||||
@ -46,10 +47,7 @@ export default async (req, res) => {
|
||||
res.setHeader("Cache-Control", "public, max-age=10800, s-maxage=10800, stale-while-revalidate");
|
||||
}
|
||||
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
res.status(200).json(response);
|
||||
return res.status(200).json(response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@ -59,7 +57,8 @@ export default async (req, res) => {
|
||||
|
||||
const message = error instanceof Error ? error.message : "Unknown error.";
|
||||
|
||||
res.status(400).json({ success: false, message: message });
|
||||
// 500 Internal Server Error
|
||||
return res.status(500).json({ success: false, message: message });
|
||||
}
|
||||
};
|
||||
|
||||
@ -100,7 +99,7 @@ const getNowPlaying = async () => {
|
||||
if (active.is_playing === true && active.item) {
|
||||
return {
|
||||
isPlaying: active.is_playing,
|
||||
artist: active.item.artists.map((_artist) => _artist.name).join(", "),
|
||||
artist: active.item.artists.map((artist) => artist.name).join(", "),
|
||||
title: active.item.name,
|
||||
album: active.item.album.name,
|
||||
imageUrl: active.item.album.images ? active.item.album.images[0].url : undefined,
|
||||
@ -126,7 +125,7 @@ const getTopTracks = async () => {
|
||||
const { items } = await response.json();
|
||||
|
||||
const tracks = items.map((track) => ({
|
||||
artist: track.artists.map((_artist) => _artist.name).join(", "),
|
||||
artist: track.artists.map((artist) => artist.name).join(", "),
|
||||
title: track.name,
|
||||
album: track.album.name,
|
||||
imageUrl: track.album.images ? track.album.images[0].url : undefined,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import "./src/dark-mode.js";
|
||||
import "./src/emoji.js";
|
||||
import "./src/counter.js";
|
||||
import "./src/hits.js";
|
||||
import "./src/clipboard.js";
|
||||
import "./src/anchor.js";
|
||||
import "./src/contact.js";
|
||||
|
@ -13,7 +13,7 @@ Okay, this is an easy one. 😉
|
||||
|
||||
A simple hit counter on each page tallies an aggregate number of pageviews (i.e. `hits = hits + 1`). Individual views and identifying (or non-identifying) details are **never stored or logged**.
|
||||
|
||||
The [serverless function](https://github.com/jakejarvis/jarv.is/blob/main/api/hits.js) and [client script](https://github.com/jakejarvis/jarv.is/blob/main/assets/js/src/counter.js) are open source, and [snapshots of the database](https://github.com/jakejarvis/website-stats) are public.
|
||||
The [serverless function](https://github.com/jakejarvis/jarv.is/blob/main/api/hits.js) and [client script](https://github.com/jakejarvis/jarv.is/blob/main/assets/js/src/hits.js) are open source, and [snapshots of the database](https://github.com/jakejarvis/website-stats) are public.
|
||||
|
||||
{{< image src="images/fauna_hits.png" alt="The entire database schema." link="/privacy/images/fauna_hits.png" />}}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user