Skip to content

Commit

Permalink
chore(api): refactor schemas into individual files (freeCodeCamp#54350)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShaunSHamilton authored Apr 11, 2024
1 parent 2227743 commit 133f07b
Show file tree
Hide file tree
Showing 34 changed files with 1,271 additions and 1,145 deletions.
1,209 changes: 64 additions & 1,145 deletions api/src/schemas.ts

Large diffs are not rendered by default.

129 changes: 129 additions & 0 deletions api/src/schemas/certificate/cert-slug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { Type } from '@fastify/type-provider-typebox';
import { Certification } from '../../../../shared/config/certification-settings';

export const certSlug = {
params: Type.Object({
certSlug: Type.String(),
username: Type.String()
}),
response: {
// TODO(POST_MVP): Most of these should not be 200s
200: Type.Union([
Type.Object({
messages: Type.Array(
Type.Object({
type: Type.Literal('info'),
message: Type.Literal('flash.username-not-found'),
variables: Type.Object({
username: Type.String()
})
})
)
}),
Type.Object({
messages: Type.Array(
Type.Object({
type: Type.Literal('info'),
message: Type.Literal('flash.not-eligible')
})
)
}),
Type.Object({
messages: Type.Array(
Type.Object({
type: Type.Literal('info'),
message: Type.Literal('flash.not-honest'),
variables: Type.Object({
username: Type.String()
})
})
)
}),
Type.Object({
messages: Type.Array(
Type.Object({
type: Type.Literal('info'),
message: Type.Literal('flash.profile-private'),
variables: Type.Object({
username: Type.String()
})
})
)
}),
Type.Object({
messages: Type.Array(
Type.Object({
type: Type.Literal('info'),
message: Type.Literal('flash.add-name')
})
)
}),
Type.Object({
messages: Type.Array(
Type.Object({
type: Type.Literal('info'),
message: Type.Literal('flash.certs-private'),
variables: Type.Object({
username: Type.String()
})
})
)
}),
Type.Object({
messages: Type.Array(
Type.Object({
type: Type.Literal('info'),
message: Type.Literal('flash.timeline-private'),
variables: Type.Object({
username: Type.String()
})
})
)
}),
Type.Object({
certSlug: Type.Enum(Certification),
certTitle: Type.String(),
username: Type.String(),
date: Type.Number(),
completionTime: Type.Number()
}),
Type.Object({
certSlug: Type.Enum(Certification),
certTitle: Type.String(),
username: Type.String(),
name: Type.String(),
date: Type.Number(),
completionTime: Type.Number()
}),
Type.Object({
messages: Type.Array(
Type.Object({
type: Type.Literal('info'),
message: Type.Literal('flash.user-not-certified'),
variables: Type.Object({
username: Type.String(),
cert: Type.String()
})
})
)
})
]),
400: Type.Object({
type: Type.Literal('error'),
message: Type.String()
}),
404: Type.Object({
message: Type.Literal('flash.cert-not-found'),
type: Type.Literal('info'),
variables: Type.Object({
certSlug: Type.String()
})
}),
500: Type.Object({
type: Type.Literal('danger'),
message: Type.Literal(
'Oops! Something went wrong. Please try again in a moment or contact support@freecodecamp.org if the error persists.'
)
})
}
};
129 changes: 129 additions & 0 deletions api/src/schemas/certificate/certificate-verify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { Type } from '@fastify/type-provider-typebox';
import { isCertMap } from '../types';

export const certificateVerify = {
// TODO(POST_MVP): Remove partial validation from route for schema validation
body: Type.Object({
certSlug: Type.String({ maxLength: 1024 })
}),
response: {
200: Type.Object({
response: Type.Union([
Type.Object({
type: Type.Literal('info'),
message: Type.Union([Type.Literal('flash.already-claimed')]),
variables: Type.Object({
name: Type.String()
})
}),
Type.Object({
type: Type.Literal('success'),
message: Type.Literal('flash.cert-claim-success'),
variables: Type.Object({
username: Type.String(),
name: Type.String()
})
})
]),
isCertMap,
completedChallenges: Type.Array(
Type.Object({
id: Type.String(),
completedDate: Type.Number(),
solution: Type.Optional(Type.String()),
githubLink: Type.Optional(Type.String()),
challengeType: Type.Optional(Type.Number()),
// Technically, files is optional, but the db default was [] and
// the client treats null, undefined and [] equivalently.
// TODO(Post-MVP): make this optional.
files: Type.Array(
Type.Object({
contents: Type.String(),
key: Type.String(),
ext: Type.String(),
name: Type.String(),
path: Type.Optional(Type.String())
})
),
isManuallyApproved: Type.Optional(Type.Boolean())
})
)
}),
400: Type.Union([
Type.Object({
response: Type.Object({
type: Type.Literal('info'),
message: Type.Union([Type.Literal('flash.incomplete-steps')]),
variables: Type.Object({
name: Type.String()
})
}),
isCertMap,
completedChallenges: Type.Array(
Type.Object({
id: Type.String(),
completedDate: Type.Number(),
solution: Type.Optional(Type.String()),
githubLink: Type.Optional(Type.String()),
challengeType: Type.Optional(Type.Number()),
// Technically, files is optional, but the db default was [] and
// the client treats null, undefined and [] equivalently.
// TODO(Post-MVP): make this optional.
files: Type.Array(
Type.Object({
contents: Type.String(),
key: Type.String(),
ext: Type.String(),
name: Type.String(),
path: Type.Optional(Type.String())
})
),
isManuallyApproved: Type.Optional(Type.Boolean())
})
)
}),
Type.Object({
response: Type.Object({
type: Type.Literal('danger'),
message: Type.Union([Type.Literal('flash.wrong-name')]),
variables: Type.Object({
name: Type.String()
})
})
}),
Type.Object({
response: Type.Object({
type: Type.Literal('info'),
message: Type.Union([Type.Literal('flash.name-needed')])
}),
isCertMap,
completedChallenges: Type.Array(
Type.Object({
id: Type.String(),
completedDate: Type.Number(),
solution: Type.Optional(Type.String()),
githubLink: Type.Optional(Type.String()),
challengeType: Type.Optional(Type.Number()),
// Technically, files is optional, but the db default was [] and
// the client treats null, undefined and [] equivalently.
// TODO(Post-MVP): make this optional.
files: Type.Array(
Type.Object({
contents: Type.String(),
key: Type.String(),
ext: Type.String(),
name: Type.String(),
path: Type.Optional(Type.String())
})
),
isManuallyApproved: Type.Optional(Type.Boolean())
})
)
})
]),
500: Type.Object({
type: Type.Literal('danger'),
message: Type.Literal('flash.went-wrong')
})
}
};
26 changes: 26 additions & 0 deletions api/src/schemas/challenge/backend-challenge-completed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Type } from '@fastify/type-provider-typebox';

export const backendChallengeCompleted = {
body: Type.Object({
id: Type.String({ format: 'objectid', maxLength: 24, minLength: 24 })
}),
response: {
200: Type.Object({
completedDate: Type.Number(),
points: Type.Number(),
alreadyCompleted: Type.Boolean()
}),
400: Type.Object({
type: Type.Literal('error'),
message: Type.Literal(
'That does not appear to be a valid challenge submission.'
)
}),
500: Type.Object({
type: Type.Literal('danger'),
message: Type.Literal(
'Oops! Something went wrong. Please try again in a moment or contact support@freecodecamp.org if the error persists.'
)
})
}
};
22 changes: 22 additions & 0 deletions api/src/schemas/challenge/coderoad-challenge-completed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Type } from '@fastify/type-provider-typebox';

export const coderoadChallengeCompleted = {
body: Type.Object({
tutorialId: Type.String()
}),
headers: Type.Object({ 'coderoad-user-token': Type.String() }),
response: {
200: Type.Object({
type: Type.Literal('success'),
msg: Type.String()
}),
400: Type.Object({
type: Type.Literal('error'),
msg: Type.String()
}),
500: Type.Object({
type: Type.Literal('danger'),
msg: Type.String()
})
}
};
40 changes: 40 additions & 0 deletions api/src/schemas/challenge/exam-challenge-completed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Type } from '@fastify/type-provider-typebox';
import { examResults } from '../types';

export const examChallengeCompleted = {
body: Type.Object({
id: Type.String({ format: 'objectid', maxLength: 24, minLength: 24 }),
challengeType: Type.Number(),
userCompletedExam: Type.Object({
examTimeInSeconds: Type.Number(),
userExamQuestions: Type.Array(
Type.Object({
id: Type.String(),
question: Type.String(),
answer: Type.Object({
id: Type.String(),
answer: Type.String()
})
}),
{ minItems: 1 }
)
})
}),
response: {
200: Type.Object({
completedDate: Type.Number(),
points: Type.Number(),
alreadyCompleted: Type.Boolean(),
examResults
}),
400: Type.Object({
error: Type.String()
}),
403: Type.Object({
error: Type.String()
}),
500: Type.Object({
error: Type.String()
})
}
};
37 changes: 37 additions & 0 deletions api/src/schemas/challenge/exam.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Type } from '@fastify/type-provider-typebox';

export const exam = {
params: Type.Object({
id: Type.String({
format: 'objectid',
maxLength: 24,
minLength: 24
})
}),
response: {
200: Type.Object({
generatedExam: Type.Array(
Type.Object({
id: Type.String(),
question: Type.String(),
answers: Type.Array(
Type.Object({
id: Type.String(),
answer: Type.String()
})
)
})
)
}),
// TODO: Standardize error responses - e.g. { type, message }
400: Type.Object({
error: Type.String()
}),
403: Type.Object({
error: Type.String()
}),
500: Type.Object({
error: Type.String()
})
}
};
Loading

0 comments on commit 133f07b

Please sign in to comment.