Added zod. Wrapped picsum API.

This commit is contained in:
Yura Dupyn 2026-05-14 19:05:18 +02:00
parent 2137fcc776
commit ae6451e052
3 changed files with 78 additions and 11 deletions

View file

@ -1,12 +1,78 @@
import { CssBaseline, Typography } from '@mui/material';
import { z } from 'zod'
// TODO: Use Material UI later.
// TODO: Improve error-handling. Introduce some proper server response.
type ImageId = string
type ImageRef = string
type Image = {
id: ImageId,
dimension: Dimension,
source: ImageRef,
}
type Dimension = {
width: number,
height: number,
}
// WARNING: page starts at 1
type Pagination = {
page: number,
limit: number, // page size
}
const Pagination = {
init(): Pagination { return { page: 1, limit: 10 } },
}
// === api ===
const picsumApiImageSchema = z.object({
id: z.string(),
author: z.string(),
width: z.number(),
height: z.number(),
url: z.string(),
download_url: z.string(), // WARNING: the api-endpoint returns "url" and "download_url". You definitely want "download_url" for image sources.
})
type PicsumApiImage = z.infer<typeof picsumApiImageSchema>
async function getPicsumImages({ page, limit }: Pagination): Promise<PicsumApiImage[]> {
const response = await fetch(`https://picsum.photos/v2/list?limit=${limit}&page=${page}`)
if (!response.ok) {
throw new Error(`Failed to fetch images: ${response.status}`)
}
const json: unknown = await response.json()
const data = z.array(picsumApiImageSchema).parse(json)
return data
}
async function getImages(pagination: Pagination): Promise<Image[]> {
const data = await getPicsumImages(pagination)
return data.map(({ id, download_url, width, height }) => ({ id: id as ImageId, dimension: { width, height }, source: download_url as ImageRef }))
}
async function getImageIds(pagination: Pagination): Promise<ImageId[]> {
const data = await getPicsumImages(pagination)
return data.map(({ id }) => id)
}
// Use this for `<img src=... />`
function getImageSource(id: ImageId, dimension: Dimension): ImageRef {
return `https://picsum.photos/id/${id}/${dimension.width}/${dimension.height}`;
}
// test
// (async () => {
// const imgs = await getImages({ page: 2, limit: 10 })
// console.log(imgs)
// })()
export default function App() {
return (
<>
<CssBaseline />
<main>
<Typography variant="h1">Hello world</Typography>
</main>
</>
);
<h1>hello world</h1>
)
}