Moved split openApi into multiple files and moved them to a separate directory
This commit is contained in:
parent
c7d358a352
commit
c122deb132
6 changed files with 198 additions and 148 deletions
|
|
@ -1,147 +0,0 @@
|
|||
import { RedocModule, RedocOptions } from "@juicyllama/nestjs-redoc";
|
||||
import { INestApplication } from "@nestjs/common";
|
||||
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
|
||||
import { skills } from "@/skills/skills";
|
||||
import { experiences } from "@/experiences/experiences";
|
||||
import { ExperienceType } from "@/experiences/experiences.types";
|
||||
|
||||
const apiDocument = (
|
||||
options: {
|
||||
title: string;
|
||||
description: string;
|
||||
version: `${number}.${number}.${number}${string}` | `${number}.${number}${string}` | `${number}${string}`;
|
||||
contact: {
|
||||
name: string;
|
||||
email: string;
|
||||
};
|
||||
},
|
||||
redocOptions: RedocOptions
|
||||
) => {
|
||||
redocOptions.title = options.title;
|
||||
|
||||
return new DocumentBuilder()
|
||||
.setTitle(options.title)
|
||||
.setDescription(options.description)
|
||||
.setVersion(options.version)
|
||||
.setContact(options.contact.name, null, options.contact.email)
|
||||
.addServer("http://localhost:3000/");
|
||||
};
|
||||
|
||||
const addIntro = (document: DocumentBuilder, redocOptions: RedocOptions): DocumentBuilder => {
|
||||
const intro = [
|
||||
"I'm a software lead with 5+ years of experience in cloud-native development and Agile/Scrum methodologies. I'm passionate about building and leading high-performing teams to deliver scalable and reliable cloud-based applications. I have a proven track record of success in using Node.js, TypeScript, JavaScript, Docker, Kubernetes, AWS, DevOps, Git, microservices, and HAProxy to create and deploy innovative solutions.",
|
||||
"I'm also a strong communicator and collaborator, and I'm always looking for ways to improve my skills and knowledge. I'm excited about the future of cloud computing, and I'm eager to use my skills and experience to help others achieve their goals.",
|
||||
];
|
||||
|
||||
const introTagGroup = redocOptions.tagGroups.find((tagGroup) => tagGroup.name === "Intro");
|
||||
if (!introTagGroup) {
|
||||
redocOptions.tagGroups.push({
|
||||
name: "Intro",
|
||||
tags: ["Intro"],
|
||||
});
|
||||
} else {
|
||||
introTagGroup.tags.push("Intro");
|
||||
}
|
||||
|
||||
return document.addTag("Intro", intro.join("<br/>"));
|
||||
};
|
||||
|
||||
const addSkills = (document: DocumentBuilder, count: number = 5, redocOptions: RedocOptions): DocumentBuilder => {
|
||||
const introTagGroup = redocOptions.tagGroups.find((tagGroup) => tagGroup.name === "Intro");
|
||||
if (!introTagGroup) {
|
||||
redocOptions.tagGroups.push({
|
||||
name: "Intro",
|
||||
tags: ["Skills"],
|
||||
});
|
||||
} else {
|
||||
introTagGroup.tags.push("Skills");
|
||||
}
|
||||
|
||||
const intro = "A short excerpt of my skills are";
|
||||
const skillList = skills
|
||||
.slice(0, count)
|
||||
.reduce((list, skill) => list.concat(`<li><strong>${skill.name}</strong> ${skill.description}</li>`), "");
|
||||
|
||||
return document.addTag("Skills", `${intro}<br/><ul>${skillList}</ul>`);
|
||||
};
|
||||
|
||||
const formatExperience = (experience: ExperienceType) => {
|
||||
return `${experience.startDate.toLocaleDateString("en-GB")}`;
|
||||
};
|
||||
|
||||
const addExperiences = (document: DocumentBuilder, count: number = 5, redocOptions: RedocOptions): DocumentBuilder => {
|
||||
let experienceTagGroup = redocOptions.tagGroups.find((tagGroup) => tagGroup.name === "Experience");
|
||||
if (!experienceTagGroup) {
|
||||
experienceTagGroup = {
|
||||
name: "Experience",
|
||||
tags: ["Experience"],
|
||||
};
|
||||
redocOptions.tagGroups.push(experienceTagGroup);
|
||||
}
|
||||
|
||||
experiences.slice(0, count).forEach((experience) => {
|
||||
experienceTagGroup.tags.push(experience.name);
|
||||
document.addTag(experience.name, formatExperience(experience));
|
||||
});
|
||||
|
||||
return document;
|
||||
};
|
||||
|
||||
const initDocs = async ({
|
||||
app,
|
||||
config,
|
||||
redocOptions,
|
||||
swaggerUIPath,
|
||||
redocPath,
|
||||
}: {
|
||||
app: INestApplication;
|
||||
config: DocumentBuilder;
|
||||
redocOptions: RedocOptions;
|
||||
swaggerUIPath: string;
|
||||
redocPath: string;
|
||||
}): Promise<void> => {
|
||||
const document = SwaggerModule.createDocument(app, config.build(), {
|
||||
operationIdFactory: (controllerKey: string, methodKey: string) =>
|
||||
`${methodKey[0].toUpperCase()}${methodKey.substring(1)}`,
|
||||
});
|
||||
|
||||
SwaggerModule.setup(swaggerUIPath, app, document);
|
||||
await RedocModule.setup(redocPath, app, document, redocOptions);
|
||||
};
|
||||
|
||||
export default async (app: INestApplication) => {
|
||||
const redocOptions: RedocOptions = {
|
||||
logo: {
|
||||
url: "https://picsum.photos/256/128",
|
||||
altText: "Thom Werring",
|
||||
},
|
||||
sortPropsAlphabetically: true,
|
||||
hideDownloadButton: false,
|
||||
tagGroups: [],
|
||||
};
|
||||
|
||||
const config = apiDocument(
|
||||
{
|
||||
title: "Thom Werring - CV",
|
||||
description: "Westerstraat 83<br/>1521ZB, Wormerveer<br/><a href='tel:+31637650849'>+31 6 37 65 08 49</a>",
|
||||
version: "1.0.0a",
|
||||
contact: {
|
||||
name: "Thom Werring",
|
||||
email: "cv@t-werring.nl",
|
||||
},
|
||||
},
|
||||
redocOptions
|
||||
);
|
||||
|
||||
addIntro(config, redocOptions);
|
||||
addSkills(config, 5, redocOptions);
|
||||
addExperiences(config, 3, redocOptions);
|
||||
|
||||
await initDocs({
|
||||
app,
|
||||
config,
|
||||
redocOptions,
|
||||
swaggerUIPath: "/api",
|
||||
redocPath: "/docs",
|
||||
});
|
||||
};
|
||||
59
src/cvdocs/experience.ts
Normal file
59
src/cvdocs/experience.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import { ExperienceType } from "@/experiences/experiences.types";
|
||||
import { DocumentBuilder } from "@nestjs/swagger";
|
||||
import { RedocOptions } from "@juicyllama/nestjs-redoc";
|
||||
import { experiences } from "@/experiences/experiences";
|
||||
|
||||
const formatExperience = (experience: ExperienceType) => {
|
||||
const workPeriod = `${formatDate(experience.startDate)} - ${
|
||||
experience.endDate ? formatDate(experience.endDate) : "present"
|
||||
}`;
|
||||
|
||||
const company = experience.url
|
||||
? `<a target="_blank" href="${experience.url}">${experience.name}</a>`
|
||||
: experience.name;
|
||||
|
||||
return `<strong>${company}</strong>, <em>${experience.city}</em><br/>
|
||||
<strong>${experience.jobTitle}</strong><br/>
|
||||
${workPeriod}
|
||||
<p>${experience.description}</p>`;
|
||||
};
|
||||
|
||||
const formatDate = (date: Date, locale: string | string[] = "en-GB"): string => {
|
||||
const dateFormatter = new Intl.DateTimeFormat(locale, {
|
||||
dateStyle: "long",
|
||||
});
|
||||
const dateParts = dateFormatter.formatToParts(date).reduce<Record<"day" | "month" | "year", string>>(
|
||||
(result, datePart: Intl.DateTimeFormatPart) => {
|
||||
if (datePart.type !== "literal") {
|
||||
result[datePart.type] = datePart.value;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
{ day: "", month: "", year: "" }
|
||||
);
|
||||
|
||||
return `${dateParts.month} ${dateParts.year}`;
|
||||
};
|
||||
|
||||
export const addExperiences = (
|
||||
document: DocumentBuilder,
|
||||
count: number = 5,
|
||||
redocOptions: RedocOptions
|
||||
): DocumentBuilder => {
|
||||
let experienceTagGroup = redocOptions.tagGroups.find((tagGroup) => tagGroup.name === "Experience");
|
||||
if (!experienceTagGroup) {
|
||||
experienceTagGroup = {
|
||||
name: "Experience",
|
||||
tags: ["Experience"],
|
||||
};
|
||||
redocOptions.tagGroups.push(experienceTagGroup);
|
||||
}
|
||||
|
||||
experiences.slice(0, count).forEach((experience) => {
|
||||
experienceTagGroup.tags.push(experience.name);
|
||||
document.addTag(experience.name, formatExperience(experience));
|
||||
});
|
||||
|
||||
return document;
|
||||
};
|
||||
21
src/cvdocs/intro.ts
Normal file
21
src/cvdocs/intro.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { DocumentBuilder } from "@nestjs/swagger";
|
||||
import { RedocOptions } from "@juicyllama/nestjs-redoc";
|
||||
|
||||
export const addIntro = (document: DocumentBuilder, redocOptions: RedocOptions): DocumentBuilder => {
|
||||
const intro = [
|
||||
"I'm a software lead with 5+ years of experience in cloud-native development and Agile/Scrum methodologies. I'm passionate about building and leading high-performing teams to deliver scalable and reliable cloud-based applications. I have a proven track record of success in using Node.js, TypeScript, JavaScript, Docker, Kubernetes, AWS, DevOps, Git, microservices, and HAProxy to create and deploy innovative solutions.",
|
||||
"I'm also a strong communicator and collaborator, and I'm always looking for ways to improve my skills and knowledge. I'm excited about the future of cloud computing, and I'm eager to use my skills and experience to help others achieve their goals.",
|
||||
];
|
||||
|
||||
const introTagGroup = redocOptions.tagGroups.find((tagGroup) => tagGroup.name === "Intro");
|
||||
if (!introTagGroup) {
|
||||
redocOptions.tagGroups.push({
|
||||
name: "Intro",
|
||||
tags: ["Intro"],
|
||||
});
|
||||
} else {
|
||||
introTagGroup.tags.push("Intro");
|
||||
}
|
||||
|
||||
return document.addTag("Intro", intro.join("<br/>"));
|
||||
};
|
||||
91
src/cvdocs/openApi.ts
Normal file
91
src/cvdocs/openApi.ts
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import { RedocModule, RedocOptions } from "@juicyllama/nestjs-redoc";
|
||||
import { INestApplication } from "@nestjs/common";
|
||||
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
|
||||
import { addExperiences } from "@/cvdocs/experience";
|
||||
import { addSkills } from "@/cvdocs/skills";
|
||||
import { addIntro } from "@/cvdocs/intro";
|
||||
|
||||
const apiDocument = (
|
||||
options: {
|
||||
title: string;
|
||||
description: string;
|
||||
version: `${number}.${number}.${number}${string}` | `${number}.${number}${string}` | `${number}${string}`;
|
||||
contact: {
|
||||
name: string;
|
||||
email: string;
|
||||
};
|
||||
},
|
||||
redocOptions: RedocOptions
|
||||
) => {
|
||||
redocOptions.title = options.title;
|
||||
|
||||
return new DocumentBuilder()
|
||||
.setTitle(options.title)
|
||||
.setDescription(options.description)
|
||||
.setVersion(options.version)
|
||||
.setContact(options.contact.name, null, options.contact.email)
|
||||
.addServer("http://localhost:3000/");
|
||||
};
|
||||
|
||||
const initDocs = async ({
|
||||
app,
|
||||
config,
|
||||
redocOptions,
|
||||
swaggerUIPath,
|
||||
redocPath,
|
||||
}: {
|
||||
app: INestApplication;
|
||||
config: DocumentBuilder;
|
||||
redocOptions: RedocOptions;
|
||||
swaggerUIPath?: string;
|
||||
redocPath?: string;
|
||||
}): Promise<void> => {
|
||||
const document = SwaggerModule.createDocument(app, config.build(), {
|
||||
operationIdFactory: (controllerKey: string, methodKey: string) =>
|
||||
`${methodKey[0].toUpperCase()}${methodKey.substring(1)}`,
|
||||
});
|
||||
|
||||
if (swaggerUIPath) {
|
||||
SwaggerModule.setup(swaggerUIPath, app, document);
|
||||
}
|
||||
if (redocPath) {
|
||||
await RedocModule.setup(redocPath, app, document, redocOptions);
|
||||
}
|
||||
};
|
||||
|
||||
export default async (app: INestApplication) => {
|
||||
const redocOptions: RedocOptions = {
|
||||
logo: {
|
||||
url: "https://picsum.photos/256/128",
|
||||
altText: "Thom Werring",
|
||||
},
|
||||
sortPropsAlphabetically: true,
|
||||
hideDownloadButton: false,
|
||||
tagGroups: [],
|
||||
};
|
||||
|
||||
const config = apiDocument(
|
||||
{
|
||||
title: "Thom Werring - CV",
|
||||
description: "Westerstraat 83<br/>1521ZB, Wormerveer<br/><a href='tel:+31637650849'>+31 6 37 65 08 49</a>",
|
||||
version: "1.0.0a",
|
||||
contact: {
|
||||
name: "Thom Werring",
|
||||
email: "cv@t-werring.nl",
|
||||
},
|
||||
},
|
||||
redocOptions
|
||||
);
|
||||
|
||||
addIntro(config, redocOptions);
|
||||
addSkills(config, 5, redocOptions);
|
||||
addExperiences(config, 3, redocOptions);
|
||||
|
||||
await initDocs({
|
||||
app,
|
||||
config,
|
||||
redocOptions,
|
||||
swaggerUIPath: "/api",
|
||||
redocPath: "/docs",
|
||||
});
|
||||
};
|
||||
26
src/cvdocs/skills.ts
Normal file
26
src/cvdocs/skills.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { DocumentBuilder } from "@nestjs/swagger";
|
||||
import { RedocOptions } from "@juicyllama/nestjs-redoc";
|
||||
import { skills } from "@/skills/skills";
|
||||
|
||||
export const addSkills = (
|
||||
document: DocumentBuilder,
|
||||
count: number = 5,
|
||||
redocOptions: RedocOptions
|
||||
): DocumentBuilder => {
|
||||
const introTagGroup = redocOptions.tagGroups.find((tagGroup) => tagGroup.name === "Intro");
|
||||
if (!introTagGroup) {
|
||||
redocOptions.tagGroups.push({
|
||||
name: "Intro",
|
||||
tags: ["Skills"],
|
||||
});
|
||||
} else {
|
||||
introTagGroup.tags.push("Skills");
|
||||
}
|
||||
|
||||
const intro = "A short excerpt of my skills are";
|
||||
const skillList = skills
|
||||
.slice(0, count)
|
||||
.reduce((list, skill) => list.concat(`<li><strong>${skill.name}</strong> ${skill.description}</li>`), "");
|
||||
|
||||
return document.addTag("Skills", `${intro}<br/><ul>${skillList}</ul>`);
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { NestFactory } from "@nestjs/core";
|
||||
import { AppModule } from "@/app.module";
|
||||
import openApi from "@/common/openApi";
|
||||
import openApi from "@/cvdocs/openApi";
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
|
|
|||
Loading…
Reference in a new issue