Skip to content

Commit

Permalink
feat(1.2d): Add validation with JSON Schema
Browse files Browse the repository at this point in the history
  • Loading branch information
one-aalam committed Jul 14, 2021
1 parent 0d1a1ea commit 1e6f837
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 12 deletions.
15 changes: 14 additions & 1 deletion src/routes/auth.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
import { FastifyInstance, FastifyRequest } from 'fastify'
import { USERS } from '../fixtures'

const authBodySchema = {
type: 'object',
properties: {
email: { type: 'string', format: 'email'},
password: { type: 'string'},
},
required: ['email', 'password']
}

type AuthLoginBody = {
email: string
password: string
}

export default async function auth(fastify: FastifyInstance) {
// log-in a user
fastify.post<{ Body: AuthLoginBody }>('/auth/login', async (req: FastifyRequest, reply) => {
fastify.post<{ Body: AuthLoginBody }>('/auth/login', {
schema: {
body: authBodySchema
}
},async (req: FastifyRequest, reply) => {
// @ts-ignore
const { email, password } = req.body
const user = USERS.find(user => user.email == email)
Expand Down
40 changes: 36 additions & 4 deletions src/routes/categories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@ import { FastifyInstance } from 'fastify'
import { RECIPE_CATEGORIES } from '../fixtures'
import { RecipeCatgeory } from '../types'

const categoryBodySchema = {
type: 'object',
properties: {
type: { type: 'string'},
name: { type: 'string'},
desc: { type: 'string'}
},
}

const categoryCreateBodySchema = {
...categoryBodySchema,
required: [ 'type' ]
}

const categoryParamsSchema = {
type: 'object',
properties: {
id: { type: 'number'}
},
required: [ 'id' ]
}

type CategoryParams = {
id: string
}
Expand All @@ -17,7 +39,9 @@ export default async function categories(fastify: FastifyInstance) {
// get the category by provided id
fastify.get<{
Params: CategoryParams
}>('/categories/:id', async (req, reply) => {
}>('/categories/:id', { schema: {
params: categoryParamsSchema
}},async (req, reply) => {
const recipeCategory = RECIPE_CATEGORIES.find(recipeCategory => recipeCategory.id === parseInt(req.params.id))
if(!recipeCategory) {
reply.code(404).send({
Expand All @@ -28,7 +52,10 @@ export default async function categories(fastify: FastifyInstance) {
return recipeCategory
})

fastify.post<{ Body: CategoryCreateBody }>('/categories', async (req, reply) => {
fastify.post<{ Body: CategoryCreateBody }>('/categories', { schema: {
params: categoryParamsSchema,
body: categoryCreateBodySchema
}}, async (req, reply) => {
const { type, name, desc } = req.body

// enforce constraints like unique-ness
Expand All @@ -55,7 +82,10 @@ export default async function categories(fastify: FastifyInstance) {
fastify.put<{
Params: CategoryParams,
Body: CategoryUpdateBody
}>('/categories/:id', async (req, reply) => {
}>('/categories/:id', { schema: {
params: categoryParamsSchema,
body: categoryBodySchema
}}, async (req, reply) => {

// err, and exit early!
let recipeCategory = RECIPE_CATEGORIES.find(recipeCategory => recipeCategory.id === parseInt(req.params.id))
Expand Down Expand Up @@ -101,7 +131,9 @@ export default async function categories(fastify: FastifyInstance) {

fastify.delete<{
Params: CategoryParams,
}>('/categories/:id', async (req, reply) => {
}>('/categories/:id', { schema: {
params: categoryParamsSchema
}}, async (req, reply) => {

// get where is it
const recipeCategoryIndex = RECIPE_CATEGORIES.findIndex(recipeCategory => recipeCategory.id === parseInt(req.params.id))
Expand Down
66 changes: 60 additions & 6 deletions src/routes/recipes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,49 @@ import { FastifyInstance } from 'fastify'
import { Recipe } from '../types'
import { RECIPES } from '../fixtures'


const recipeBodySchema = {
type: 'object',
properties: {
name: { type: 'string' },
desc: { type: 'string', default: '' },
imageUrl: { type: 'string', default: '' },
courseId: { type: 'number', },
cuisineId: { type: 'number' },
serves: { type: 'number' },
prepTime: { type: 'number', default: 0 },
cookingTime: { type: 'number' },
ingredients: { type: 'array', items: { type: 'string' }},
directions: { type: 'array', items: { type: 'string' }},
source: { type: 'string', default: '' },
tags: { type: 'string', default: '' },
},
}

const recipeBodyCreateSchema = {
...recipeBodySchema,
required: [ 'name', 'courseId', 'cuisineId', 'serves', 'cookingTime', 'ingredients', 'directions' ]
}

const recipeParamsSchema = {
type: 'object',
properties: {
id: { type: 'number'}
},
required: [ 'id' ]
}

const recipeQuerystringSchema = {
type: 'object',
properties: {
offset: { type: 'number'},
limit: { type: 'number'},
tag: { type: 'string'},
cuisineId: { type: 'number'},
courseId: { type: 'number'},
},
}

type RecipeParams = {
id: string
}
Expand All @@ -24,7 +67,9 @@ export default async function recipes(fastify: FastifyInstance) {
// get all recipes having the provided `tag`, `cuisineId`, `categoryId`, or range, or all the recipes
fastify.get<{
Querystring: RecipeQuerystring
}>('/recipes', async (req) => {
}>('/recipes', { schema: {
querystring: recipeQuerystringSchema
}}, async (req) => {
const { offset = 0, limit = 10, tag, cuisineId, courseId } = req.query
return RECIPES
.filter(recipe =>
Expand All @@ -42,7 +87,9 @@ export default async function recipes(fastify: FastifyInstance) {
// get the recipe by provided id
fastify.get<{
Params: RecipeParams
}>('/recipes/:id', async (req, reply) => {
}>('/recipes/:id', { schema: {
params: recipeParamsSchema
}}, async (req, reply) => {
const recipe = RECIPES.find(recipe => recipe.id === parseInt(req.params.id))
if(!recipe) {
reply.code(404).send({
Expand All @@ -53,19 +100,24 @@ export default async function recipes(fastify: FastifyInstance) {
return recipe
})

fastify.post<{ Body: RecipeCreateBody }>('/recipes', async (req, reply) => {
fastify.post<{ Body: RecipeCreateBody }>('/recipes', { schema: {
body: recipeBodyCreateSchema
}}, async (req, reply) => {
const newRecipe: Recipe = {
...req.body,
id: RECIPES[RECIPES.length - 1].id + 1,
}
// RECIPES.push(newRecipe)
RECIPES.push(newRecipe)
reply.code(201).send(newRecipe)
})

fastify.put<{
Params: RecipeParams,
Body: RecipeUpdateBody
}>('/recipes/:id', async (req, reply) => {
}>('/recipes/:id', { schema: {
params: recipeParamsSchema,
body: recipeBodySchema
}}, async (req, reply) => {

const recipe = RECIPES.find(recipe => recipe.id === parseInt(req.params.id))
if(!recipe) {
Expand Down Expand Up @@ -93,7 +145,9 @@ export default async function recipes(fastify: FastifyInstance) {

fastify.delete<{
Params: RecipeParams,
}>('/recipes/:id', async (req, reply) => {
}>('/recipes/:id', { schema: {
params: recipeParamsSchema
}}, async (req, reply) => {

// get where is it
const recipeIndex = RECIPES.findIndex(recipe => recipe.id === parseInt(req.params.id))
Expand Down
12 changes: 11 additions & 1 deletion src/routes/users.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { FastifyInstance } from 'fastify'
import { USERS } from '../fixtures'

const userParamsSchema = {
type: 'object',
properties: {
id: { type: 'number'}
},
required: [ 'id' ]
}

type UserParams = {
id: string
}
Expand All @@ -12,7 +20,9 @@ export default async function users(fastify: FastifyInstance) {
// get the user by provided id
fastify.get<{
Params: UserParams
}>('/users/:id', async (req, reply) => {
}>('/users/:id', { schema: {
params: userParamsSchema
}}, async (req, reply) => {
const user = USERS.find(user => user.id === parseInt(req.params.id))
if(!user) {
reply.code(404).send({
Expand Down

0 comments on commit 1e6f837

Please sign in to comment.