หนึ่งในภารกิจพื้นฐานที่ต้องดำเนินการใน API คือการตรวจสอบข้อมูล ในบทความนี้ฉันต้องการแสดงวิธีเพิ่มการตรวจสอบความถูกต้องกันกระสุนสำหรับข้อมูลของคุณด้วยวิธีที่ส่งคืนข้อมูลในรูปแบบที่สวยงาม
ทำการตรวจสอบข้อมูลแบบกำหนดเองใน โหนด js ไม่ใช่เรื่องง่ายหรือรวดเร็ว มีฟังก์ชันมากมายที่คุณต้องเขียนเพื่อให้ครอบคลุมข้อมูลทุกประเภท ในขณะที่ฉันได้ลองใช้ไลบรารีข้อมูลฟอร์ม Node.js ไปสองสามรายการสำหรับทั้งสองอย่าง Express และ Koa - พวกเขาไม่เคยเติมเต็มความต้องการของโครงการของฉัน มีปัญหาในการขยายไลบรารีและไลบรารีไม่ทำงานกับโครงสร้างข้อมูลที่ซับซ้อนหรือการตรวจสอบความถูกต้องแบบอะซิงโครนัส
นั่นเป็นเหตุผลที่ในที่สุดฉันจึงตัดสินใจเขียนไลบรารีการตรวจสอบความถูกต้องของฟอร์มขนาดเล็ก แต่ทรงพลังของตัวเองชื่อว่า ดาต้าไลซ์ . ขยายได้ดังนั้นคุณสามารถใช้ในโครงการใดก็ได้และปรับแต่งตามความต้องการของคุณ ตรวจสอบความถูกต้องของเนื้อหาข้อความค้นหาหรือพารามิเตอร์ของคำขอ นอกจากนี้ยังรองรับ async
ตัวกรองและโครงสร้าง JSON ที่ซับซ้อนเช่น อาร์เรย์ หรือ วัตถุที่ซ้อนกัน .
สามารถติดตั้ง Datalize ผ่าน npm:
npm install --save datalize
ในการแยกวิเคราะห์เนื้อหาของคำขอคุณควรใช้ห้องสมุดแยกต่างหาก หากคุณยังไม่ได้ใช้ฉันขอแนะนำ koa-body สำหรับ Koa หรือ ตัวแยกวิเคราะห์ร่างกาย สำหรับ Express.
สปริง mvc พร้อมสปริงบูต
คุณสามารถใช้บทช่วยสอนนี้กับเซิร์ฟเวอร์ HTTP API ที่ตั้งค่าไว้แล้วหรือใช้รหัสเซิร์ฟเวอร์ Koa HTTP แบบง่ายต่อไปนี้
const Koa = require('koa'); const bodyParser = require('koa-body'); const app = new Koa(); const router = new (require('koa-router'))(); // helper for returning errors in routes app.context.error = function(code, obj) { this.status = code; this.body = obj; }; // add koa-body middleware to parse JSON and form-data body app.use(bodyParser({ enableTypes: ['json', 'form'], multipart: true, formidable: { maxFileSize: 32 * 1024 * 1024, } })); // Routes... // connect defined routes as middleware to Koa app.use(router.routes()); // our app will listen on port 3000 app.listen(3000); console.log(' API listening on 3000');
อย่างไรก็ตามนี่ไม่ใช่การตั้งค่าการใช้งานจริง (คุณควรใช้ไฟล์ การบันทึก , บังคับใช้ การอนุญาต , ด้ามจับ ข้อผิดพลาด ฯลฯ ) แต่โค้ดสองสามบรรทัดนี้ใช้ได้ดีกับตัวอย่างที่ฉันจะแสดงให้คุณเห็น
หมายเหตุ: ตัวอย่างโค้ดทั้งหมดใช้ Koa แต่รหัสตรวจสอบข้อมูลจะใช้ได้กับ Express เช่นกัน ไลบรารี datalize ยังมีตัวอย่างสำหรับการใช้งานการตรวจสอบความถูกต้องของฟอร์ม Express
สมมติว่าคุณมีเว็บเซิร์ฟเวอร์ Koa หรือ Express และจุดสิ้นสุดใน API ของคุณที่สร้างผู้ใช้ที่มีหลายช่องในฐานข้อมูล ต้องระบุบางช่องและบางช่องสามารถมีได้เฉพาะค่าหรือต้องจัดรูปแบบให้ถูกต้อง
คุณสามารถเขียนตรรกะง่ายๆดังนี้:
/** * @api {post} / Create a user * ... */ router.post('/', (ctx) => { const data = ctx.request.body; const errors = {}; if (!String(data.name).trim()) { errors.name = ['Name is required']; } if (!(/^[-0-9a-zA-Z.+_] [email protected] [-0-9a-zA-Z.+_]+.[a-zA-Z]{2,}$/).test(String(data.email))) { errors.email = ['Email is not valid.']; } if (Object.keys(errors).length) { return ctx.error(400, {errors}); } const user = await User.create({ name: data.name, email: data.email, }); ctx.body = user.toJSON(); });
ตอนนี้เรามาเขียนโค้ดนี้ใหม่และตรวจสอบความถูกต้องของคำขอนี้โดยใช้ datalize:
const datalize = require('datalize'); const field = datalize.field; /** * @api {post} / Create a user * ... */ router.post('/', datalize([ field('name').trim().required(), field('email').required().email(), ]), (ctx) => { if (!ctx.form.isValid) { return ctx.error(400, {errors: ctx.form.errors}); } const user = await User.create(ctx.form); ctx.body = user.toJSON(); });
สั้นกว่าสะอาดกว่าอ่านง่ายมาก ด้วย datalize คุณสามารถระบุรายการของเขตข้อมูลและเชื่อมโยงกับฟิลด์เหล่านั้นได้มาก กฎ (ฟังก์ชันที่ทำให้เกิดข้อผิดพลาดหากอินพุตไม่ถูกต้อง) หรือ ตัวกรอง (ฟังก์ชันที่จัดรูปแบบข้อมูลเข้า) ตามที่คุณต้องการ
สถานะของวงการเพลง
กฎและตัวกรองจะดำเนินการตามลำดับเดียวกันกับที่กำหนดไว้ดังนั้นหากคุณต้องการตัดสตริงสำหรับช่องว่างก่อนจากนั้นตรวจสอบว่ามีค่าหรือไม่คุณต้องกำหนด .trim()
ก่อนหน้า .required()
.
จากนั้น Datalize จะสร้างออบเจ็กต์ (พร้อมใช้งานเป็น .form
ในอ็อบเจ็กต์บริบทที่กว้างขึ้น) โดยมีเพียงฟิลด์ที่คุณระบุดังนั้นคุณจึงไม่ต้องแสดงรายการอีก .form.isValid
คุณสมบัติจะบอกคุณว่าการตรวจสอบความถูกต้องสำเร็จหรือไม่
หากเราไม่ต้องการตรวจสอบว่าแบบฟอร์มถูกต้องหรือไม่กับทุกคำขอเราสามารถเพิ่มมิดเดิลแวร์ส่วนกลางซึ่งจะยกเลิกคำขอได้หากข้อมูลไม่ผ่านการตรวจสอบความถูกต้อง
ในการทำเช่นนี้เราเพียงแค่เพิ่มโค้ดชิ้นนี้ในไฟล์ ไฟล์ bootstrap ที่เราสร้างอินสแตนซ์แอป Koa / Express
const datalize = require('datalize'); // set datalize to throw an error if validation fails datalize.set('autoValidate', true); // only Koa // add to very beginning of Koa middleware chain app.use(async (ctx, next) => { try { await next(); } catch (err) { if (err instanceof datalize.Error) { ctx.status = 400; ctx.body = err.toJSON(); } else { ctx.status = 500; ctx.body = 'Internal server error'; } } }); // only Express // add to very end of Express middleware chain app.use(function(err, req, res, next) { if (err instanceof datalize.Error) { res.status(400).send(err.toJSON()); } else { res.send(500).send('Internal server error'); } });
และเราไม่จำเป็นต้องตรวจสอบว่าข้อมูลถูกต้องอีกต่อไปเนื่องจาก datalize จะดำเนินการให้เรา หากข้อมูลไม่ถูกต้องข้อมูลจะส่งคืนข้อความแสดงข้อผิดพลาดที่จัดรูปแบบพร้อมรายการฟิลด์ที่ไม่ถูกต้อง
ได้คุณยังตรวจสอบความถูกต้องของพารามิเตอร์การสืบค้นได้อย่างง่ายดายโดยไม่จำเป็นต้องใช้กับ POST
ร้องขอเท่านั้น เราใช้ปุ่ม .query()
วิธีการช่วยเหลือและข้อแตกต่างเพียงอย่างเดียวคือข้อมูลจะถูกเก็บไว้ใน .data
วัตถุแทน .form
.
const datalize = require('datalize'); const field = datalize.field; /** * @api {get} / List users * ... */ router.post('/', datalize.query([ field('keywords').trim(), field('page').default(1).number(), field('perPage').required().select([10, 30, 50]), ]), (ctx) => { const limit = ctx.data.perPage; const where = { }; if (ctx.data.keywords) { where.name = {[Op.like]: ctx.data.keywords + '%'}; } const users = await User.findAll({ where, limit, offset: (ctx.data.page - 1) * limit, }); ctx.body = users; });
นอกจากนี้ยังมีวิธีการช่วยเหลือสำหรับการตรวจสอบพารามิเตอร์ .params()
ข้อมูลแบบสอบถามและแบบฟอร์มสามารถตรวจสอบความถูกต้องร่วมกันได้โดยส่งข้อมูลกลางสองตัวของข้อมูลใน .post()
ของเราเตอร์ วิธี.
องค์ประกอบการออกแบบคืออะไร
จนถึงตอนนี้เราได้ใช้ข้อมูลง่ายๆในการตรวจสอบความถูกต้องของฟอร์ม Node.js ตอนนี้เรามาลองฟิลด์ที่ซับซ้อนมากขึ้นเช่นอาร์เรย์อ็อบเจ็กต์ที่ซ้อนกัน ฯลฯ :
const datalize = require('datalize'); const field = datalize.field; const DOMAIN_ERROR = 'Email's domain does not have a valid MX (mail) entry in its DNS record'; /** * @api {post} / Create a user * ... */ router.post('/', datalize([ field('name').trim().required(), field('email').required().email().custom((value) => { return new Promise((resolve, reject) => { dns.resolve(value.split('@')[1], 'MX', function(err, addresses) { if (err || !addresses || !addresses.length) { return reject(new Error(DOMAIN_ERROR)); } resolve(); }); }); }), field('type').required().select(['admin', 'user']), field('languages').array().container([ field('id').required().id(), field('level').required().select(['beginner', 'intermediate', 'advanced']) ]), field('groups').array().id(), ]), async (ctx) => { const {languages, groups} = ctx.form; delete ctx.form.languages; delete ctx.form.groups; const user = await User.create(ctx.form); await UserGroup.bulkCreate(groups.map(groupId => ({ groupId, userId: user.id, }))); await UserLanguage.bulkCreate(languages.map(item => ({ languageId: item.id, userId: user.id, level: item.level, )); });
หากไม่มีกฎในตัวสำหรับข้อมูลที่เราต้องตรวจสอบความถูกต้องเราสามารถสร้างกฎการตรวจสอบข้อมูลที่กำหนดเองโดยใช้ .custom()
วิธีการ (ชื่อดีใช่มั้ย) และเขียนตรรกะที่จำเป็นที่นั่น สำหรับวัตถุที่ซ้อนกันจะมี .container()
วิธีการที่คุณสามารถระบุรายการของเขตข้อมูลในลักษณะเดียวกับใน datalize()
ฟังก์ชัน คุณสามารถซ้อนคอนเทนเนอร์ภายในคอนเทนเนอร์หรือเสริมด้วย .array()
ตัวกรองซึ่งจะแปลงค่าเป็นอาร์เรย์ เมื่อ .array()
ใช้ตัวกรองโดยไม่มีคอนเทนเนอร์กฎหรือตัวกรองที่ระบุจะถูกนำไปใช้กับทุกค่าในอาร์เรย์
ดังนั้น .array().select(['read', 'write'])
จะตรวจสอบว่าทุกค่าในอาร์เรย์เป็น 'read'
หรือไม่ หรือ 'write'
และหากไม่มีก็จะแสดงรายการดัชนีทั้งหมดที่มีข้อผิดพลาด สวยดีใช่มั้ย?
PUT
/ PATCH
เมื่อพูดถึงการอัปเดตข้อมูลของคุณด้วย PUT
/ PATCH
(หรือ POST
) คุณไม่จำเป็นต้องเขียนตรรกะกฎและตัวกรองใหม่ทั้งหมด คุณเพียงแค่เพิ่มตัวกรองพิเศษเช่น .optional()
หรือ .patch()
ซึ่งจะลบฟิลด์ใด ๆ ออกจากอ็อบเจ็กต์บริบทหากไม่ได้กำหนดไว้ในคำขอ (.optional()
จะทำให้เป็นทางเลือกเสมอในขณะที่ .patch()
จะทำให้เป็นทางเลือกก็ต่อเมื่อวิธีการขอ HTTP คือ PATCH
) คุณสามารถเพิ่มตัวกรองพิเศษนี้เพื่อให้ใช้ได้ทั้งการสร้างและการอัปเดต ข้อมูลในฐานข้อมูลของคุณ
const datalize = require('datalize'); const field = datalize.field; const userValidator = datalize([ field('name').patch().trim().required(), field('email').patch().required().email(), field('type').patch().required().select(['admin', 'user']), ]); const userEditMiddleware = async (ctx, next) => { const user = await User.findByPk(ctx.params.id); // cancel request here if user was not found if (!user) { throw new Error('User was not found.'); } // store user instance in the request so we can use it later ctx.user = user; return next(); }; /** * @api {post} / Create a user * ... */ router.post('/', userValidator, async (ctx) => { const user = await User.create(ctx.form); ctx.body = user.toJSON(); }); /** * @api {put} / Update a user * ... */ router.put('/:id', userEditMiddleware, userValidator, async (ctx) => { await ctx.user.update(ctx.form); ctx.body = ctx.user.toJSON(); }); /** * @api {patch} / Patch a user * ... */ router.patch('/:id', userEditMiddleware, userValidator, async (ctx) => { if (!Object.keys(ctx.form).length) { return ctx.error(400, {message: 'Nothing to update.'}); } await ctx.user.update(ctx.form); ctx.body = ctx.user.toJSON(); });
ด้วยตัวกลางง่ายๆสองตัวเราสามารถเขียนตรรกะส่วนใหญ่สำหรับทุกคน POST
/ PUT
/ PATCH
วิธีการ userEditMiddleware()
ฟังก์ชันตรวจสอบว่าระเบียนที่เราต้องการแก้ไขมีอยู่หรือไม่และแสดงข้อผิดพลาดเป็นอย่างอื่น แล้ว userValidator()
ทำการตรวจสอบความถูกต้องสำหรับจุดสิ้นสุดทั้งหมด สุดท้าย .patch()
ตัวกรองจะลบฟิลด์ใด ๆ ออกจาก .form
ออบเจ็กต์หากไม่ได้กำหนดไว้และถ้าเมธอดของคำขอคือ PATCH
ในตัวกรองแบบกำหนดเองคุณสามารถรับค่าของช่องอื่น ๆ และทำการตรวจสอบความถูกต้องตามนั้น คุณยังสามารถรับข้อมูลใด ๆ จากออบเจ็กต์บริบทเช่นคำขอหรือข้อมูลผู้ใช้เนื่องจากข้อมูลทั้งหมดมีให้ในพารามิเตอร์การเรียกกลับของฟังก์ชันที่กำหนดเอง
ไลบรารีครอบคลุมชุดกฎและตัวกรองพื้นฐาน แต่คุณสามารถลงทะเบียนตัวกรองส่วนกลางที่กำหนดเองซึ่งคุณสามารถใช้กับช่องใดก็ได้ดังนั้นคุณไม่จำเป็นต้องเขียนรหัสเดิมซ้ำแล้วซ้ำเล่า:
const datalize = require('datalize'); const Field = datalize.Field; Field.prototype.date = function(format = 'YYYY-MM-DD') { return this.add(function(value) { const date = value ? moment(value, format) : null; if (!date || !date.isValid()) { throw new Error('%s is not a valid date.'); } return date.format(format); }); }; Field.prototype.dateTime = function(format = 'YYYY-MM-DD HH:mm') { return this.date(format); };
ด้วยตัวกรองที่กำหนดเองทั้งสองนี้คุณสามารถเชื่อมโยงฟิลด์ของคุณด้วย .date()
หรือ .dateTime()
ตัวกรองเพื่อตรวจสอบการป้อนวันที่
ไฟล์สามารถตรวจสอบความถูกต้องโดยใช้ datalize: มีตัวกรองพิเศษสำหรับไฟล์เช่น .file()
, .mime()
และ .size()
คุณจึงไม่ต้องจัดการไฟล์แยกกัน
powerpivot ใน excel คืออะไร
ฉันใช้การตรวจสอบความถูกต้องของฟอร์ม datalize สำหรับ Node.js ในโปรเจ็กต์การผลิตหลายโครงการแล้วสำหรับทั้ง API ขนาดเล็กและขนาดใหญ่ ช่วยให้ฉันสามารถส่งมอบโปรเจ็กต์ที่ยอดเยี่ยมได้ตรงเวลาและมีความเครียดน้อยลงในขณะเดียวกันก็ทำให้สามารถอ่านและบำรุงรักษาได้มากขึ้น ในโครงการหนึ่งฉันเคยใช้มันเพื่อตรวจสอบข้อมูลสำหรับข้อความ WebSocket ด้วยการเขียน Wrapper แบบธรรมดารอบ ๆ Socket.IO และการใช้งานก็ค่อนข้างเหมือนกับการกำหนดเส้นทางใน Koa ดังนั้นมันก็ดี หากมีความสนใจเพียงพอฉันอาจเขียนบทช่วยสอนสำหรับสิ่งนั้นด้วย
ฉันหวังว่าบทช่วยสอนนี้จะช่วยคุณและฉันสร้าง API ที่ดีขึ้นใน Node.js ด้วยข้อมูลที่ผ่านการตรวจสอบอย่างสมบูรณ์แบบ ไม่มีปัญหาด้านความปลอดภัย หรือข้อผิดพลาดภายในเซิร์ฟเวอร์ และที่สำคัญที่สุดฉันหวังว่ามันจะช่วยคุณประหยัดเวลาได้มากพอที่จะต้องลงทุนในการเขียนฟังก์ชันพิเศษสำหรับการตรวจสอบแบบฟอร์มโดยใช้ JavaScript
Node.js เป็นแพลตฟอร์มส่วนหลัง ตามความหมายของชื่อแอป Node.js จะเขียนด้วย JavaScript (JS) หรือภาษาใด ๆ ที่สามารถรวบรวมหรือแปลงไฟล์ได้
การคำนวณที่ใช้ CPU มากทำงานได้ไม่ดีกับ Node.js เพราะจะบล็อกการวนซ้ำของเหตุการณ์
วิธีการสร้างภาษาโปรแกรมของคุณเอง
ผู้ใช้สามารถส่งข้อมูลประเภทใดก็ได้ไปยังส่วนหลัง - อาจจะไม่ได้รับการตรวจสอบความถูกต้องที่ส่วนหน้าหรืออาจส่งโดยตรงผ่าน API ของคุณ ข้อมูลนี้ได้รับส่วนใหญ่เป็นข้อความธรรมดาหรือในรูปแบบไบนารีที่ส่วนหลังและต้องแยกวิเคราะห์และตรวจสอบเพื่อป้องกันข้อผิดพลาดที่เกิดจากการป้อนข้อมูลของผู้ใช้ที่ไม่ถูกต้อง / เป็นอันตราย
Express เป็นเว็บเฟรมเวิร์กที่ใช้บน Node.js ในขณะที่ Node.js เป็นสภาพแวดล้อมของเซิร์ฟเวอร์สำหรับเรียกใช้ JavaScript ที่ส่วนหลัง
Node.js มีกรณีการใช้งานมากมาย แต่เหมาะที่สุดสำหรับแอปแบบเรียลไทม์ (เช่นการแชทการสตรีมข้อมูลบริการการทำงานร่วมกัน) เว็บแอปที่แสดงผลฝั่งเซิร์ฟเวอร์ CLI และ API
เพื่อให้แน่ใจว่ารูปแบบและประเภทของข้อมูลอินพุตถูกต้องข้อมูลนั้นมีเฉพาะค่าที่อนุญาตเป็นต้นข้อมูลนั้นจะต้องได้รับการตรวจสอบความถูกต้อง มิฉะนั้นคุณอาจประสบปัญหาเมื่อแทรกลงในฐานข้อมูล การตรวจสอบความถูกต้องยังป้องกันการรั่วไหลของความปลอดภัยที่เกิดจากข้อมูลผู้ใช้ที่เป็นอันตราย