This is the fifth day of my participation in Gwen Challenge

What is theJSON Schema

How to define it? To be honest, I didn’t realize it until I finished writing it. It’s just like JSON Schema, so I’ll just say ta is JSON Schema.

Serious definition

Json Schema defines a set of terms and rules for defining Json metadata, which is expressed as Json data. Json metadata defines specifications that Json data must meet, including membership, structure, type, and constraints.

Why am I writing this

It has always been a very “confusing” thing to coordinate with the background. The main reason is that the communication cost is too high, which mainly focuses on the communication of interface documents. Either this parameter value does not need to be passed, or that value must be written, or some parameters must be what type. Also don’t carry out the document, so also not rigorous, he has a document, but not “clear”, still can’t avoid the communication, or have changed his don’t update, after all, formulate rules and strict adherence to can’t directly “comfortable” word of mouth, is the convenience, but it is very dangerous, you once synchronization disorder, function is write wrong, the waste of manpower and hollow white teeth, The mental breakdown caused by the lack of reasoning was simply unacceptable. Instead of enduring the confusion, I found a way to “change”. So, THAT’s what I did.

So let’s start serving

Design ideas

First of all, I expect him or her to do two things for me when I ask:

  1. Compliance with background requirements: Input parameters (sent to background data) are verified at request time.
  2. Does not meet the requirements of the front desk: in the request to return the data, to the reference (background returned data) for the corresponding verification.

Then, add a feature

  1. configurable

☺ next.

Configuration method

Post the configuration data first, and then we’ll analyze it:

import BaseApiShape from './baseApiCheck'


let config = {
    fetchTestDataList: {
        reqParam: {
            type: {},// Do not write to objects by default
            p1: {
                type: "string".// What type is required, pass in the type name, or simply take the type of the variable passed in
            },
            p2: {
                type: {},},p13: {
                type: "string",}},resParam: {
            p1: {
                type: []},p2: {
                type: {},}}},fetchLightDetail: {
        resParam: {
            type: []._item: {
                lightItems: {
                    type: []._item: {
                        exclude: {
                            type: "boolean",}}},aaaaa: {
                    type: {},}}}}}export default new BaseApiShape({ config })

Copy the code

Analysis:

The above two validators are very typical and represent all of my validators completely:

  • fetchTestDataList
  • fetchLightDetail

The general structure looks like this:

    {
        reqParam: {... },resParam: {... }}Copy the code

ReqParam and resParam represent the input parameter (front => back) and the output parameter (back => front) respectively.

Then let’s take a closer look:

Here are the rules of engagement:

For example, if you’re passing a string, you can tell me what type it is or you can just give me a string variable and I can pick the type internally, just arbitrarily.

_item: Represents an element in an array. This element is present only in the array type.

Case 1:

    {
        // A
        type: {},
        // B
        p1: {
            type: "string".// C
        },
        p2: {
            type: {},},p13: {
            type: "string",}}Copy the code

B: Yes, it is.

  • A:typeIt means that this whole thing is an object.
  • B:p1Denotes that the structure has to be namedp1Properties.
  • C:p1The inside of thetype, it meansp1What type it should be.

Now let’s talk about case two

Case 2:

    {
        // A
        type: [].// B
        _item: {
             // C
            lightItems: {
                type: []._item: {
                    exclude: {
                        type: "boolean",}}},aaaaa: {
                type: {},}}}Copy the code

B: Yes, it is.

  • A:typeThe whole thing is an array. .
  • B:_itemRepresents an element in an array.
  • C:lightItemsNote that this is an array, this constitutes a nested array, super complex, it does not matter, support! (This is already deep, deep? It’s time to talk to the guys backstage.)

Let’s do it.

In order tofetchLightDetailAs an example

The returned argument looks like this:

[{
    lightName: "test_lightName_0".comment: "test_comment_0".lightItems: [{lightItemId: 1.lightType: 0.baseSelect: 1.exclude: 0}}]]Copy the code

Then the verification result is:

Already very warm heart said the problem out, enough, later again elegant, anyway the idea basically ground.

Post the base class internal implementation without much polish, no penetration, probably buggy (should be positive)

let typeArr = [
    "bigInt"."boolean"."string"."symbol"."undefined"."object"."number"."function"."array"
]
export default class BaseApiShape {
    constructor(props) {
        const { config } = props;
        this.config = config;
        this.checkReport = []
    }
    process(config) {
        for (let key in config) {
            this[key] = _.cloneDeep(config[key])
        }
    }

    checkReqParams({ apiName, params }) {
        if (apiName in this.config) {
            return this.check({
                required: this.config[apiName].reqParam,
                current: params
            })
        }
    }

    checkResParams({ apiName, params }) {
        if (apiName in this.config) {
            return this.check({
                required: this.config[apiName].resParam,
                current: params
            })
        }
    }
    checkArr({ required, current = [], logPrefix }) {
        current.forEach((item, index) = > {
            this.checkObj({
                required: required,
                current: item,
                logPrefix: logPrefix + ` [${index}] `})})}check({ required = {}, current }) {
        if (required.type === "array" || Array.isArray(required.type)) {
            if (Array.isArray(current)) {
                if (required._item) {
                    this.checkArr({
                        required: required._item,
                        current: current,
                        logPrefix: "Whole"}}})else {
                this.checkReport.push({ property: "Whole".message: 'Require an array! `}}})else {
            this.checkObj({ required, current })
        }
        return this.checkReport;
    }
    // If it is an array, it is an internal element of the array
    checkObj({ required = {}, current = {}, logPrefix }) {
        for (let key in required) {
            let checkOption = required[key];
            if (Object.keys(checkOption).length) {
                const { isRequired = true, type } = checkOption;
                if (type === "array" || Array.isArray(type)) {
                    if (checkOption._item) {
                        this.checkArr({
                            required: checkOption._item,
                            current: current[key],
                            logPrefix: ` ${logPrefix + "- >" + key}`})}continue;
                }
                // check whether it exists
                if(isRequired && ! (keyin current)) {
                    this.checkReport.push({ property: key, message: The required attribute is not specified in the 'parameter:${key}`})}// Check - type
                if((typeArr.indexOf(type) ! = -1) | |typeof type in typeArr || Array.isArray(type)) {
                    let typeTemp;
                    if(typeArr.indexOf(type) ! = -1) {
                        typeTemp = type;
                    } else {
                        typeTemp = typeof type;
                    }
                    if(typeTemp ! = =typeof current[key]) {
                        this.checkReport.push({ property: key, message: `${logPrefix && ('array' + logPrefix)}: Parameter specifies the required attribute type is incorrect, yes-${typeTemp}: no -The ${typeof current[key]}`})}}}}}}Copy the code

conclusion

West for use, the past, “hard”, “abstract” knowledge, after understanding that is actually composed of many “simple”, I don’t believe in coder has not feeling, you technology is strong, you don’t have a “heart”, you are at most is a machine, you technology is weak, you have a “heart”, you also is personal, not too arrogant, not self-pity, slowly learning, Decide a direction toward that diligently, tube ta becomes not 😁, accomplish end.

🌰 integrates this functionality