Skip to content

Commit 0afbc84

Browse files
committed
first commit
0 parents  commit 0afbc84

14 files changed

Lines changed: 3649 additions & 0 deletions

File tree

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules
2+
dist
3+
.data
4+
.nitro
5+
.cache
6+
.output
7+
.env
8+
.env.local

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Nitro starter
2+
3+
Look at the [nitro quick start](https://nitro.build/guide#quick-start) to learn more how to get started.
4+
# nitro-models-validation-and-transformation-Public

cat/cat.repository.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { CatRemote } from "./models/cat.remote";
2+
3+
export class CatsRepository {
4+
private cats: CatRemote[];
5+
6+
constructor() {
7+
this.cats = [
8+
{
9+
id: 1,
10+
name: "Whiskers",
11+
age: 18,
12+
breed: "Siamese",
13+
},
14+
{
15+
id: 2,
16+
name: "Fluffy",
17+
age: 6,
18+
breed: "Persian",
19+
},
20+
{
21+
id: 3,
22+
name: "Mittens",
23+
age: 1,
24+
breed: "Maine Coon",
25+
},
26+
{
27+
id: 4,
28+
name: "Tigger",
29+
age: 19,
30+
breed: "Ragdoll",
31+
},
32+
];
33+
}
34+
35+
async getById(id: number) {
36+
const cat = this.cats.find((cat) => cat.id === id);
37+
if (!cat) throw new Error("Cat not found");
38+
return CatRemote.create(cat);
39+
}
40+
}

cat/controllers/cat.controller.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { CatsRepository } from "../cat.repository";
2+
import { CatService } from "../services/cat.service";
3+
4+
export class CatController {
5+
private catService: CatService;
6+
7+
constructor() {
8+
this.catService = new CatService(new CatsRepository());
9+
}
10+
11+
async getById(id: number) {
12+
return this.catService.getCat(id);
13+
}
14+
}

cat/models/cat.local.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import z from "zod";
2+
3+
// The local model for the Cat entity used internally.
4+
// You could argue whether this model is needed at all, since it replicates the remote model.
5+
export class CatLocal {
6+
public static readonly schema = z.object({
7+
id: z.number(),
8+
name: z.string(),
9+
age: z.number(),
10+
breed: z.string(),
11+
});
12+
13+
constructor(
14+
public id: number,
15+
public name: string,
16+
public age: number,
17+
public breed: string,
18+
) {}
19+
20+
public static create<TData>(data: TData) {
21+
const { id, name, age, breed } = this.schema.parse(data);
22+
return new this(id, name, age, breed);
23+
}
24+
}

cat/models/cat.remote.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import z from "zod";
2+
3+
// The remote model for the Cat returned by the remote source.
4+
export class CatRemote {
5+
public static readonly schema = z.object({
6+
id: z.number(),
7+
name: z.string(),
8+
age: z.number(),
9+
breed: z.string(),
10+
});
11+
12+
constructor(
13+
public id: number,
14+
public name: string,
15+
public age: number,
16+
public breed: string,
17+
) {}
18+
19+
public static create<TData>(data: TData) {
20+
const { id, name, age, breed } = this.schema.parse(data);
21+
return new this(id, name, age, breed);
22+
}
23+
}

cat/models/cat.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import z from "zod";
2+
3+
type AgeCategory = "Kitten" | "Adult" | "Senior";
4+
5+
// The Cat is the representation of a Cat to send to client.
6+
export class Cat {
7+
public static readonly schema = z.object({
8+
name: z.string(),
9+
age: z.number(),
10+
breed: z.string(),
11+
});
12+
13+
constructor(
14+
public name: string,
15+
public ageCategory: AgeCategory,
16+
public breed: string,
17+
) {}
18+
19+
private static getageCategory(age: number): AgeCategory {
20+
if (age < 1) return "Kitten";
21+
if (age < 7) return "Adult";
22+
return "Senior";
23+
}
24+
25+
// The client is not interested in the age but in the age category.
26+
// The client is also not interested in the id of the cat -
27+
// that is why the is is not part of the constructor.
28+
// Also neither the id nor the age is returned in the `transform` function.
29+
public static create<TData>(data: TData) {
30+
const { name, ageCategory, breed } = this.schema
31+
.transform(({ name, age, breed }) => {
32+
return { name, ageCategory: this.getageCategory(age), breed };
33+
})
34+
.parse(data);
35+
return new this(name, ageCategory, breed);
36+
}
37+
}

cat/services/cat.service.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { CatLocal } from "cat/models/cat.local";
2+
import { CatsRepository } from "../cat.repository";
3+
import { Cat } from "cat/models/cat";
4+
5+
export class CatService {
6+
constructor(private repository: CatsRepository) {}
7+
8+
async getLocalCat(id: number) {
9+
const remoteCat = await this.repository.getById(id);
10+
if (!remoteCat) throw new Error("Cat not found");
11+
return CatLocal.create(remoteCat);
12+
}
13+
14+
async getCat(id: number) {
15+
const localCat = await this.getLocalCat(id);
16+
return Cat.create(localCat);
17+
}
18+
}

nitro.config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { defineNitroConfig } from "nitropack/config";
2+
import { fileURLToPath } from "url";
3+
import { resolve, dirname } from "path";
4+
5+
const __dirname = dirname(fileURLToPath(import.meta.url));
6+
7+
// https://nitro.build/config
8+
export default defineNitroConfig({
9+
compatibilityDate: "latest",
10+
srcDir: "server",
11+
imports: false,
12+
alias: {
13+
cat: resolve(__dirname, "cat"),
14+
},
15+
});

package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "nitro-app",
3+
"private": true,
4+
"scripts": {
5+
"build": "nitro build",
6+
"dev": "nitro dev",
7+
"preview": "node .output/server/index.mjs"
8+
},
9+
"devDependencies": {
10+
"@types/node": "^25.2.3",
11+
"h3": "^1.15.4",
12+
"nitropack": "^2.12.4"
13+
},
14+
"dependencies": {
15+
"zod": "^4.3.6"
16+
}
17+
}

0 commit comments

Comments
 (0)