वंशानुक्रम के साथ एक प्रतिष्ठित एपीआई मॉडल कैसे करें?


88

मेरे पास एक ऑब्जेक्ट पदानुक्रम है जिसे मुझे RESTful API के माध्यम से उजागर करना होगा और मुझे यकीन नहीं है कि मेरे URL को कैसे संरचित किया जाना चाहिए और उन्हें क्या लौटना चाहिए। मुझे कोई सर्वोत्तम अभ्यास नहीं मिला।

मान लीजिए कि मेरे पास डॉग्स और बिल्लियाँ हैं जो जानवरों से विरासत में मिली हैं। मुझे कुत्तों और बिल्लियों पर CRUD संचालन की आवश्यकता है; मैं सामान्य रूप से जानवरों पर ऑपरेशन करने में सक्षम होना चाहता हूं।

मेरा पहला विचार कुछ ऐसा करने का था:

GET /animals        # get all animals
POST /animals       # create a dog or cat
GET /animals/123    # get animal 123

बात यह है कि / जानवरों का संग्रह अब "असंगत" है, क्योंकि यह उन वस्तुओं को वापस ले सकता है और ले सकता है जिनके पास बिल्कुल समान संरचना (कुत्ते और बिल्लियाँ) नहीं हैं। क्या यह "रेस्टफुल" माना जाता है कि एक संग्रह वस्तुओं को अलग करने की विशेषता है?

एक अन्य समाधान प्रत्येक ठोस प्रकार के लिए एक URL बनाना होगा, जैसे:

GET /dogs       # get all dogs
POST /dogs      # create a dog
GET /dogs/123   # get dog 123

GET /cats       # get all cats
POST /cats      # create a cat
GET /cats/123   # get cat 123

लेकिन अब कुत्तों और बिल्लियों के बीच का रिश्ता खो गया है। यदि कोई सभी जानवरों को प्राप्त करना चाहता है, तो कुत्ते और बिल्ली दोनों को संसाधनों को छोड़ना होगा। प्रत्येक नए पशु उपप्रकार के साथ यूआरएल की संख्या भी बढ़ेगी।

एक अन्य सुझाव यह जोड़कर दूसरे समाधान को बढ़ाने के लिए था:

GET /animals    # get common attributes of all animals

इस मामले में, लौटे जानवरों में केवल सभी जानवरों के लिए सामान्य विशेषताएं होंगी, कुत्ते-विशिष्ट और बिल्ली-विशिष्ट गुण छोड़ने होंगे। यह सभी जानवरों को पुनः प्राप्त करने की अनुमति देता है, हालांकि कम विवरण के साथ। प्रत्येक लौटी हुई वस्तु में विस्तृत, ठोस संस्करण का लिंक हो सकता है।

कोई टिप्पणी या सुझाव?

जवाबों:


41

मै सुझाव दूंगा:

  • प्रति संसाधन केवल एक URI का उपयोग करना
  • केवल विशेषता स्तर पर जानवरों के बीच अंतर करना

एक ही संसाधन में कई यूआरआई की स्थापना करना एक अच्छा विचार नहीं है क्योंकि यह भ्रम और अप्रत्याशित दुष्प्रभाव पैदा कर सकता है। यह देखते हुए, आपका एकल URI जैसी सामान्य योजना पर आधारित होना चाहिए /animals

"बेस" स्तर पर कुत्तों और बिल्लियों के पूरे संग्रह से निपटने की अगली चुनौती पहले ही /animalsयूआरआई दृष्टिकोण के आधार पर हल हो गई है ।

कुत्तों और बिल्लियों जैसे विशेष प्रकारों से निपटने की अंतिम चुनौती को आपके मीडिया प्रकार के भीतर क्वेरी मापदंडों और पहचान विशेषताओं के संयोजन का उपयोग करके आसानी से हल किया जा सकता है। उदाहरण के लिए:

GET /animals( Accept : application/vnd.vet-services.animals+json)

{
   "animals":[
      {
         "link":"/animals/3424",
         "type":"dog",
         "name":"Rex"
      },
      {
         "link":"/animals/7829",
         "type":"cat",
         "name":"Mittens"
      }
   ]
}
  • GET /animals - सभी कुत्तों और बिल्लियों को प्राप्त होता है, रेक्स और मिट्टेंस दोनों को वापस करेगा
  • GET /animals?type=dog - सभी कुत्तों को मिलता है, केवल रेक्स को वापस करेगा
  • GET /animals?type=cat - सभी बिल्लियों को मिल जाता है, केवल मिट्टेंस होगा

फिर जानवरों को बनाते या संशोधित करते समय, इसमें शामिल जानवर के प्रकार को निर्दिष्ट करने के लिए फोन करने वाले पर निर्भर होगा:

मीडिया का स्वरूप: application/vnd.vet-services.animal+json

{
   "type":"dog",
   "name":"Fido"
}

उपरोक्त पेलोड को एक अनुरोध POSTया PUTअनुरोध के साथ भेजा जा सकता है ।

उपरोक्त योजना आपको OEST विरासत के रूप में REST के माध्यम से और इसी तरह की विशिष्टताओं (जैसे अधिक जानवरों के प्रकार) को प्रमुख सर्जरी या आपकी URI योजना में कोई बदलाव किए बिना जोड़ने की क्षमता के साथ मूल रूप से मिलती है।


यह एक REST API के माध्यम से "कास्टिंग" के समान लगता है। यह मुझे C ++ उपवर्ग के मेमोरी लेआउट में मुद्दों / समाधानों की भी याद दिलाता है। उदाहरण के लिए, जहां और कैसे दोनों एक साथ एक आधार का प्रतिनिधित्व करते हैं और स्मृति में एक एकल पते के साथ उपवर्ग।
त्रिकार्ण

10
मेरा सुझाव है: GET /animals - gets all dogs and cats GET /animals/dogs - gets all dogs GET /animals/cats - gets all cats
dipold

1
जीईटी अनुरोध पैरामीटर के रूप में वांछित प्रकार को निर्दिष्ट करने के अलावा: यह मुझे लगता है कि आप इसे प्राप्त करने के लिए स्वीकार प्रकार का उपयोग कर सकते हैं। वह है: GET /animals स्वीकारapplication/vnd.vet-services.animal.dog+json
ब्रायन।

22
क्या होगा अगर बिल्ली और कुत्ते में से प्रत्येक में अद्वितीय गुण हैं? आप POSTऑपरेशन को कैसे संभालेंगे , क्योंकि अधिकांश रूपरेखाओं को यह नहीं पता होगा कि एक मॉडल में इसे ठीक से कैसे चित्रित किया जाए क्योंकि जौन टाइपिंग की जानकारी नहीं रखता है। आप पोस्ट मामलों को कैसे संभालेंगे उदा [{"type":"dog","name":"Fido","playsFetch":true},{"type":"cat","name":"Sparkles","likesToPurr":"sometimes"}?
LB2

1
क्या होगा अगर कुत्तों और बिल्लियों में (अधिकांश) अलग-अलग गुण हों? उदाहरण के लिए # 1 एसएमएस के लिए एक पोस्टिंग (, मास्क,) बनाम एक ईमेल (ईमेल पता, सीसी, बीसीसी, से, आईएसएचटीएमएल), या उदाहरण के लिए क्रेडिट कार्ड (मास्कपैन, नामऑनकार्ड, एक्सपायरी) के लिए # 2 पोस्टिंग एक सोर्सिंग स्रोत बनाम। BankAccount (bsb, accountNumber) ... क्या आप अभी भी एकल API संसाधन का उपयोग करेंगे? यह SOLID सिद्धांतों से एकल ज़िम्मेदारी का उल्लंघन लगता है, लेकिन यह सुनिश्चित नहीं होता है कि यह API डिज़ाइन पर लागू होता है या नहीं ...
Ryan.Bartsch

5

ओपनएपीआई के नवीनतम संस्करण में हाल ही में वृद्धि के समर्थन के साथ इस सवाल का बेहतर जवाब दिया जा सकता है।

OneOf, allOf, anyOf जैसे कीवर्ड का उपयोग करके स्कीमाओं को जोड़ना संभव है और JSON स्कीमा v1.0 के बाद से मान्य संदेश पेलोड प्राप्त करें।

https://spacetelescope.github.io/understanding-json-schema/reference/combining.html

हालांकि, OpenAPI (पूर्व स्वैगर) में, स्कीमा रचना कीवर्ड के आधार पर बढ़ाया गया है discriminator (v2.0 +) और oneof (v3.0 +) वास्तव में समर्थन बहुरूपता के लिए।

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaComposition

आपके वंशानुक्रम को वनऑफ़ (सबटाइप्स में से एक को चुनने के लिए) और ऑलऑफ़ (प्रकार और उसके सबटाइप्स के संयोजन के लिए) के संयोजन का उपयोग करके बनाया जा सकता है। नीचे POST विधि के लिए एक नमूना परिभाषा दी गई है।

paths:
  /animals:
    post:
      requestBody:
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/Dog'
              - $ref: '#/components/schemas/Cat'
              - $ref: '#/components/schemas/Fish'
            discriminator:
              propertyName: animal_type
     responses:
       '201':
         description: Created

components:
  schemas:
    Animal:
      type: object
      required:
        - animal_type
        - name
      properties:
        animal_type:
          type: string
        name:
          type: string
      discriminator:
        property_name: animal_type
    Dog:
      allOf:
        - $ref: "#/components/schemas/Animal"
        - type: object
          properties:
            playsFetch:
              type: string
    Cat:
      allOf:
        - $ref: "#/components/schemas/Animal"
        - type: object
          properties:
            likesToPurr:
              type: string
    Fish:
      allOf:
        - $ref: "#/components/schemas/Animal"
        - type: object
          properties:
            water-type:
              type: string

1
यह सच है कि OAS इसकी अनुमति देता है। हालाँकि, Swagger UI ( लिंक ) में प्रदर्शित होने वाली सुविधा के लिए कोई समर्थन नहीं है , और मुझे लगता है कि एक सुविधा सीमित उपयोग की है यदि आप इसे किसी को नहीं दिखा सकते हैं।
ईएमएफ

1
@ चोरी, सच नहीं। इस उत्तर को लिखते समय, स्वैगर UI पहले से ही इसका समर्थन करता है।
रसियन कैनिकोव्स

धन्यवाद, यह महान काम करता है! वर्तमान में यह सच है कि स्वैगर यूआई इसे पूरी तरह से प्रदर्शित नहीं करता है। मॉडल नीचे स्कीमा अनुभाग में दिखाए जाएंगे, और वनऑफ़ अनुभाग का संदर्भ देने वाला कोई भी प्रतिक्रिया अनुभाग आंशिक रूप से UI (स्कीमा केवल, कोई उदाहरण नहीं) में दिखाई देगा, लेकिन आपको अनुरोध इनपुट के लिए कोई उदाहरण नहीं मिलता है। इसके लिए github मुद्दा 3 साल से खुला है, इस तरह से बने रहने की संभावना है: github.com/swagger-api/swagger-ui/issues/3803
जेथ्रो

4

मैं कुत्तों और मछलियों और दोनों की सूची की वापसी करने वाले / जानवरों के लिए जाऊंगा और कभी भी:

<animals>
  <animal type="dog">
    <name>Fido</name>
    <fur-color>White</fur-color>
  </animal>
  <animal type="fish">
    <name>Wanda</name>
    <water-type>Salt</water-type>
  </animal>
</animals>

एक समान JSON उदाहरण को लागू करना आसान होना चाहिए।

ग्राहक हमेशा "नाम" तत्व पर भरोसा कर सकते हैं (एक सामान्य विशेषता)। लेकिन "प्रकार" विशेषता के आधार पर पशु प्रतिनिधित्व के हिस्से के रूप में अन्य तत्व होंगे।

ऐसी सूची वापस करने में स्वाभाविक रूप से Restful या UnRestful कुछ भी नहीं है - REST डेटा का प्रतिनिधित्व करने के लिए किसी विशिष्ट प्रारूप को निर्धारित नहीं करता है। सभी का कहना है कि डेटा में कुछ प्रतिनिधित्व होना चाहिए और उस प्रतिनिधित्व के प्रारूप को मीडिया प्रकार (जो HTTP में सामग्री-प्रकार हेडर है) द्वारा पहचाना जाता है।

अपने उपयोग के मामलों के बारे में सोचें - क्या आपको मिश्रित जानवरों की सूची दिखाने की आवश्यकता है? खैर, फिर मिश्रित पशु डेटा की सूची लौटाएं। क्या आपको केवल कुत्तों की सूची की आवश्यकता है? अच्छा, ऐसी सूची बनाओ।

चाहे आप / पशु करते हैं? प्रकार = कुत्ता या / कुत्ते REST के संबंध में अप्रासंगिक है जो किसी भी URL स्वरूपों को नहीं रखता है - जो कि REST के दायरे से बाहर कार्यान्वयन विवरण के रूप में छोड़ा गया है। REST केवल यह बताता है कि संसाधनों के पास पहचानकर्ता होना चाहिए - जो कभी भी प्रारूपित न हो।

आपको RESTful API के करीब आने के लिए कुछ हाइपर मीडिया को जोड़ना चाहिए। उदाहरण के लिए जानवरों के विवरण में संदर्भ जोड़कर:

<animals>
  <animal type="dog" href="https://stackoverflow.com/animals/123">
    <name>Fido</name>
    <fur-color>White</fur-color>
  </animal>
  <animal type="fish" href="https://stackoverflow.com/animals/321">
    <name>Wanda</name>
    <water-type>Salt</water-type>
  </animal>
</animals>

हाइपर मीडिया को जोड़ने से आप क्लाइंट / सर्वर युग्मन को कम करते हैं - उपरोक्त मामले में आप क्लाइंट से URL निर्माण का बोझ उठाते हैं और सर्वर को यह तय करने देते हैं कि URL का निर्माण कैसे किया जाए (जो कि परिभाषा के अनुसार एकमात्र अधिकार है)।


1

लेकिन अब कुत्तों और बिल्लियों के बीच का रिश्ता खो गया है।

वास्तव में, लेकिन ध्यान रखें कि यूआरआई कभी भी वस्तुओं के बीच संबंधों को प्रतिबिंबित नहीं करता है।


1

मुझे पता है कि यह एक पुराना सवाल है, लेकिन मैं एक रूस्टफुल इनहेरिटेंस मॉडलिंग पर आगे के मुद्दों की जांच करने में दिलचस्पी रखता हूं

मैं हमेशा कह सकता हूं कि एक कुत्ता एक जानवर है और मुर्गी भी, लेकिन मुर्गी अंडे देती है जबकि कुत्ता एक स्तनपायी प्राणी है, इसलिए यह नहीं हो सकता। एक एपीआई की तरह

पशु प्राप्त करें: / पशु / अंडे

सुसंगत नहीं है क्योंकि यह इंगित करता है कि पशु के सभी उपप्रकारों में अंडे हो सकते हैं (लिस्कोव प्रतिस्थापन के परिणामस्वरूप)। यदि सभी स्तनधारी इस अनुरोध पर '0' के साथ प्रतिक्रिया करते हैं, तो एक गिरावट होगी, लेकिन क्या होगा अगर मैं एक POST विधि को भी सक्षम करूं? क्या मुझे डर होना चाहिए कि कल मेरी क्रेप्स में कुत्ते के अंडे होंगे?

इन परिदृश्यों को संभालने का एकमात्र तरीका एक 'सुपर-रिसोर्स' प्रदान करना है जो सभी उप-स्रोतों को सभी कब्जे वाले 'व्युत्पन्न-संसाधन' के बीच संयोजित करता है और फिर प्रत्येक व्युत्पन्न-संसाधन के लिए एक विशेषज्ञता जिसे इसकी आवश्यकता है, जैसे कि जब हम किसी ऑब्जेक्ट को डाउन करते हैं ऊप में

GET / जानवर /: animalID / बेटे GET / मुर्गियाँ /: animalID / अंडे POST / मुर्गियाँ /: animalID / अंडे

यहाँ दोष यह है कि कोई एक कुत्ते की आईडी पारित कर सकता है, ताकि वह उसके संग्रह का उदाहरण दे सके, लेकिन कुत्ता मुर्गी नहीं है, इसलिए यह गलत नहीं होगा यदि प्रतिक्रिया 404 या 400 कारण संदेश के साथ हो।

क्या मै गलत हु?


1
मुझे लगता है कि आप यूआरआई संरचना पर बहुत अधिक जोर दे रहे हैं। HATEOAS के माध्यम से आपको "जानवरों /: जानवरों के अंडे / अंडे" प्राप्त करने में सक्षम होना चाहिए। तो आप सबसे पहले जानवर को "जानवरों /: एनिमिड" के माध्यम से अनुरोध करेंगे और फिर उन जानवरों के लिए जिनके पास अंडे हो सकते हैं, "जानवरों /: / जानवरों के अंडे / अंडे" के लिए एक लिंक होगा, और उन लोगों के लिए, जो नहीं करेंगे जानवरों से अंडों तक जाने की एक कड़ी हो। यदि कोई किसी ऐसे अंडे के लिए अंडे पर समाप्त होता है जिसमें अंडे नहीं हो सकते हैं, तो उचित HTTP स्थिति कोड लौटाएं (उदाहरण के लिए पाया नहीं गया या निषिद्ध नहीं)
wired_in

0

हां, आप गलत हैं। इसके अलावा रिश्तों को इस बहुरूपी तरीके से OpenAPI चश्मा के बाद मॉडल किया जा सकता है।

Chicken:
  type: object
  discriminator:
    propertyName: typeInformation
  allOf:
    - $ref:'#components/schemas/Chicken'
    - type: object
      properties:
        eggs:
          type: array
          items:
            $ref:'#/components/schemas/Egg'
          name:
            type: string

...


अतिरिक्त टिप्पणी: एपीआई मार्ग पर ध्यान केंद्रित GET chicken/eggs करना भी नियंत्रकों के लिए सामान्य ओपनएपीआई कोड जनरेटर का उपयोग करके काम करना चाहिए, लेकिन मैंने अभी तक इसकी जांच नहीं की थी। शायद कोई कोशिश कर सकता है?
एंड्रियास गॉस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.