Skip to content

Commit d05fa5e

Browse files
authored
feat(app): add OpenAPI fetcher (#397)
1 parent e5d4f9a commit d05fa5e

File tree

10 files changed

+365
-62
lines changed

10 files changed

+365
-62
lines changed

apps/app/.env.local

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
NEXT_PUBLIC_API_URL=http://api.devfaq.localhost:3002
1+
NEXT_PUBLIC_API_URL=https://staging-api.devfaq.pl
22
NEXT_PUBLIC_APP_URL=http://app.devfaq.localhost:3000

apps/app/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@next/font": "13.0.6",
1818
"client-only": "0.0.1",
1919
"next": "13.0.4",
20+
"openapi-typescript-fetch": "1.1.3",
2021
"react": "18.2.0",
2122
"react-dom": "18.2.0",
2223
"tailwind-merge": "1.8.0"
@@ -39,6 +40,7 @@
3940
"eslint": "8.29.0",
4041
"eslint-config-devfaq": "workspace:*",
4142
"eslint-plugin-storybook": "^0.6.7",
43+
"openapi-types": "workspace:*",
4244
"postcss": "^8.4.19",
4345
"postcss-loader": "^7.0.2",
4446
"storybook": "^7.0.0-alpha.54",

apps/app/src/app/foo/page.tsx

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,21 @@
11
import { QuestionItem } from "../../components/QuestionItem/QuestionItem";
2+
import { getAllQuestions } from "../../services/questions.service";
3+
4+
export default async function FooPage() {
5+
const { data } = await getAllQuestions({ limit: 20 });
26

3-
export default function FooPage() {
47
return (
58
<div className="flex flex-col gap-y-10 p-10">
6-
<QuestionItem
7-
title="Co się stanie gdy EventEmitter wyemituje event 'error', a nic na niego nie
8-
nasłuchuje?"
9-
level="junior"
10-
creationDate={new Date("2023-01-01")}
11-
votes={1}
12-
voted={false}
13-
/>
14-
<QuestionItem
15-
title="Co się stanie gdy EventEmitter wyemituje event 'error', a nic na niego nie
16-
nasłuchuje?"
17-
level="mid"
18-
creationDate={new Date("2023-01-01")}
19-
votes={2}
20-
voted={true}
21-
/>
22-
<QuestionItem
23-
title="Co się stanie gdy EventEmitter wyemituje event 'error', a nic na niego nie
24-
nasłuchuje?"
25-
level="senior"
26-
creationDate={new Date("2023-01-01")}
27-
votes={3}
28-
voted={true}
29-
/>
9+
{data.data.map(({ id, question, _levelId, acceptedAt, votesCount }) => (
10+
<QuestionItem
11+
key={id}
12+
title={question}
13+
level={_levelId as "junior"}
14+
creationDate={new Date(acceptedAt || "")}
15+
votes={votesCount}
16+
voted={id % 2 === 0}
17+
/>
18+
))}
3019
</div>
3120
);
3221
}

apps/app/src/lib/fetcher.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { Fetcher } from "openapi-typescript-fetch";
2+
import type { paths } from "openapi-types";
3+
4+
export const fetcher = Fetcher.for<paths>();
5+
6+
fetcher.configure({
7+
baseUrl: process.env.NEXT_PUBLIC_API_URL,
8+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { fetcher } from "../lib/fetcher";
2+
3+
export const getAllQuestions = fetcher.path("/questions").method("get").create();

packages/openapi-types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./types";

packages/openapi-types/package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "openapi-types",
3+
"version": "0.0.0",
4+
"main": "index.ts",
5+
"types": "index.ts",
6+
"license": "MIT",
7+
"scripts": {
8+
"generate": "openapi-typescript https://staging-api.devfaq.pl/documentation/json --output types.ts"
9+
},
10+
"devDependencies": {
11+
"openapi-typescript": "6.1.0",
12+
"tsconfig": "workspace:*"
13+
}
14+
}

packages/openapi-types/tsconfig.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"$schema": "https://json.schemastore.org/tsconfig",
3+
"extends": "tsconfig/base.json"
4+
}

packages/openapi-types/types.ts

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
/**
2+
* This file was auto-generated by openapi-typescript.
3+
* Do not make direct changes to the file.
4+
*/
5+
6+
export interface paths {
7+
"/oauth/github/login": {
8+
get: {
9+
responses: {
10+
/** @description Default Response */
11+
200: never;
12+
};
13+
};
14+
};
15+
"/oauth/github": {
16+
get: {
17+
responses: {
18+
/** @description Default Response */
19+
200: never;
20+
};
21+
};
22+
};
23+
"/auth/me": {
24+
/** @description Get currently logged-in user */
25+
get: {
26+
/** @description Get currently logged-in user */
27+
responses: {
28+
/** @description Default Response */
29+
200: {
30+
content: {
31+
"application/json": {
32+
data: {
33+
/** Format: date-time */
34+
createdAt: string;
35+
/** Format: date-time */
36+
updatedAt: string;
37+
keepMeSignedIn: boolean;
38+
/** Format: date-time */
39+
validUntil: string;
40+
_user: {
41+
id: number;
42+
email: string;
43+
firstName: string | null;
44+
lastName: string | null;
45+
_roleId: string;
46+
/** Format: date-time */
47+
createdAt: string;
48+
/** Format: date-time */
49+
updatedAt: string;
50+
socialLogin: {
51+
[key: string]: (string | number) | undefined;
52+
};
53+
};
54+
};
55+
};
56+
};
57+
};
58+
};
59+
};
60+
/** @description Log out */
61+
delete: {
62+
/** @description Log out */
63+
responses: {
64+
/** @description Default Response */
65+
204: {
66+
content: {
67+
"application/json": Record<string, never>;
68+
};
69+
};
70+
};
71+
};
72+
};
73+
"/questions": {
74+
get: {
75+
parameters?: {
76+
query?: {
77+
category?: string;
78+
status?: string;
79+
level?: string;
80+
limit?: number;
81+
offset?: number;
82+
orderBy?: "acceptedAt" | "level" | "votesCount";
83+
order?: "asc" | "desc";
84+
};
85+
};
86+
responses: {
87+
/** @description Default Response */
88+
200: {
89+
content: {
90+
"application/json": {
91+
data: {
92+
id: number;
93+
question: string;
94+
_categoryId: string;
95+
_levelId: string;
96+
_statusId: string;
97+
/** Format: date-time */
98+
acceptedAt?: string;
99+
votesCount: number;
100+
currentUserVotedOn: boolean;
101+
}[];
102+
meta: {
103+
total: number;
104+
};
105+
};
106+
};
107+
};
108+
};
109+
};
110+
post: {
111+
requestBody: {
112+
content: {
113+
"application/json": {
114+
question: string;
115+
level: string;
116+
category: string;
117+
};
118+
};
119+
};
120+
responses: {
121+
/** @description Default Response */
122+
200: {
123+
content: {
124+
"application/json": {
125+
data: {
126+
id: number;
127+
question: string;
128+
_categoryId: string;
129+
_levelId: string;
130+
_statusId: string;
131+
/** Format: date-time */
132+
acceptedAt?: string;
133+
votesCount: number;
134+
currentUserVotedOn: boolean;
135+
};
136+
};
137+
};
138+
};
139+
};
140+
};
141+
};
142+
"/questions/{id}": {
143+
get: {
144+
parameters: {
145+
path: {
146+
id: number;
147+
};
148+
};
149+
responses: {
150+
/** @description Default Response */
151+
200: {
152+
content: {
153+
"application/json": {
154+
data: {
155+
id: number;
156+
question: string;
157+
_categoryId: string;
158+
_levelId: string;
159+
_statusId: string;
160+
/** Format: date-time */
161+
acceptedAt?: string;
162+
votesCount: number;
163+
currentUserVotedOn: boolean;
164+
};
165+
};
166+
};
167+
};
168+
};
169+
};
170+
delete: {
171+
parameters: {
172+
path: {
173+
id: number;
174+
};
175+
};
176+
responses: {
177+
/** @description Default Response */
178+
200: never;
179+
};
180+
};
181+
patch: {
182+
parameters: {
183+
path: {
184+
id: number;
185+
};
186+
};
187+
requestBody: {
188+
content: {
189+
"application/json": {
190+
question: string;
191+
level: string;
192+
category: string;
193+
status: string;
194+
};
195+
};
196+
};
197+
responses: {
198+
/** @description Default Response */
199+
200: {
200+
content: {
201+
"application/json": {
202+
data: {
203+
id: number;
204+
question: string;
205+
_categoryId: string;
206+
_levelId: string;
207+
_statusId: string;
208+
/** Format: date-time */
209+
acceptedAt?: string;
210+
votesCount: number;
211+
currentUserVotedOn: boolean;
212+
};
213+
};
214+
};
215+
};
216+
};
217+
};
218+
};
219+
"/": {
220+
get: {
221+
responses: {
222+
/** @description Default Response */
223+
200: {
224+
content: {
225+
"application/json": string;
226+
};
227+
};
228+
};
229+
};
230+
};
231+
}
232+
233+
export type webhooks = Record<string, never>;
234+
235+
export interface components {
236+
schemas: {};
237+
responses: never;
238+
parameters: never;
239+
requestBodies: never;
240+
headers: never;
241+
pathItems: never;
242+
}
243+
244+
export type external = Record<string, never>;
245+
246+
export type operations = Record<string, never>;

0 commit comments

Comments
 (0)