JSON Toolkit

שאלות נפוצות על שיתוף פעולה בצוות: חוזים, קונפיגורציה ו-fixtures

שורה תחתונה: סגנון שמות, פורמטי זמן, סמנטיקת null, צורות enum, פורמטי קונפיגורציה, ארגון fixtures וקונפליקטים במיזוג — שתים-עשרה פשרות שצוותים באמת מתווכחים עליהן.

בינוניכ-12 דקות קריאהפורסם 2026-10-30עודכן 2026-10-30
עטיפה לשאלות הנפוצות על שיתוף פעולה בצוות

שורה תחתונה: סגרו את אלה פעם אחת במוסכמת צוות — מעטפת {"data":…,"meta":…} עם קודי סטטוס HTTP, סגנון שמות אחד בכל האתר, חותמות זמן RFC 3339 עם אזור זמן, ו-enum של מחרוזות — ואז פתחו כל API חדש מול אותו חוזה רק על ידי הוספת שדות, בלי לשנות או למחוק אותם.

אין תשובה נכונה אחת לשאלות האלה, אבל לצוות חייבת להיות תשובה אחת — אחרת כל API חדש מתחיל את אותו ויכוח מחדש.

1. חוזי API

איזה מבנה צריך להחזיר API?

שלוש צורות נפוצות, לכל אחת מחיר:

צורה דוגמה יתרונות חסרונות
נתונים גולמיים [{...}, {...}] פשוט לא יכול לשאת מטא-נתונים
מעטפה קבועה {"code":0,"message":"ok","data":{...}} טיפול אחיד בשגיאות קוד עסקי משכפל את סטטוס ה-HTTP
מעטפת משאב {"data":{...},"meta":{...},"links":{...}} ניתן להרחבה, סמנטיקה ברורה עוד רמת קינון אחת

ל-API עסקיים פנימיים, העדיפו "מעטפת משאב + קודי סטטוס HTTP שמבטאים את התוצאה":

{
  "data": [{ "id": "1", "name": "示例" }],
  "meta": { "total": 128, "page": 2, "pageSize": 20 }
}

לשגיאות, השתמשו בקוד סטטוס HTTP בתוספת גוף שגיאה מובנה במקום לקנן עוד code:

{
  "error": {
    "type": "validation_failed",
    "message": "请求参数校验失败",
    "details": [
      { "path": "/email", "reason": "格式不正确" }
    ]
  }
}

נקודה מרכזית: קודי סטטוס HTTP כבר מבטאים הצלחה או כישלון, כך שקוד עסקי הוא כפילות. כששתי המערכות דרות יחד, חוסר עקביות כמו "201 אבל code הוא 500" הוא כמעט בלתי נמנע.

הימנעו ממערכים חשופים. עם מערך ברמה העליונה אי אפשר לצרף פיצול לעמודים, סכומים או cursors, והוספה שלהם מאוחר יותר פירושה לשנות כל קורא.

האם שמות שדות צריכים להשתמש ב-snake_case או ב-camelCase?

בחרו אחד, החילו אותו בכל האתר, ולעולם אל תערבבו ביניהם במסמך JSON אחד.

סגנון אקוסיסטם נפוץ דוגמה
camelCase JavaScript / TypeScript / Java userName, createdAt
snake_case Python / Ruby / Go (חלקית) / עמודות מסד נתונים user_name, created_at
kebab-case נדיר; מפתחות עם מקף מסורבלים לגישה user-name

קריטריונים:

  1. מי צורך את ה-JSON הזה: בחרו camelCase כשהחזית דומיננטית, snake_case כשה-pipelines של נתונים ושירותי Python דומיננטיים;
  2. האם זה ממופה ישירות לעמודות מסד נתונים: snake_case חוסך שכבת המרה כשמעבירים מבני טבלה כמו שהם;
  3. המשכיות של מערכות קיימות: שמרו על מה שה-API הקיים משתמש בו; עקביות גוברת על נכונות.

אם באמת חייבים להמיר, עשו זאת בגבול (שער או שכבת בקשות בחזית) במקום לפזר קריאות toCamelCase בקוד העסקי.

איזה פורמט צריכים שדות זמן?

השתמשו במחרוזות RFC 3339 / ISO 8601 עם היסט אזור זמן:

{
  "createdAt": "2026-10-30T11:37:57+08:00",
  "updatedAt": "2026-10-30T03:37:57Z"
}

נקודות מרכזיות:

  • כללו את אזור הזמן: 2026-10-30 11:37:57 בלי אזור יישבר בהכרח בתרחישים חוצי-אזורי זמן;
  • השתמשו ב-Z או בהיסט באופן עקבי: שניהם נכונים, אבל אל תערבבו ביניהם באותו API;
  • הימנעו מחותמות זמן מספריות: אם זה בשניות או במילישניות, ואם שניות עיבור נכללות, כל צוות צריך לפרש מחדש. כשצריך קומפקטיות, השתמשו במספר שלם במילישניות, אבל קבעו את יחידת המידה בתיעוד.

העדיפו שמות שדות עם סיומת At כמו createdAt / updatedAt / deletedAt, כך שברור ממבט ראשון שהערך הוא נקודת זמן ולא משך. למשכים השתמשו ב-timeoutMs, ttlSeconds — שימו את היחידה בשם.

האם nulls צריכים להיות null או שדה שהושמט?

זה תלוי אם "השדה הזה בעל משמעות":

סמנטיקה צורה הערות
השדה קיים אבל אין לו ערך עדיין "name": null אומר במפורש "נבדק וזה ריק"
השדה לא רלוונטי למשאב הזה השמטה למשל, משתמש רגיל לא צריך שיהיה לו vipExpireAt
עדכון חלקי (PATCH) השמטה = אל תשנה רק null פירושו "נקה" כאן

המקרה השלישי הוא הנפוץ ביותר להתעלמות ממנו. בבקשת PATCH:

{ "nickname": null }

זה אומר "נקה את הכינוי", בעוד שהשמטת nickname מגוף הבקשה אומרת "אל תיגע בכינוי". אם מתייחסים לשניהם כ"נקה", משתמש שמשנה את האימייל שלו ימחק את הכינוי שלו.

עוד פעם: אל תשתמשו ב-undefined. זה לא ערך JSON תקין, ו-JSON.stringify משמיט את המפתח לגמרי, כך שההתנהגות תואמת ל"השמטה" בעוד הקוד נראה כמו "ערך ריק הועבר במפורש".

איך צריכים להיקרא שדות בוליאניים?

השתמשו בקידומות is / has / can / should והימנעו משלילות.

{
  "isActive": true,
  "hasPassword": false,
  "canEdit": true
}

שלושה לקחים:

  1. בלי שלילות: isDisabled: false מכריח את הקורא להפוך אותו פעם אחת; isEnabled: true ישיר יותר. שלילה כפולה (isNotDisabled) היא אסון;
  2. אל תשתמשו במספרים לבוליאנים: "enabled": 1 מכריח כל צרכן לכתוב === 1 פעם אחת;
  3. אל תשתמשו במחרוזות: "enable": "true" הוא truthy ב-JavaScript, ו- if (data.enable) גם נכון עבור "false"; באגים כאלה קשים מאוד לאיתור.

האם שדות enum צריכים להשתמש במספרים או במחרוזות?

השתמשו במחרוזות אלא אם יש אילוץ ברור של אחסון או רוחב פס.

{ "status": "active" }

בהשוואה ל-{ "status": 1 }, מחרוזות מנצחות כי:

  • לוגים, לכידות מנות ומסדי נתונים ניתנים לקריאה ישירה בלי לחפש טבלת מיפוי;
  • הוספת ערך enum לא משנה את משמעות הערכים הקיימים (הכנסת ערך באמצע enum מספרי מזיזה הכל);
  • החזית לא צריכה לתחזק מיפוי 1 → 'active' מסונכרן.

המחיר הוא כמה בייטים נוספים, שהם כמעט זניחים אחרי דחיסה.

פרקטיקה נלווית: השתמשו באותיות קטנות + קווים תחתונים לערכי enum של מחרוזות (pending_review), והגבילו אותם עם enum ב-Schema כך שערכים לא תקינים יידחו בשלב האימות.

2. קונפיגורציה ו-fixtures

האם קונפיגורציה צריכה להיות JSON, YAML או TOML?

בחרו לפי מטרה, לא לפי העדפה:

פורמט טוב ל גרוע ל
JSON קריאה וכתיבה פרוגרמטיות, נתונים במבנה קפדני, אימות Schema עריכה ידנית תכופה (הערות אסורות)
YAML קונפיגורציית פריסה מקוננת לעומק (K8s) הזחה שנכתבת ביד נוטה לטעויות; yes/no הופכים לבוליאניים
TOML קונפיגורציית תלויות וכלים שטוחה (Cargo.toml, pyproject.toml) קריאות ירודה לקינון עמוק
JSONC קונפיגורציית עורך שצריכה הערות (tsconfig.json) חציית גבולות מערכות

טעות נפוצה בצוותים היא לאחסן קונפיגורציה עסקית ב-YAML — ההמרה המשתמעת של YAML (1.0 הופך למספר, NO הופך לבוליאני, 2026-10-30 הופך לתאריך) מפיקה תוצאות שונות בין מפרסים.

אם הקונפיגורציה חייבת להיות מאומתת בקפדנות על ידי תוכנית, בחרו JSON + Schema, ותעדו הערות דרך שדה _comment או תיעוד נפרד.

איך לארגן fixtures לבדיקות?

ארגנו לפי "בסיס אחד + שינויים מינימליים", לא לפי העתקת JSON ענק לכל מקרה בדיקה.

fixtures/
├─ users/
│  ├─ base.json              # Baseline user object
│  ├─ no-email.json          # Only email is missing
│  └─ invalid-age.json       # Only age is out of range
└─ fixtures.ts               # Utility functions for loading and shallow merging
import baseUser from './users/base.json';

export function makeUser(overrides: Partial<User> = {}): User {
  return { ...baseUser, ...overrides };
}

כך מקרה בדיקה חדש צריך לכתוב רק את השדות השונים, ושינוי שדה בבסיס מעדכן כל מקרה אוטומטית.

שלושה כללים:

  1. fixtures חייבים לעבור אימות Schema: קובץ הבסיס עצמו צריך להיות נתונים תקינים;
  2. אל תייצאו נתונים אמיתיים מפרודקשן: מספרי טלפון, מספרי זהות וכתובות הם כולם מידע אישי;
  3. fixtures שייכים לבקרת גרסאות אבל חייבים להישאר קטנים: קובץ בודד מעל כמה עשרות KB ראוי לקיצוץ או לייצור.

איך מפחיתים קונפליקטים במיזוג בקבצי JSON?

קונפליקטים ב-JSON קלים: מעצב זורם את כל הקובץ בבת אחת, כך ששני אנשים שכל אחד משנה שורה אחת מתנגשים על הקובץ כולו.

ארבעה טקטיקות:

  1. אחדו את העיצוב והוסיפו אותו ל-.editorconfig: הזחה עקבית, סיומות שורה ושורה חדשה בסוף מונעות דיפים לא קשורים;
  2. מיינו מפתחות: הסכימו על סדר אלפביתי כך ששדה חדש לא מתנגש בנקודת ההכנסה של מישהו אחר;
  3. פצלו קבצים: שברו config.json ענק אחד לכמה קבצים לפי תחום, ושטח הקונפליקט מתכווץ באופן טבעי;
  4. הימנעו מ-commits של "עצב הכל מחדש": הפרידו עיצוב משינויים עסקיים לשני commits כדי שהסקירה תישאר קריאה.

אם הצוות משתמש בקבצי lock (pnpm-lock.yaml, package-lock.json), אל תמזגו אותם ביד; צרו אותם מחדש:

git checkout --theirs pnpm-lock.yaml
pnpm install

איך שומרים על תאימות גרסאות?

העיקרון הוא "הוסיפו, אל תשנו, אל תמחקו".

שינוי תאימות גישה
הוספת שדה אופציונלי תואם הוסיפו; צרכנים מתעלמים משדות לא מוכרים
הוספת שדה חובה לא תואם העלו גרסה, או ספקו ברירת מחדל
הסרת שדה לא תואם סמנו אותו תחילה כ-deprecated, עקבו אחרי הקוראים, ואז הסירו
שינוי טיפוס שדה לא תואם הוסיפו שם שדה חדש וכתבו כפול בתקופת המעבר
שינוי קבוצת ערכי enum תלוי הוספת ערכים תואמת; הסרה לא

מנגנונים תומכים:

  • צרכנים משתמשים ב"פירוס סלחני": מתעלמים משדות לא מוכרים ומספקים ברירות מחדל לחסרים;
  • השרת שומר שדות ישנים לזמן מה ומחזיר כותרת Deprecation בתשובה כרמז;
  • ב-Schema, אל תסמנו שדות חדשים כ-required, ותייגו שדות deprecated עם deprecated: true.

איך מאמתים חוזים ב-CI?

התייחסו ל-Schema כחלק מהקוד ואמתו אותו בכל commit.

# Validate sample data against the Schema (using ajv-cli)
npx ajv-cli validate -s schemas/user.json -d "fixtures/users/*.json" --strict=false

הריצו שלושה דברים ב-CI:

  1. תוקפות ה-Schema עצמו: האם הצהרת $schema תקינה והאם $ref נפתר;
  2. האם ה-fixtures תואמים ל-Schema: מבטיח שנתוני הבדיקה לא סוטים;
  3. האם החוזה תואם לאחור: השוו לגרסה הקודמת ובדקו שדות שהוסרו או טיפוסים שהשתנו.

הפריט השלישי דורש תמיכת כלים (כמו openapi-diff או json-schema-diff); בלעדיה, לפחות השוו שינויים במערכי required ובקבוצות המפתחות של properties עם סקריפט.

3. עיון מהיר

שאלה המלצה
מבנה תשובה {"data":..., "meta":...}, עם קודי סטטוס HTTP לשגיאות
סגנון שמות camelCase (חזית קודם) או snake_case (נתונים קודם), עקבי בכל האתר
פורמט זמן מחרוזות RFC 3339 עם אזור זמן, שמות שדות שמסתיימים ב-At
Nulls השתמשו ב-null כשאין ערך, השמיטו שדות לא רלוונטיים, השמטה ב-PATCH פירושה "אל תשנה"
שמות בוליאניים קידומות is/has/can, בלי שלילות, בלי 0/1
Enums מחרוזות, אותיות קטנות עם קווים תחתונים, הוסיפו enum ב-Schema
פורמט קונפיגורציה JSON לאימות פרוגרמטית, TOML או JSONC לעריכה ידנית
Fixtures בסיס אחד + overrides בשינוי מינימלי, תקינים מול ה-Schema
קונפליקטים במיזוג אחדו עיצוב, מיינו מפתחות, פצלו קבצים
תאימות גרסאות הוסיפו, אל תשנו, אל תמחקו; סמנו deprecated לפני הסרה