תנאים עם משתני זרימה

כרגע מוצג התיעוד של Apigee Edge.
כניסה למסמכי התיעוד של Apigee X.
מידע

הצהרות מותנות הן מבנה בקרה משותף בכל שפות התכנות. בדומה לשפת תכנות, גם ההגדרה של שרת ה-proxy של ה-API תומכת בהצהרות מותנות לגבי תהליכי עבודה, כללי מדיניות, שלבים וכללי Route Rules. באמצעות הגדרה של הצהרות מותנות, אפשר להגדיר התנהגות דינמית ל-API. ההתנהגות הדינמית הזו מאפשרת לבצע פעולות כמו המרת XML ל-JSON בלבד עבור מכשירים ניידים, או ניתוב לכתובת URL של קצה עורפי על סמך סוג התוכן או פועל ה-HTTP של הודעת הבקשה.

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

הגדרה של הצהרות מותנות

אפשר להטמיע התנהגות מותנית בשרתי proxy של API באמצעות שילוב של conditions וconditions. הצהרה מותנית נוצרת באמצעות רכיב תנאי. התנאי הבא הוא ריק:

<Condition></Condition>

כדי ליצור הצהרה מותנית, מוסיפים אופרטור ומשתנה כדי ליצור את המבנה הבא:

<Condition>{variable.name}{operator}{"value"}</Condition>

אופרטורים מותנים נתמכים כוללים את = (שווה), != (לא שווה) ו-> (גדול מ-). כדי שיהיה קל יותר לקרוא את התנאים, אפשר גם לכתוב אותם כטקסט: equals, notequals, greaterthan.

כשעובדים עם נתיבי URI, אפשר להשתמש ב-~/ או ב-MatchesPath. אפשר גם להתאים ביטויים רגולריים של JavaRegex לאופרטור ~~.

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

משתנים

התנאים עושים את העבודה על ידי הערכה של הערכים של משתנים. משתנה הוא מאפיין של טרנזקציית HTTP שמתבצעת על ידי שרת proxy של API, או מאפיין של הגדרת שרת proxy של API עצמה. בכל פעם ששרת proxy של API מקבל בקשה מאפליקציה, Apigee Edge מאכלס רשימה ארוכה של משתנים שקשורים לדברים כמו זמן המערכת, פרטי הרשת של האפליקציה, כותרות HTTP בהודעות, הגדרת שרת ה-API של שרת ה-API, הפעלות של מדיניות וכן הלאה. כך נוצר הקשר עשיר שבו ניתן להשתמש כדי להגדיר הצהרות מותנות.

במשתנים תמיד מוצג סימון עם נקודות. לדוגמה, כותרות HTTP בהודעת הבקשה זמינות כמשתנים שנקראים request.header.{header_name}. כדי להעריך את הכותרת מסוג Content-type, אפשר להשתמש במשתנה request.header.Content-type. לדוגמה, הקוד request.header.Content-type = "application/json" מציין שסוג התוכן של הבקשה צריך להיות JSON.

נניח שצריך ליצור הצהרה מותנית שתביא לאכיפה של מדיניות רק כאשר הודעת הבקשה היא מסוג GET. כדי ליצור תנאי שמעריך את פועל ה-HTTP של בקשה, צריך ליצור את ההצהרה המותנית שבהמשך. המשתנה בתנאי הזה הוא request.verb. ערך המשתנה הוא GET. האופרטור הוא =.

<Condition>request.verb = "GET"</Condition>
אפשר גם להשתמש:
<Condition>request.verb equals "GET"</Condition>

Edge משתמש בהצהרה כזו כדי להעריך תנאים. בדוגמה שלמעלה מתקבל הערך True אם פועל ה-HTTP המשויך לבקשה הוא GET. אם פועל ה-HTTP המשויך לבקשה הוא POST, אז ההצהרה תקבל את הערך False.

כדי להפעיל התנהגות דינמית, אפשר לצרף תנאים לזרימה, לשלבים ולכללי מסלול.

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

לדוגמה, כדי ליצור תהליך עבודה שמופעל רק כאשר פועל הבקשה הוא GET:

<Flows>
  <Flow name="ExecuteForGETs">
  <Condition>request.verb="GET"</Condition>
  </Flow>
</Flows>

כדי ליצור תהליך אחד ל-GET ושלב אחר ל-POST:

<Flows>
  <Flow name="ExecuteForGETs">
  <Condition>request.verb="GET"</Condition>
  </Flow>
  <Flow name="ExecuteForPOSTs">
  <Condition>request.verb="POST"</Condition>
  </Flow>
</Flows>

כפי שמוצג בדוגמה למטה, אפשר להחיל את התנאי על שלב המדיניות עצמו. התנאי הבא גורם לאכיפה של מדיניות ValidApiKey רק אם הודעת הבקשה היא POST.

<PreFlow name="PreFlow">
    <Request>
        <Step>
            <Condition>request.verb equals "POST"</Condition>
            <Name>VerifyApiKey</Name>
        </Step>
    </Request>
</PreFlow>

אחרי שמגדירים תהליכי עבודה מותנים כאלה, אפשר לצרף אליהם כללי מדיניות, להפעיל שרת proxy של API כדי לאכוף קבוצה אחת של כללי מדיניות עבור בקשות GET, וקבוצה אחרת של כללי מדיניות לבקשות POST.

מידע מקיף זמין במקורות המידע הבאים:

דוגמה 1

בדוגמה הבאה מוצג תהליך מותנה אחד בשם Convert-for-devices, שמוגדר בתהליך התגובה של ProxyEndpoint. מוסיפים את התנאי כרכיב לישות שהתנאי חל עליה. בדוגמה הזו, התנאי הוא רכיב בזרימה. לכן, הזרימה תתבצע בכל פעם שההצהרה תתבצע כ-true.

<Flows>
  <Flow name="Convert-for-devices">
  <Condition>(request.header.User-Agent = "Mozilla")</Condition>
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

לכל בקשה שמתקבלת מאפליקציה, Edge מאחסנת את הערכים של כל כותרות ה-HTTP שנמצאות כמשתנים. אם הבקשה מכילה כותרת HTTP בשם User-Agent, הכותרת והערך שלה מאוחסנים כמשתנה שנקרא request.header.User-Agent.

בהתאם להגדרות ProxyEndpoint שלמעלה, Edge בודק את הערך של המשתנה request.header.User-Agent כדי לראות אם התנאי מקבל ערך True.

אם התנאי מקבל את הערך True, כלומר הערך של המשתנה request.header.User-Agent שווה ל-Mozilla, אז ה-זרימה המותנה מופעלת ותיאכף מדיניות XMLtoJSON שנקראת ConvertToJSON. אחרת, התהליך לא מתבצע, ותגובת ה-XML מוחזרת לאפליקציה ששולחת את הבקשה ללא שינוי (בפורמט XML).

דוגמה 2

נבחן דוגמה ספציפית שבה צריך להמיר הודעות תגובה מ-XML ל-JSON – אבל רק במכשירים ניידים. תחילה, יוצרים את המדיניות שתמיר את התגובה בפורמט XML מ-Weather API ל-JSON:

<XMLToJSON name="ConvertToJSON">
  <Options>
  </Options>
  <OutputVariable>response</OutputVariable>
  <Source>response</Source>
</XMLToJSON>

הגדרת המדיניות שלמעלה מורה לשרת ה-proxy של ה-API לקחת את הודעת התגובה, לבצע המרה מ-XML ל-JSON עם הגדרות ברירת המחדל, ולאחר מכן לכתוב את התוצאה בהודעת התגובה החדשה. (אם ממירים הודעת בקשה מ-XML ל-JSON, פשוט מגדירים את שני הערכים ל-request).

מכיוון שברצונך להמיר תגובות מ-XML ל-JSON, עליך להגדיר תהליך של תגובה מותנית לביצוע ההמרה. לדוגמה, כדי להמיר את כל התגובות מ-XML ל-JSON, לפני שהן מוחזרות לאפליקציית הלקוח, צריך להגדיר את תהליך התגובה הבא של ProxyEndpoint.

<Flows>
  <Flow name="Convert-for-devices">
    <Response>
      <Step><Name>ConvertToJSON</Name></Step>
    </Response>
  </Flow>
</Flows>

כשמפעילים את ה-API באמצעות הבקשה הרגילה, התגובה כתובה בפורמט JSON.

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

בדיקת התהליך המותנה

בבקשה לדוגמה הזו, כותרת ה-HTTP User-Agent מוגדרת כ-Mozilla, וכתוצאה מכך הצהרת המותנית תהיה True והזרימה המותנה Convert-for-devices תופעל.

$ curl -H "User-Agent:Mozilla" http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282

או, כדי להדפיס באופן יפהפה, היכן ש-Python זמין:

$ curl -H "User-Agent:Mozilla" http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282 | python -mjson.tool

תשובה לדוגמה:

. . .

"yweather_forecast": [
         {
              "code": "11",
              "date": "12 Dec 2012",
              "day": "Wed",
              "high": "55",
              "low": "36",
              "text": "Showers"
          },
          {
              "code": "32",
              "date": "13 Dec 2012",
              "day": "Thu",
              "high": "56",
              "low": "38",
              "text": "Sunny"
          }
      ]
  }

. . .

בקשה שנשלחת ללא הכותרת User-Agent או עם ערך שונה מ-Mozilla, תוביל לתשובה בפורמט XML.

$ curl http://{org_name}-test.apigee.net/weather/forecastrss?w=12797282

מוחזרת תגובת ה-XML ללא שינוי.

תשובה לדוגמה:

<yweather:forecast day="Wed" date="12 Dec 2012" low="36" high="55" text="Showers" code="11" /> <yweather:forecast day="Thu" date="13 Dec 2012" low="38" high="56" text="Sunny" code="32" />

התאמת דפוסים

בקטע הזה אנחנו מסבירים איך להשתמש בהתאמת דפוסים עם תנאים בזרימה ב-Apigee.

אופרטורים

בקטע הזה נסביר איך להשתמש באופרטורים הבאים של התאמת דפוסים בהצהרות מותנות:

תואם את:

קודם נבחן את האופרטור המותנה 'תואם' או '~'. שני האופרטורים האלה זהים – הגרסה באנגלית, 'התאמות', נחשבת לאפשרות קריאה יותר.

סיכום: האופרטור 'התאמות' נותן שתי אפשרויות. ניתן להזין את המחרוזת באופן מילולי, או לבצע התאמה של תווים כלליים לחיפוש עם "*". כפי שניתן לצפות, התו הכללי לחיפוש תואם לאפס תווים או יותר. בואו נראה איך זה עובד.

קוד ה-XML הבא מציג תנאי של Step. הפונקציה מיישמת את מדיניות somePolicy כשהתנאי מקבל את הערך True. בדוגמה הזו אנחנו בודקים את המשתנה proxy.pathsuffix, משתנה מובנה ב-Edge ששומר את סיומת הנתיב של הבקשה. עם זאת, שימו לב שאפשר לבדוק את הערך של כל משתנה זרימה שמכיל מחרוזת. לכן, במקרה הזה, אם הנתיב הבסיסי של הבקשה הנכנסת הוא /animals והבקשה היא /animals/cat, אז סיומת הנתיב היא המחרוזת המילולית "/cat".

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix Matches "/cat")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

שאלה:איזו סיומת של נתיב שרת proxy תגרום ל-SomePolicy? יש רק אפשרות אחת.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat

האם המדיניות מיושמת? כן, כי הסיומת של נתיב שרת ה-proxy תואמת בדיוק ל-"/cat". הוא לא יופעל אם הסיומת היא /bat או /dog, "/" או כל דבר אחר.

עכשיו נחשוב על ההצהרה המותנית הבאה שבה אנחנו משתמשים בתו הכללי לחיפוש "*":

<Condition>(proxy.pathsuffix Matches "/*at")</Condition>

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat

האם המדיניות מיושמת? כן, כי התו הכללי לחיפוש תואם לכל תו, ו-""/cat" הוא התאמה.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/bat

האם המדיניות מיושמת? כן, מאחר שהתו הכללי לחיפוש תואם לכל תו, "/bat" מתאים.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/owl

האם המדיניות מיושמת? בהחלט לא – אף על פי שהתו הכללי לחיפוש תואם ל-"o", האותיות "wl" אינן תואמות.

עכשיו נעביר את התו הכללי לחיפוש לסוף הסיומת:

<Condition>(proxy.pathsuffix Matches "/cat*")</Condition>

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat

האם המדיניות מיושמת? כן, כי התו הכללי לחיפוש תואם לאפס תווים כלשהם או יותר.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/bat

האם המדיניות מיושמת? לא, "/bat" אינו התאמה.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat123

האם המדיניות מיושמת? כן, התו הכללי לחיפוש תואם לאפס תווים כלשהם או יותר, ולכן "123" יוצר התאמה.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat/bird/mouse

האם המדיניות מיושמת? כן, כי התו הכללי לחיפוש תואם לאפס תווים כלשהם או יותר, אז "/bird/mouse" יוצרת התאמה. חשוב לשים לב איך ביטוי כזה עלול לגרום לך לצרות כי הוא תואם את כל מה שמופיע אחרי התווים המילוליים!

שאלה: האם האופרטור 'התאמות' הוא תלוי אותיות רישיות?

כן. נניח שיש לכם תנאי כזה:

<Condition>(proxy.pathsuffix Matches "/*At")</Condition>

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat

האם המדיניות מיושמת? לא, התו הכללי לחיפוש תואם לכל אות (ללא קשר לאותיות רישיות), אבל האות a הקטנה לא תואמת ל-A.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/bAt

האם המדיניות מיושמת? כן, הפנייה תואמת.

שאלה: איך מוסיפים תו בריחה (escape) עם האופרטור 'התאמות'?

אפשר להשתמש בתו האחוז "%" כדי לצאת מתווים שמורים. לדוגמה:

<Condition>(proxy.pathsuffix Matches "/c%*at")</Condition>

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat

האם המדיניות מיושמת? לא, האופרטור Matches מחפש את המחרוזת המילולית "c*at".

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/c*at

שאלה:האם המדיניות מבוצעת?

כן, הנתיב הזה תואם לנתיב, למרות שהוא קצת יוצא דופן.

JavaRegex

כמו שאפשר לראות, האופרטור 'התאמות' הוא כלי מצוין במצבים פשוטים. עם זאת, אפשר להשתמש באופרטור JavaRegex או באופרטור '~~'. שני האופרטורים האלה זהים, אבל JavaRegex נחשב לקריא יותר. היא נקראת JavaRegex כי היא מאפשרת להתאים תבניות של ביטויים רגולריים, ו-Edge פועלת לפי אותם כללים כמו המחלקות בחבילת java.util.regex בשפת Java. אופן הפעולה של האופרטור JavaRegex שונה מאוד מהאופרטור Matches, ולכן חשוב לא להתבלבל ביניהם!

Summary (סיכום): האופרטור JavaRegex מאפשר להשתמש בתחביר של ביטויים רגולריים בהצהרות מותנות.

הקוד הבא מציג תנאי של שלב. הפונקציה מריצה את מדיניות somePolicy אם התנאי מקבל את הערך True. בדוגמה הזו אנחנו בודקים את המשתנה proxy.pathsuffix, משתנה מובנה ב-Edge ששומר את סיומת הנתיב של הבקשה. אם הנתיב הבסיסי של הבקשה הנכנסת הוא /animals והבקשה היא /animals/cat, אז הסיומת של הנתיב היא המחרוזת המילולית "/cat".

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix JavaRegex "/cat")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

שאלה:איזו סיומת של נתיב שרת proxy תגרום ל-SomePolicy? בדיוק כמו האופרטור 'התאמות', יש רק אפשרות אחת במקרה הזה.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat

האם המדיניות מיושמת? כן, כי הסיומת של נתיב שרת ה-proxy תואמת בדיוק ל-"/cat". הוא לא יופעל אם הסיומת היא /bat או /dog או משהו אחר.

עכשיו ניצור ביטוי רגולרי באמצעות כמת "*". המכמת הזה תואם לאפס או יותר מהתו הקודם.

<Condition>(proxy.pathsuffix JavaRegex "/c*t")</Condition>

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat

האם המדיניות מיושמת? לא. כמת "*" תואם לאפס או יותר מתוך התו הקודם, שהוא "c".

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/ccccct

האם המדיניות מיושמת? כן, כי התו הכללי לחיפוש תואם לאפס או יותר מהתו הקודם.

בשלב הבא אנחנו משתמשים בכמת "?" שתואם לתו הקודם פעם אחת, או שלא בכלל.

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat

האם המדיניות מיושמת? כן. כמת "?" תואם לאפס או למופע אחד של התו הקודם, שהוא "a".

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/ct

האם המדיניות מיושמת? כן. כמת "?" תואם לאחד או לאף אחד מהתו הקודם. במקרה כזה, אין תו "a" ולכן התנאי מקבל ערך של True.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/caat

האם המדיניות מיושמת? לא. כמת "?" תואם לאחד מהתו הקודם, שהוא "a".

לאחר מכן נשתמש בסגנון "[abc]" או "קיבוץ" של ביטוי רגולרי. הוא תואם לתווים "a", "b" או "c".

<Condition>(proxy.pathsuffix JavaRegex "/[cbr]at")</Condition>

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat

האם המדיניות מיושמת? כן. יש לנו כאן ביטויים רגולריים, והביטוי "[cbr]" תואם ל-"c", ל-"b" או ל-"r". הקריאות האלה גם תואמות ל:

GET http://artomatic-test.apigee.net/matchtest/bat

GET http://artomatic-test.apigee.net/matchtest/rat

אבל זו לא התאמה:

GET http://artomatic-test.apigee.net/matchtest/mat

שאלה: האם האופרטור של JavaRegex תלוי אותיות רישיות?

כן. נניח שיש לכם תנאי כזה:

<Condition>(proxy.pathsuffix JavaRegex "/ca?t")</Condition>

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat

האם המדיניות מיושמת? כן, הביטוי הרגולרי תואם לאפס או לאחד מהתו הקודם - "a".

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cAt

שאלה: האם המדיניות חלה?

לא, מכיוון שהאותיות "A" רישיות אינן תואמות "a" באות קטנה.

MatchesPath

אפשר לציין גם את האופרטור MatchesPath כך '~/'. הוא נראה קצת כמו האופרטורים Matches (~) ו-JavaRegex (~~). אבל MatchesPath הוא שונה לחלוטין.

חשוב לזכור שהאופרטור הזה מסתכל על נתיב בתור סדרה של חלקים. לכן, אם הנתיב הוא: /animals/cats/wild, אפשר לחשוב על הנתיב כמכיל את החלקים "/animals", "/cats" ו-"/wild".

האופרטור MatchesPath מאפשר להשתמש בשני סימנים כלליים לחיפוש: כוכבית אחת (*) וכוכבית כפולה (**). הכוכבית היחידה תואמת לרכיב נתיב אחד. הכוכבית הכפולה תואמת לאחד או יותר מרכיבי הנתיב.

נבחן את הדוגמה הבאה. בדוגמה הזו אנחנו בודקים את המשתנה proxy.pathsuffix, משתנה מובנה ב-Edge ששומר את סיומת הנתיב של הבקשה. עם זאת, שימו לב שאפשר לבדוק את הערך של כל משתנה זרימה שמכיל מחרוזת.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

שאלה:איזו סיומת של נתיב שרת proxy תגרום ל-SomePolicy?

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/animals

שאלה: האם המדיניות חלה?

לא, כי התנאי מחייב רכיב נתיב אחר אחרי '/animals', כפי שצוין על ידי '/*'.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/animals/

האם המדיניות מיושמת? כן, יש בנתיב רכיב נתיב נוסף (החלק שאחרי "/animals/"), אבל הוא פשוט ריק.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/animals/cats

האם המדיניות מיושמת? כן, כי ברור שהנתיב מכיל רכיב ("/cats") שמופיע אחרי "/animals"

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild

שאלה: האם המדיניות חלה?

לא, כי הכוכבית היחידה תואמת רק לאלמנט נתיב אחד, וב-API הזה יש יותר מרכיב אחד אחרי "/animals".

עכשיו נשתמש בכוכבית הכפולה:

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

שאלה:איזו סיומת של נתיב שרת proxy תגרום ל-SomePolicy?

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/animals

האם המדיניות מיושמת? לא, כי התנאי מחייב לפחות רכיב אחד בנתיב שצוין על ידי "/**".

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/animals/

האם המדיניות מיושמת?

כן, יש בנתיב רכיב נתיב נוסף (החלק שאחרי "/animals/"), אבל הוא פשוט ריק.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/animals/cats

האם המדיניות מיושמת?

כן, כי הנתיב כולל לפחות רכיב אחד שמופיע אחרי "/animals"

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild

האם המדיניות מיושמת?

כן, כי הנתיב כולל יותר מרכיב אחד אחרי "/animals"

ערבוב כוכביות

אפשר להשתמש בשילובים של כוכבית אחת (*) וכפולה (**) כדי לצמצם עוד יותר את התאמת הנתיב.

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>(proxy.pathsuffix MatchesPath "/animals/*/wild/**")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

קריאה ל-API:

כל הקריאות האלה ל-API ייצרו התאמה:

GET http://artomatic-test.apigee.net/matchtest/animals/cats/wild/

וגם

GET http://artomatic-test.apigee.net/matchtest/animals/dogs/wild/austrailian

וגם

GET http://artomatic-test.apigee.net/matchtest/animals/birds/wild/american/finches

משאבי API

שירותי RESTful הם אוספים של משאבי API. משאב API הוא מקטע של נתיב ה-URI שמזהה ישות מסוימת שמפתחים יכולים לגשת אליה באמצעות קריאה ל-API. לדוגמה, אם השירות מספק דוחות מזג אוויר ותחזיות מזג אוויר, השירות לקצה העורפי עשוי להגדיר שני משאבי API:

  • http://mygreatweatherforecast.com/reports
  • http://mygreatweatherforecast.com/forecasts

כשיוצרים שרת proxy ל-API (כפי שמוצג בבניית שרת ה-API הראשון של שרת ה-API), לפחות יוצרים כתובת URL בסיסית חלופית שממופה אל השירות לקצה העורפי. לדוגמה:

כתובת URL בסיסית של הקצה העורפי כתובת URL של שרת proxy חדש/שווה ערך ל-API
http://mygreatweatherforecast.com http://{your_org}-{environment}.apigee.net/mygreatweatherforecast

בשלב זה, ניתן לבצע קריאות ל-API לקצה העורפי באמצעות כל אחת מכתובות ה-URL הבסיסיות. אבל כשמשתמשים בכתובת ה-URL של שרת ה-API של שרת ה-API, מתחיל להיות מעניין.

בנוסף לניתוחי API ש-Edge מתחיל לאסוף כשמשתמשים בשרת proxy ל-API, שרתי proxy מאפשרים גם להגדיר תהליכי עבודה מותנים שממופים למשאבים בקצה העורפי. בגדול, "אם מגיעה קריאה ל-GET למשאב /reports, Edge צריך לבצע פעולה כלשהי".

התמונה הבאה מציגה את הבדלי ההתנהגות בין שתי כתובות URL שבסופו של דבר ניגשות לאותו קצה עורפי. אחת היא כתובת ה-URL של המשאב ללא שרת proxy, והשנייה היא שרת proxy של Edge API עם זרימה מותנית לאותו משאב בקצה העורפי. בהמשך מוסבר בפירוט על תהליכי עבודה מותנים.

איך שרתי proxy של API ממופים למשאבים ספציפיים בקצה העורפי

כשכתובת URL של שרת proxy ל-API ממופה לכתובת ה-URL הבסיסית של השירות לקצה העורפי (כשיוצרים את שרת ה-Proxy), אפשר להוסיף תהליכי עבודה מותנים למשאבים מסוימים, כמו המשאבים /reports ו-/forecasts שצוינו קודם.

נניח שרציתם ש-Edge "תבצע פעולה" כאשר שיחות מגיעות למשאבים של /reports או /forecasts. בשלב זה, אתם לא אומרים ל-Edge מה לעשות, אלא רק להקשיב לקריאות למשאבים האלה. אפשר לעשות את זה עם תנאים. בשרת ה-proxy של Edge API אפשר ליצור תהליכי עבודה מותנים ל-/reports ול-/forecasts. למטרות רעיוניות, ה-XML של שרת ה-API הבא של שרת ה-API מראה איך התנאים האלה עשויים להיראות.

<Flows>
    <Flow name="reports">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
    </Flow>
    <Flow name="forecasts">
        <Description/>
        <Request/>
        <Response/>
        <Condition>(proxy.pathsuffix MatchesPath "/forecasts") and (request.verb = "GET")</Condition>
    </Flow>
</Flows>

לפי תנאים אלה, כתוב "כשבקשת GET מגיעה עם /reports ו-/forecasts בכתובת ה-URL, Edge מבצע את כל מה שביקשת ממנו (מפתח ה-API) לבצע באמצעות המדיניות שתצורף לתהליכי המדיניות האלה.

עכשיו אפשר להדגים ל-Edge מה לעשות כשתנאי מסוים מתקיים. ב-XML של שרת ה-API הבא של שרת ה-API, כשבקשת GET נשלחת אל https://yourorg-test.apigee.net/mygreatweatherforecast/reports, Edge מפעילה את מדיניות 'XML-to-JSON-1' בתגובה.

<Flows>
    <Flow name="reports">
        <Description/>
        <Request/>
        <Response>
            <Step>
                <Name>XML-to-JSON-1</Name>
            </Step>
        </Response>
        <Condition>(proxy.pathsuffix MatchesPath "/reports") and (request.verb = "GET")</Condition>
</Flow>

בנוסף לתהליכי העבודה המותנים האופציונליים, לכל שרת proxy של API יש גם שני תהליכי ברירת מחדל: <PreFlow> שבוצעו לפני התהליכים המותנים, ו-<PostFlow> שבוצעו אחרי התהליכים המותנים. הן שימושיות לביצוע מדיניות כשכל קריאה לשרת proxy של API. לדוגמה, אם רוצים לאמת מפתח API של אפליקציה בכל קריאה, ללא קשר למשאב הקצה העורפי שאליו מתבצעת הגישה, אפשר להוסיף מדיניות של אימות מפתח API ל‐<PreFlow>. למידע נוסף על תהליכי עבודה, קראו את המאמר הגדרת תהליכי עבודה.

יצירת תהליכי עבודה מותנים למשאבים בקצה העורפי

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

בפורטל תוכלו:

  • מחילים את הניהול באופן שמשקף את הסמנטיקה של מודל ה-API
  • החלת מדיניות והתנהגות סקריפטים על נתיבי משאבים נפרדים (URI)
  • איסוף מדדים מפורטים לשירותי Analytics

לדוגמה, נניח שאתם צריכים להחיל סוגי לוגיקה שונים על הקצה העורפי /developers על המשאבים /apps.

כדי לעשות את זה, צריך להוסיף שני שלבים מותנים לשרת ה-proxy של ה-API: /developers ו-/apps.

בתצוגה 'פיתוח' של חלונית הניווט של עורך ה-API של שרת ה-API, לוחצים על הסמל + לצד ברירת המחדל בקטע 'נקודות קצה של Proxy'.

בחלון 'זרימה מותנית חדשה', מזינים את תצורות המפתח הבאות:

  • שם התהליך: מפתחים
  • סוג תנאי: נתיב
  • נתיב: /developers

התנאי יופעל (והמדיניות תבוצע) אם תישלח קריאה לשרת ה-proxy עם /developers בסוף ה-URI.

עכשיו מוסיפים זרימה מותנית ל- /apps, ויוצאים מנקודת הנחה שאתם רוצים שהתנאי יופעל גם ב-URI וגם בפעלים של ה-POST בבקשה. ההגדרה כוללת את הפעולות הבאות:

  • שם זרימה: אפליקציות
  • סוג תנאי: נתיב ופועל
  • נתיב: /apps
  • פועל: POST

התנאי יופעל (והמדיניות תבוצע) אם תישלח קריאה לשרת ה-proxy עם /apps בסוף ה-URI ופועל POST.

בחלונית הניווט יופיעו התהליכים החדשים לאפליקציות ולמפתחים.

צריך לבחור אחד מהתהליכים כדי להציג את ההגדרה של הזרימה המותנית בתצוגת הקוד של עורך ה-API של שרת ה-API:

<Flow name="Apps">
    <Description>Developer apps registered in Developer Services</Description>
    <Request/>
    <Response/>
    <Condition>(proxy.pathsuffix MatchesPath "/apps") and (request.verb = "POST")</Condition>
</Flow>

כמו שאפשר לראות, משאבי ה-API הם פשוט תהליכים מותנים שמעריכים את נתיב ה-URI של הבקשה הנכנסת. (המשתנה proxy.pathsuffix מזהה את ה-URI של הבקשה הבאה אחרי ה-BasePath שהוגדר בתצורה של ProxyEndpoint).

כל משאב של ממשק API שתגדירו יוטמע על ידי זרימה מותנית בשרת ה-API של ה-API. (מידע נוסף מופיע במאמר הגדרת תהליכי עבודה).

אחרי שפורסים את שרת ה-proxy של ה-API לסביבת הבדיקה, צריך לבצע את הבקשה הבאה:

http://{org_name}-test.apigee.net/{proxy_path}/apps

יגרום לכך שהתנאי יהיה TRUE, והתהליך הזה, יחד עם כל כללי המדיניות המשויכים, יתבצע.

התנאי הבא לדוגמה משתמש בביטוי רגולרי של Java כדי לזהות קריאות שבוצעו למשאב /apps, עם או בלי קו נטוי קדימה (/apps או /apps/**):

<Condition>(proxy.pathsuffix JavaRegex "/apps(/?)") and (request.verb = "POST")</Condition>

למידע נוסף על תנאי מהסוג הזה, אפשר לעיין בקטע איך להתאים ללא קשר ... בקהילת Apigee.

יצירת מודלים של מזהי URI היררכיים

בחלק מהמקרים יהיו לכם משאבי API היררכיים. לדוגמה, ה-Developer Services API מספק שיטה לרישום כל האפליקציות ששייכות למפתח. נתיב ה-URI הוא:

/developers/{developer_email}/apps

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

/genus/:id/species

נתיב זה חל באופן שווה על שני מזהי ה-URI הבאים:

/genus/18904/species
/genus/17908/species

כדי לייצג את המבנה הזה במשאב API, אפשר להשתמש בתווים כלליים לחיפוש. לדוגמה:

/developers/*/apps
/developers/*example.com/apps
/genus/*/species

המערכת תטפל במזהי ה-URI ההיררכיים האלה כמשאבי API כראוי.

במקרים מסוימים, במיוחד בממשקי API היררכיים עמוקים, כדאי פשוט לתקן את כל מה שנמצא מתחת למקטע URI מסוים. כדי לעשות זאת, צריך להשתמש בתו כללי לחיפוש כוכבית כפולה בהגדרת המשאב. לדוגמה, אם מגדירים את משאב ה-API הבא:
/developers/**

משאב ה-API הזה יפתור את נתיבי ה-URI הבאים:

/developers/{developer_email}/apps
/developers/{developer_email}/keys
/developers/{developer_email}/apps/{app_id}/keys

כך ייראה תנאי זרימה מותנית בהגדרה של שרת ה-proxy של API:

<Condition>(proxy.pathsuffix MatchesPath "/developers/**") and (request.verb = "POST")</Condition>

דוגמאות נוספות

תנאי מצורף ל-RouteRule

<RouteRule name="default">
 <!--this routing executes if the header indicates that this is an XML call. If true, the call is routed to the endpoint XMLTargetEndpoint-->
  <Condition>request.header.content-type = "text/xml"</Condition>
  <TargetEndpoint>XmlTargetEndpoint</TargetEndpoint>
</RouteRule>

תנאי מצורף למדיניות

<Step>
<!--the policy MaintenancePolicy only executes if the response status code is exactly 503-->
  <Condition>response.status.code = 503</Condition>
  <Name>MaintenancePolicy</Name>
</Step>

זרימה מותנית

<!-- this entire flow is executed only if the request verb is a GET-->
<Flow name="GetRequests">
  <Condition>request.verb="GET"</Condition>
  <Request>
    <Step>
<!-- this policy only executes if request path includes a term like statues-->
<Condition>request.path ~ "/statuses/**"</Condition>
      <Name>StatusesRequestPolicy</Name>
    </Step>
  </Request>
  <Response>
    <Step>
<!-- this condition has multiple expressions. The policy executes if the response code status is exactly 503 or 400-->
<Condition>(response.status.code = 503) or (response.status.code = 400)</Condition>
      <Name>MaintenancePolicy</Name>
    </Step>
  </Response>
</Flow>

אופרטורים לדוגמה בתנאים

לפניכם כמה דוגמאות לאופרטורים שמשמשים ליצירת תנאים:

  • request.header.content-type = "text/xml"
  • request.header.content-length < 4096 && request.verb = "PUT"
  • response.status.code = 404 || response.status.code = 500
  • request.uri MatchesPath "/*/statuses/**"
  • request.queryparam.q0 NotEquals 10

דוגמה מעשית: התעלמות מ-"/" בסוף נתיב

בדרך כלל מפתחי Edge רוצים לטפל בשני סיומות הנתיב הבאות: '/cat' ו-'/cat/'. הסיבה לכך היא שחלק מהמשתמשים או הלקוחות עשויים לקרוא ל-API שלך באמצעות קו הנטוי הנוסף בסוף הנתיב, וחשוב שיהיה אפשר לטפל בכך בהצהרות המותנות. התרחיש לדוגמה הזה נדון בקהילת Apigee.

אם אתם מעדיפים, אפשר לעשות זאת בלי להשתמש בביטוי רגולרי (regex):

    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Condition>((proxy.pathsuffix = "/cat") OR (proxy.pathsuffix = "/cat/")</Condition>
                <Name>SomePolicy</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>

זו אפשרות טובה. הוא ברור וקריא.

עם זאת, אפשר לבצע את אותו הדבר עם ביטוי רגולרי, באופן הזה. הסוגריים משמשים לקיבוץ החלק של הביטוי הרגולרי בהצהרה, אבל הם לא נדרשים.

<Condition>(proxy.pathsuffix JavaRegex "/cat(/?)"</Condition>

קריאות ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat
or

GET http://artomatic-test.apigee.net/matchtest/cat/

האם המדיניות מיושמת? כן. חשוב לשים לב שבביטוי רגולרי, התו "?" פירושו התאמה לאפס או אחד מהתו הקודם. לכן גם "/cat" וגם "/cat/" הם התאמות.

קריאה ל-API:

GET http://artomatic-test.apigee.net/matchtest/cat/spotted

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

התאמת מחרוזות שרירותיות ל-JavaRegex

בכל הדוגמאות בנושא הזה, נראה איך להתאים את אחד ממשתני הזרימה המובנים: proxy.pathsuffix. כדאי לדעת שתוכל לבצע התאמת דפוסים בכל מחרוזת או משתנה זרימה שרירותיים, בין אם מדובר במשתנה זרימה מובנה כמו proxy.pathsuffix.

לדוגמה, אם יש תנאי שבודק מחרוזת שרירותית, למשל מחרוזת שמוחזרת במטען ייעודי (payload) עורפי או מחרוזת שמוחזרת מחיפוש בשרת אימות, אפשר להשתמש באופרטורים תואמים כדי לבדוק אותו. אם משתמשים ב-JavaRegex, המערכת משווה בין הביטוי הרגולרי לבין כל מחרוזת הנושא. אם הנושא הוא "abc" והביטוי הרגולרי הוא "[a-z]", אין התאמה, מכיוון ש-"[a-z]" תואם בדיוק לתו אלפא אחד. הביטוי "[a-z]+" פועל כמו גם "[a-z]*" ו-"[a-z]{3}.

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

כדי לבדוק את הנוכחות של תפקיד העורך, המבנה הזה לא יעבוד, כי 'עריכה' היא רק חלק מהמחרוזת.

<Condition>returned_roles ~~ "editor"</Condition>

עם זאת, המבנה הזה יעבוד:

<Condition>returned_roles ~~ ".*\beditor\b.*")</Condition>

התכונה פועלת כי היא מביאה בחשבון מעברי מילים וכל חלק אחר במחרוזת עם הקידומת והסיומת .*

בדוגמה הזו אפשר גם לבדוק את הערך 'עריכה' באמצעות האופרטור 'התאמות':

<Condition>returned_roles ~~ "*editor*")</Condition>

עם זאת, במקרים שבהם דרושה לך רמת דיוק גבוהה יותר, JavaRegex בדרך כלל מתאימה יותר.

הוספת מירכאות כפולות לביטויי JavaRegex

תחביר התנאי מחייב שביטוי JavaRegex מוקף במירכאות כפולות. לכן, אם יש לכם ביטוי רגולרי שכולל מירכאות כפולות, עליכם למצוא דרך חלופית להתאים אותן. התשובה היא בפורמט Unicode. לדוגמה, נניח שאתם מעבירים בכותרת שכוללת מירכאות כפולות, כמו בדוגמה הבאה:
 -H 'content-type:multipart/related; type="application/xop+xml"'
אם תנסו להתאים את הכותרת הזו בתנאי של ביטוי רגולרי, תקבלו שגיאת 'תנאי לא חוקי' כי הביטוי כולל מירכאות כפולות:
request.header.Content-Type ~~ "(multipart\/related)(; *type="application\/xop\+xml\")"
הפתרון הוא להחליף מירכאות כפולות שמבוססות על ASCII במקבילות שלהן ל-Unicode, \u0022. לדוגמה, הביטוי הבא חוקי ומפיק את התוצאה הצפויה:
request.header.Content-Type ~~ "(multipart\/related)(; *type=\u0022application\/xop\+xml\u0022)"