Skip to content

Commit

Permalink
docs: update code examples in action validator section
Browse files Browse the repository at this point in the history
  • Loading branch information
fruneen committed Jan 26, 2024
1 parent 6869948 commit 77c8146
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 19 deletions.
82 changes: 67 additions & 15 deletions docs/api-reference/api-action-validator.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,96 @@ title: "API action validator"

**API action validator** — is an array of functions (think middlewares) that is used to make sure that data sent by client is valid.


## Examples

```typescript
import { z } from 'zod';

import validate from 'middlewares/validate.middleware';
import { securityUtil } from 'utils';
import { AppKoaContext, Next } from 'types';
import { EMAIL_REGEX, PASSWORD_REGEX } from 'app-constants';

import { userService } from 'resources/user';

import { PASSWORD_REGEX } from 'app-constants';
import { Next, AppKoaContext, AppRouter } from 'types';
import { validateMiddleware } from 'middlewares';

const schema = z.object({
password: z.string().regex(PASSWORD_REGEX, 'The password must contain 6 or more characters with at least one letter (a-z) and one number (0-9).'),
firstName: z.string().min(1, 'Please enter fist name.').max(100),
lastName: z.string().min(1, 'Please enter last name.').max(100),
email: z.string().regex(EMAIL_REGEX, 'Email format is incorrect.'),
password: z.string().regex(PASSWORD_REGEX, 'The password format is incorrect'),
});

type ValidatedData = {
password: string;
type ValidatedData = z.infer<typeof schema>;

async function validator(ctx: AppKoaContext<ValidatedData>, next: Next) {
const { email } = ctx.validatedData;

const isUserExists = await userService.exists({ email });

ctx.assertClientError(!isUserExists, {
email: 'User with this email is already registered',
});

await next();
}

async function handler(ctx: AppKoaContext<ValidatedData>) {
// ...action code
}

export default (router: AppRouter) => {
router.post('/sign-up', validateMiddleware(schema), validator, handler);
};
```

To pass data from the `validator` to the `handler`, utilize the `ctx.validatedData` object:

``` typescript
import { z } from 'zod';

import { AppKoaContext, AppRouter, Next, User } from 'types';
import { EMAIL_REGEX, PASSWORD_REGEX } from 'app-constants';

import { userService } from 'resources/user';

import { validateMiddleware } from 'middlewares';
import { securityUtil } from 'utils';

const schema = z.object({
email: z.string().regex(EMAIL_REGEX, 'Email format is incorrect.'),
password: z.string().regex(PASSWORD_REGEX, 'The password format is incorrect'),
});

interface ValidatedData extends z.infer<typeof schema> {
user: User;
}

async function validator(ctx: AppKoaContext<ValidatedData>, next: Next) {
const { user } = ctx.state;
const { password } = ctx.validatedData;
const { email, password } = ctx.validatedData;

const user = await userService.findOne({ email });

ctx.assertClientError(user && user.passwordHash, {
credentials: 'The email or password you have entered is invalid',
});

const isPasswordMatch = await securityUtil.compareTextWithHash(password, user.passwordHash);
ctx.assertClientError(!isPasswordMatch, {
password: 'The new password should be different from the previous one',

ctx.assertClientError(isPasswordMatch, {
credentials: 'The email or password you have entered is invalid',
});

ctx.validatedData.user = user;
await next();
}

async function handler(ctx: AppKoaContext<ValidatedData>) {
// action code
const { user } = ctx.validatedData;

// ...action code
}

export default (router: AppRouter) => {
router.post('/current', validate(schema), validator, handler);
router.post('/sign-in', validateMiddleware(schema), validator, handler);
};

```
6 changes: 2 additions & 4 deletions template/apps/api/src/resources/account/actions/sign-up.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { z } from 'zod';

import { AppKoaContext, Next, AppRouter, Template, User } from 'types';
import { AppKoaContext, Next, AppRouter, Template } from 'types';
import { EMAIL_REGEX, PASSWORD_REGEX } from 'app-constants';

import { userService } from 'resources/user';
Expand All @@ -18,9 +18,7 @@ const schema = z.object({
password: z.string().regex(PASSWORD_REGEX, 'The password must contain 6 or more characters with at least one letter (a-z) and one number (0-9).'),
});

interface ValidatedData extends z.infer<typeof schema> {
user: User;
}
type ValidatedData = z.infer<typeof schema>;

async function validator(ctx: AppKoaContext<ValidatedData>, next: Next) {
const { email } = ctx.validatedData;
Expand Down

0 comments on commit 77c8146

Please sign in to comment.