Added zod. Wrapped picsum API.
This commit is contained in:
parent
2137fcc776
commit
ae6451e052
3 changed files with 78 additions and 11 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -12,7 +12,8 @@
|
||||||
"@emotion/styled": "^11.14.1",
|
"@emotion/styled": "^11.14.1",
|
||||||
"@mui/material": "^9.0.1",
|
"@mui/material": "^9.0.1",
|
||||||
"react": "^19.2.6",
|
"react": "^19.2.6",
|
||||||
"react-dom": "^19.2.6"
|
"react-dom": "^19.2.6",
|
||||||
|
"zod": "^4.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
|
|
@ -3472,7 +3473,6 @@
|
||||||
"version": "4.4.3",
|
"version": "4.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
|
||||||
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@
|
||||||
"@emotion/styled": "^11.14.1",
|
"@emotion/styled": "^11.14.1",
|
||||||
"@mui/material": "^9.0.1",
|
"@mui/material": "^9.0.1",
|
||||||
"react": "^19.2.6",
|
"react": "^19.2.6",
|
||||||
"react-dom": "^19.2.6"
|
"react-dom": "^19.2.6",
|
||||||
|
"zod": "^4.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
|
|
|
||||||
82
src/App.tsx
82
src/App.tsx
|
|
@ -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() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<>
|
<h1>hello world</h1>
|
||||||
<CssBaseline />
|
)
|
||||||
<main>
|
|
||||||
<Typography variant="h1">Hello world</Typography>
|
|
||||||
</main>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue