Add public /api
This commit is contained in:
parent
2c7ad19b44
commit
bc7c4a35c8
@ -62,3 +62,4 @@ Installation
|
||||
|
||||
1. Set `NEXT_PUBLIC_HIDE_REPO_LINK = 1` to remove footer link to repo
|
||||
2. Set `NEXT_PUBLIC_PRO_MODE = 1` to enable higher quality image storage
|
||||
3. Set `NEXT_PUBLIC_PUBLIC_API = 1` to enable a public API available at `/api`
|
||||
|
||||
24
src/app/api/route.ts
Normal file
24
src/app/api/route.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { getPhotosCached } from '@/cache';
|
||||
import { parsePhotoForApi } from '@/photo';
|
||||
import {
|
||||
BASE_URL,
|
||||
PUBLIC_API_ENABLED,
|
||||
SITE_TITLE,
|
||||
} from '@/site/config';
|
||||
|
||||
const API_PHOTO_LIMIT = 20;
|
||||
|
||||
export async function GET() {
|
||||
if (PUBLIC_API_ENABLED) {
|
||||
const photos = await getPhotosCached({ limit: API_PHOTO_LIMIT });
|
||||
return Response.json({
|
||||
meta: {
|
||||
title: SITE_TITLE,
|
||||
url: BASE_URL,
|
||||
},
|
||||
photos: photos.map(parsePhotoForApi),
|
||||
});
|
||||
} else {
|
||||
return Response.json({ message: 'API is disabled' });
|
||||
}
|
||||
}
|
||||
@ -18,7 +18,7 @@ import {
|
||||
revalidateBlobKey,
|
||||
revalidatePhotosKey,
|
||||
} from '@/cache';
|
||||
import { IS_PRO_MODE } from '@/site/config';
|
||||
import { PRO_MODE_ENABLED } from '@/site/config';
|
||||
import { getNextImageUrlForRequest } from '@/utility/image';
|
||||
import { PATH_ADMIN_PHOTOS, PATH_ADMIN_TAGS } from '@/site/paths';
|
||||
|
||||
@ -31,10 +31,10 @@ export async function createPhotoAction(formData: FormData) {
|
||||
const updatedUrl = await convertUploadToPhoto(
|
||||
photo.url,
|
||||
photo.id,
|
||||
!IS_PRO_MODE
|
||||
!PRO_MODE_ENABLED
|
||||
? getNextImageUrlForRequest(photo.url, 3840, 90, requestOrigin)
|
||||
: undefined,
|
||||
!IS_PRO_MODE ? 'webp' : undefined,
|
||||
!PRO_MODE_ENABLED ? 'webp' : undefined,
|
||||
);
|
||||
|
||||
if (updatedUrl) { photo.url = updatedUrl; }
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import { ABSOLUTE_PATH_FOR_HOME_IMAGE } from '@/site/paths';
|
||||
import {
|
||||
ABSOLUTE_PATH_FOR_HOME_IMAGE,
|
||||
absolutePathForPhoto,
|
||||
} from '@/site/paths';
|
||||
import { formatDateFromPostgresString } from '@/utility/date';
|
||||
import {
|
||||
formatAperture,
|
||||
@ -7,6 +10,7 @@ import {
|
||||
formatExposureTime,
|
||||
formatFocalLength,
|
||||
} from '@/utility/exif';
|
||||
import { getNextImageUrlForRequest } from '@/utility/image';
|
||||
import camelcaseKeys from 'camelcase-keys';
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
@ -86,6 +90,21 @@ export const parsePhotoFromDb = (photoDbRaw: PhotoDb): Photo => {
|
||||
};
|
||||
};
|
||||
|
||||
export const parsePhotoForApi = (photo: Photo) => ({
|
||||
id: photo.id,
|
||||
title: photo.title,
|
||||
url: absolutePathForPhoto(photo),
|
||||
...photo.make && { make: photo.make },
|
||||
...photo.model && { model: photo.model },
|
||||
...photo.tags.length > 0 && { tags: photo.tags },
|
||||
takenAtNaive: formatDateFromPostgresString(photo.takenAtNaive),
|
||||
src: {
|
||||
small: getNextImageUrlForRequest(photo.url, 200),
|
||||
medium: getNextImageUrlForRequest(photo.url, 640),
|
||||
large: getNextImageUrlForRequest(photo.url, 1200),
|
||||
},
|
||||
});
|
||||
|
||||
export const parseCachedPhotoDates = (photo: Photo) => ({
|
||||
...photo,
|
||||
takenAt: new Date(photo.takenAt),
|
||||
|
||||
@ -26,7 +26,8 @@ export default function SiteChecklistClient({
|
||||
hasTitle,
|
||||
hasDomain,
|
||||
showRepoLink,
|
||||
isProMode,
|
||||
isProModeEnabled,
|
||||
isPublicApiEnabled,
|
||||
showRefreshButton,
|
||||
secret,
|
||||
}: {
|
||||
@ -37,7 +38,8 @@ export default function SiteChecklistClient({
|
||||
hasTitle: boolean
|
||||
hasDomain: boolean
|
||||
showRepoLink: boolean
|
||||
isProMode: boolean
|
||||
isProModeEnabled: boolean
|
||||
isPublicApiEnabled: boolean
|
||||
showRefreshButton?: boolean
|
||||
secret: string
|
||||
}) {
|
||||
@ -219,7 +221,7 @@ export default function SiteChecklistClient({
|
||||
</ChecklistRow>
|
||||
<ChecklistRow
|
||||
title="Pro Mode"
|
||||
status={isProMode}
|
||||
status={isProModeEnabled}
|
||||
isPending={isPendingPage}
|
||||
optional
|
||||
>
|
||||
@ -227,6 +229,16 @@ export default function SiteChecklistClient({
|
||||
higher quality image storage:
|
||||
{renderEnvVars(['NEXT_PUBLIC_PRO_MODE'])}
|
||||
</ChecklistRow>
|
||||
<ChecklistRow
|
||||
title="Public API"
|
||||
status={isPublicApiEnabled}
|
||||
isPending={isPendingPage}
|
||||
optional
|
||||
>
|
||||
Set environment variable to {'"1"'} to enable
|
||||
a public API available at <code>/api</code>:
|
||||
{renderEnvVars(['NEXT_PUBLIC_PUBLIC_API'])}
|
||||
</ChecklistRow>
|
||||
</Checklist>
|
||||
{showRefreshButton &&
|
||||
<div className="py-4 space-y-4">
|
||||
|
||||
@ -25,7 +25,8 @@ export const BASE_URL = process.env.NODE_ENV === 'production'
|
||||
: 'http://localhost:3000';
|
||||
|
||||
export const SHOW_REPO_LINK = process.env.NEXT_PUBLIC_HIDE_REPO_LINK !== '1';
|
||||
export const IS_PRO_MODE = process.env.NEXT_PUBLIC_PRO_MODE === '1';
|
||||
export const PRO_MODE_ENABLED = process.env.NEXT_PUBLIC_PRO_MODE === '1';
|
||||
export const PUBLIC_API_ENABLED = process.env.NEXT_PUBLIC_PUBLIC_API === '1';
|
||||
|
||||
export const CONFIG_CHECKLIST_STATUS = {
|
||||
hasPostgres: (process.env.POSTGRES_HOST ?? '').length > 0,
|
||||
@ -38,7 +39,8 @@ export const CONFIG_CHECKLIST_STATUS = {
|
||||
hasTitle: (process.env.NEXT_PUBLIC_SITE_TITLE ?? '').length > 0,
|
||||
hasDomain: (process.env.NEXT_PUBLIC_SITE_DOMAIN ?? '').length > 0,
|
||||
showRepoLink: SHOW_REPO_LINK,
|
||||
isProMode: IS_PRO_MODE,
|
||||
isProModeEnabled: PRO_MODE_ENABLED,
|
||||
isPublicApiEnabled: PUBLIC_API_ENABLED,
|
||||
};
|
||||
|
||||
export const IS_CHECKLIST_COMPLETE =
|
||||
|
||||
Loading…
Reference in New Issue
Block a user