GitHup API

GitHup API

सीखने का अभ्यास

परिचय

JSON

JSON

JSON (JavaScript Object Notation) एक ऐसा डेटा और फाइल फॉर्मेट है जिसे मनुष्य पढ़ सकते हैं, और जिसका उपयोग आमतौर पर डेटा का आदान-प्रदान करने के लिए किया जाता है, खास तौर पर वेब ऐप्लिकेशन के लिए। इसलिए यह कोई आश्चर्य की बात नहीं है कि Elm भाषा में इसका एक खास स्थान है।

Elm JSON डेटा को पढ़ने और लिखने के लिए दो मुख्य मॉड्यूल देता है: Json.Decode और Json.Encode। JSON डिकोडर एक तरीका है यह घोषित करने का कि किस तरह का डेटा अपेक्षित है और डेटा को किस डेटा स्ट्रक्चर में ढलना चाहिए।

आइए इन मॉड्यूल से कुछ अलियास और टाइप इम्पोर्ट करते हैं:

import Json.Decode as Decode exposing (Decoder, Error)
import Json.Encode as Encode exposing (Value)

किसी डिकोडर और एक JSON स्ट्रिंग के साथ Decode.decodeString : Decoder a -> String -> Result Error a का उपयोग करने पर, अगर स्ट्रिंग डिकोडर की शर्तों के मुताबिक है तो यह सफल होगा, वरना फेल हो जाएगा। डिकोडर बनाते समय कच्चे JSON डेटा को देखने का कोई तरीका नहीं है, जो इम्पेरेटिव भाषाओं से आने वाले लोगों को असामान्य लग सकता है।

बुनियादी डेटा टाइप डिकोडर

JSON में कुछ गिने-चुने मुख्य डेटा टाइप होते हैं:

  • String: डबल कोट्स के साथ लिखी जाती है "hello world"
  • Boolean: या तो true या false
  • Number: जैसे 34 या 0.12
  • Null: डेटा का न होना null

इनमें से हर एक के लिए Decode का एक फंक्शन है:

Decode.decodeString Decode.string """\"hello\""""
    --> Ok "hello"

Decode.decodeString Decode.string """null"""
    --> Err ...

Decode.decodeString Decode.bool """true"""
    --> Ok True

Decode.decodeString Decode.bool """0"""
    --> Err ...

Decode.decodeString Decode.int """12"""
    --> Ok 12

Decode.decodeString Decode.float """3.14"""
    --> Ok 3.14

Decode.decodeString (Decode.null AnyValue) """null"""
    --> Ok AnyValue

Decode.decodeString (Decode.null AnyValue) """true"""
    --> Err ...

ध्यान दीजिए कि Decode.null आपको यह तय करने देता है कि अपने प्रोग्राम में null को कैसे दर्शाना है, क्योंकि यह आर्गुमेंट के तौर पर कोई भी वैल्यू मांगता है (शायद (), Nothing, या आपके प्रोग्राम के लिए जो भी उपयुक्त हो)।

डिकोडर को जोड़ना

JSON दो ऐसे डेटा स्ट्रक्चर भी परिभाषित करता है जो मुख्य डेटा टाइप को इकट्ठा करते हैं:

  • Array: दूसरे डेटा टाइप का संग्रह [0, null, "none", []]
  • Object: की-वैल्यू जोड़ों का संग्रह {"id": 1, "is_admin": false, "more_info": {}}

Decode इन्हें डिकोड करने के लिए भी फंक्शन देता है:

Decode.decodeString (Decode.list Decode.int) """[1, 2, 3]"""
    --> Ok [1, 2, 3]

Decode.decodeString (Decode.list Decode.int) """[1, 2, 3, "not an int"]"""
    --> Err ...

Decode.decodeString (Decode.dict Decode.int) """{ "key1": 17, "key2": 71 }"""
    --> Ok (Dict.fromList [("key1", 17), ("key2", 71)])

Decode.decodeString (Decode.dict Decode.int) """{ "key1": 17, "key2": "seventy-one" }"""
    --> Err ...

ये फंक्शन Decode.list : Decoder a -> Decoder (List a) और Decode.dict : Decoder a -> Decoder (Dict String a) दोनों आर्गुमेंट के तौर पर एक डिकोडर लेते हैं, और यह डिकोडर डेटा स्ट्रक्चर के हर एक एलिमेंट को डिकोड करता है। अगर आर्गुमेंट डिकोडर किसी ऐरे या ऑब्जेक्ट वैल्यू के किसी भी एलिमेंट को डिकोड करने में फेल हो जाए, तो पूरा डिकोडर फेल हो जाता है, और यह एक आम पैटर्न है।

साधारण डिकोडरों को जोड़कर ज़्यादा जटिल डिकोडर बनाना ही इस तकनीक का मूल विचार है। हम एक उदाहरण की मदद से कुछ और फंक्शन बताएँगे, जिनसे आप वास्तविक दुनिया के डेटा के लिए मनमुताबिक जटिल डिकोडर बना सकते हैं।

GeoJSON

जटिल JSON डेटा पढ़ने के लिए बुनियादी डिकोडरों को जोड़ने का अभ्यास करने के लिए, आइए GeoJSON डेटा (के एक हिस्से) को पढ़ने के लिए डिकोडर बनाते हैं। GeoJSON एक खास तरह का JSON-आधारित डेटा फॉर्मेट है, जिसका उपयोग भौगोलिक चीज़ों, जैसे स्थानों, रास्तों या क्षेत्रों को दर्शाने के लिए किया जाता है। ये 2D या 3D भौगोलिक निर्देशांकों के साथ, और साथ में दूसरी प्रॉपर्टीज़ के साथ दी जाती हैं।

ज्योमेट्री ऑब्जेक्ट

GeoJSON ज्योमेट्री ऑब्जेक्ट एक ऐसा ऑब्जेक्ट होता है जिसमें एक type फील्ड होती है जिसकी वैल्यू एक स्ट्रिंग होती है (7 संभावित टाइप वैल्यू होती हैं), और एक coordinates फील्ड होती है जिसमें भौगोलिक निर्देशांक होते हैं (जो टाइप के हिसाब से अलग ढाँचे में इकट्ठे होते हैं)। उदाहरण के लिए,

{
  "type": "Point",
  "coordinates": [127.831, 26.461]
}

या

{
  "type": "LineString",
  "coordinates": [
    [127.831, 26.461],
    [127.829, 26.465],
    [127.829, 26.469],
    [127.83, 26.47]
  ]
}

Elm में ज्योमेट्री ऑब्जेक्ट को इस टाइप से दर्शाया जा सकता है

type Geometry
  = Point (List Float)
  | LineString (List (List Float))
  | ...

किसी खास फील्ड की वैल्यू जाँचने के लिए हम Decode.field : String -> Decoder a -> Decoder a का उपयोग कर सकते हैं, जो किसी ऑब्जेक्ट की एक खास की की वैल्यू डिकोड करता है।

decodePointCoordinates : Decoder (List Float)
decodePointCoordinates =
    Decode.field "coordinates" (Decode.list Decode.float)

decodeLineStringCoordinates : Decoder (List (List Float))
decodeLineStringCoordinates =
    Decode.field "coordinates" (Decode.list (Decode.list Decode.float))

किसी डिकोडर द्वारा सफलतापूर्वक पढ़ी गई वैल्यू को बदलने के लिए हम Decode.map : (a -> value) -> Decoder a -> Decoder value का उपयोग कर सकते हैं, या इसके साथी फंक्शनों में से कोई भी, Decode.map2 (a -> b -> value) -> Decoder a -> Decoder b -> Decoder value से लेकर Decode.map8 तक।

इस मामले में, हमें type फील्ड की वैल्यू के हिसाब से यह तय करना है कि कौन सा निर्देशांक डिकोडर इस्तेमाल करना है। यह काम Decode.andThen : (a -> Decoder b) -> Decoder a -> Decoder b और उसके साथी फंक्शन Decode.succeed : a -> Decoder a और Decode.fail : String -> Decoder a के लिए बिल्कुल सही है।

decodeGeometry : Decoder Geometry
decodeGeometry =
    Decode.field "type" Decode.string
        |> Decode.andThen
            (\value ->
                case value of
                    "Point" ->
                        decodePointCoordinates |> Decode.map Point

                    "LineString" ->
                        decodeLineStringCoordinates |> Decode.map LineString

                    _ ->
                        Decode.fail "Geometry not implemented yet, or invalid type value"
            )

यहाँ ध्यान दीजिए कि हम निर्देशांकों की जाँच करने के लिए Decode.andThen का उपयोग कर सकते हैं (यह देखना कि निर्देशांक जोड़ों या तिकड़ियों में आते हैं, और यह देखना कि निर्देशांकों की वैल्यू भौगोलिक रूप से सही हैं)।

Decode.decodeString decodeGeometry """{"type": "Point", "coordinates": [127.831, 26.461]}"""
    --> Ok (Point [127.831, 26.461])

Decode.decodeString decodeGeometry """{"type": "LineString", "coordinates": [127.831, 26.461]}"""
    --> Err ...
फीचर ऑब्जेक्ट

GeoJSON फीचर ऑब्जेक्ट किसी ऐसी चीज़ को दर्शाता है जिसकी एक स्थानिक सीमा होती है: इसमें एक type फील्ड होती है जिसकी वैल्यू "Feature" होती है, एक geometry फील्ड होती है जिसमें एक ज्योमेट्री ऑब्जेक्ट या null होता है, एक properties फील्ड होती है जिसमें कोई भी JSON ऑब्जेक्ट या null होता है, और एक वैकल्पिक id फील्ड होती है जिसकी वैल्यू एक JSON स्ट्रिंग या संख्या होती है।

{
  "type": "Feature",
  "geometry": null,
  "properties": null
}

या

{
  "type": "Feature",
  "id": "0157",
  "geometry": {
    "type": "Point",
    "coordinates": [127.831, 26.461]
  },
  "properties": {
    "country": "Japan"
  }
}

आइए सबसे पहले id फील्ड को देखते हैं। अगर यह मौजूद है, तो इसमें स्ट्रिंग या संख्याएँ दोनों आ सकती हैं। इसलिए हम या तो वैल्यू के लिए एक कस्टम टाइप बना सकते हैं, या उसे हमेशा स्ट्रिंग के तौर पर सेव कर सकते हैं।

दो संभावित डिकोडरों में से एक चुनने के लिए हम Decode.oneOf : List (Decoder a) -> Decoder a का उपयोग कर सकते हैं।

decodeFeatureId : Decoder String
decodeFeatureId =
    Decode.oneOf
        [ Decode.string
        , Decode.int |> Decode.map String.fromInt
        , Decode.float |> Decode.map String.fromFloat
        ]
        |> Decode.field "id"

Decode.decodeString decodeFeatureId """{"id": "seventeen"}"""
    --> Ok "seventeen"

Decode.decodeString decodeFeatureId """{"id": 17}"""
    --> Ok "17"

Decode.decodeString decodeFeatureId """{"type": "Point"}"""
    --> Er ...

यह बताने के लिए कि फील्ड वैकल्पिक है, हम वही तकनीक इस्तेमाल कर सकते हैं

decodeMaybeFeatureId : Decoder (Maybe String)
decodeMaybeFeatureId =
    Decode.oneOf
        [ decodeFeatureId |> Decode.map Just
        , Decode.succeed Nothing
        ]

लेकिन हम इसके बजाय Decode.maybe : Decoder a -> Decoder (Maybe a) का उपयोग कर सकते हैं

decodeMaybeFeatureId : Decoder (Maybe String)
decodeMaybeFeatureId =
    Decode.maybe decodeFeatureId

Decode.decodeString decodeMaybeFeatureId """{"id": 17}"""
    --> Ok (Just "17")

Decode.decodeString decodeMaybeFeatureId """{"type": "Point"}"""
    --> Ok Nothing

ध्यान दीजिए कि decodeMaybeFeatureId (या Decode.maybe से लिपटा कोई भी डिकोडर) हमेशा सफल होगा, क्योंकि यह हमेशा Ok Nothing पर लौट सकता है। हालाँकि, जो डिकोडर इसका उपयोग करता है वह अब भी फेल हो सकता है

Decode.decodeString (Decode.list decodeMaybeFeatureId) """{"id": 17}"""
    --> Err ...

अब आइए geometry फील्ड पर ध्यान देते हैं, जो या तो एक ज्योमेट्री ऑब्जेक्ट हो सकती है या null। हम एक बार फिर Decode.oneOf इस्तेमाल कर सकते हैं, लेकिन इससे बेहतर विकल्प है: Decode.nullable : Decoder a -> Decoder (Maybe a)।

decodeFeatureGeometry : Decoder (Maybe Geometry)
decodeFeatureGeometry =
    Decode.nullable decodeGeometry
        |> Decode.field "geometry"

Decode.decodeString decodeFeatureGeometry """{"geometry": {"type": "Point", "coordinates": [127.831, 26.461]}}"""
    --> Ok (Just (Point [127.831, 26.461]))

Decode.decodeString decodeFeatureGeometry """{"geometry": null}"""
    --> Ok Nothing

Decode.decodeString decodeFeatureGeometry """{"geometry": {}}"""
    --> Err ...

Decode.maybe और Decode.nullable का सिग्नेचर एक जैसा है, लेकिन उनका व्यवहार अलग है, क्योंकि Decode.nullable का OK Nothing नतीजा सिर्फ खास JSON वैल्यू null से ही आएगा।

अंत में, properties फील्ड में कोई भी JSON ऑब्जेक्ट या null हो सकता है, और यह काम Decode.value : Decoder Value के लिए है।

decodeProperties : Decoder (Maybe (Dict String Value))
decodeProperties =
    Decode.nullable (Decode.dict Decode.value)
        |> Decode.field "properties"


Decode.decodeString decodeProperties """{"properties": null}"""
    --> Ok Nothing

Decode.decodeString decodeProperties """{"properties": {"country": "Japan"}}"""
    --> Ok (Just (Dict.fromList [("country", <internals>)]))

Decode.decodeString decodeProperties """{"properties": 17}"""
    --> Err ...

ध्यान दीजिए कि Value एक ओपेक टाइप है, यानी आप इसकी सामग्री को आसानी से नहीं जाँच सकते। इसका उपयोग करने के लिए, आप या तो इसके लिए एक डिकोडर लिखकर उसे Decode.decodeValue : Decoder a -> Value -> Result Error a से चला सकते हैं, या इसे पोर्ट के ज़रिए सीधे JavaScript को भेज सकते हैं।

अब हम फीचर ऑब्जेक्ट पढ़ने के लिए तैयार हैं:

type alias Feature =
    { id : Maybe String
    , geometry : Maybe Geometry
    , properties : Maybe (Dict String Value)
    }

decodeFeature : Decoder Feature
decodeFeature =
    Decode.field "type" Decode.string
        |> Decode.andThen
            (\value ->
                if value /= "Feature" then
                    Decode.fail "not a Feature"

                else
                    Decode.map3 Feature
                        decodeMaybeFeatureId
                        decodeFeatureGeometry
                        decodeProperties
            )

Decode.decodeString decodeFeature """{"type": "Feature", "geometry": null, "properties": null}"""
    --> Ok { geometry = Nothing, id = Nothing, properties = Nothing }

"""
{
  "type": "Feature",
  "id": "0157",
  "geometry": {
    "type": "Point",
    "coordinates": [127.831, 26.461]
  },
  "properties": {
    "country": "Japan"
  }
}
"""
  |> Decode.decodeString decodeFeature
    --> Ok { geometry = Just (Point [127.831,26.461]), id = Just "0157", properties = Just (Dict.fromList [("country",<internals>)]) }

JSON एनकोडर

एनकोडर आपको Encode.encode : Int -> Value -> String फंक्शन की मदद से Elm की वैल्यू से मान्य JSON लिखने देते हैं। पहला आर्गुमेंट बताता है कि अंतिम नतीजे में कितनी इंडेंटेशन होगी, और दूसरा आर्गुमेंट वह JSON वैल्यू है जिसे लिखना है।

एक Value या तो Decode.value से मिल सकती है, या किसी एक एनकोडर से बनाई जा सकती है:

Encode.encode 0 (Encode.string "hello")
    --> "hello"

Encode.encode 0 (Encode.bool True)
    --> "true"

Encode.encode 0 (Encode.int 12)
    --> "12"

Encode.encode 0 (Encode.float 3.14)
    --> "3.14"

Encode.encode 0 Encode.null
    --> "null"

Encode.encode 0 (Encode.list Encode.int [1, 2, 3])
    --> "[1,2,3]"

Encode.encode 4 (Encode.list Encode.int [1, 2, 3])
    --> "[\n    1,\n    2,\n    3\n]"

Encode.encode 0 (Encode.dict String.toLower Encode.int (Dict.fromList [("KEY1", 17), ("KEY2", 71)]))
    --> "{\"key1\":17,\"key2\":71}"

Encode.encode 4 (Encode.dict String.toLower Encode.int (Dict.fromList [("KEY1", 17), ("KEY2", 71)]))
    --> "{\n    \"key1\": 17,\n    \"key2\": 71\n}"

और इसी तरह Encode.object : List ( String, Value ) -> Value के साथ भी

Encode.object
    [ ( "key1", Encode.int 17 )
    , ( "key2", Encode.int 71 )
    ]
    |> Encode.encode 0
    --> "{\"key1\":17,\"key2\":71}"

आइए अब उन GeoJSON डिकोडरों के लिए एनकोडर बनाते हैं जो हमने पहले बनाए थे

encodeGeometry : Geometry -> Value
encodeGeometry geometry =
    case geometry of
        Point coord ->
            Encode.object
                [ ( "type", Encode.string "Point" )
                , ( "coordinates", Encode.list Encode.float coord )
                ]

        LineString coord ->
            Encode.object
                [ ( "type", Encode.string "LineString" )
                , ( "coordinates", Encode.list (Encode.list Encode.float) coord )
                ]

encodeFeature : Feature -> Value
encodeFeature feature =
    let
        maybeId =
            case feature.id of
                Nothing ->
                    []

                Just id ->
                    [ ( "id", Encode.string id ) ]
    in
    Encode.object
        (maybeId
            ++ [ ( "type", Encode.string "Feature" )
               , ( "geometry"
                 , case feature.geometry of
                    Nothing ->
                        Encode.null

                    Just geometry ->
                        encodeGeometry geometry
                 )
               , ( "properties"
                 , case feature.properties of
                    Nothing ->
                        Encode.null

                    Just dict ->
                        Encode.dict identity identity dict
                 )
               ]
        )

सामान्य तौर पर, अपने डिकोडर-एनकोडर जोड़ों की अच्छी जाँच यह है कि आप देखें कि elmValue |> encoder |> decoder == elmValue सही है।

निर्देश

प्रोग्रामिंग के बारे में आप जितना अधिक सीखते हैं, उतना ही आप सोचने लगते हैं कि यह सिर्फ एक चलन भर से ज़्यादा हो सकता है। इसमें कारोबार के मौके भी हो सकते हैं: लोग कोड लिखते हैं, वे उसे सहेजना चाहते हैं, साझा करना चाहते हैं, मिलकर काम करना चाहते हैं, और शायद कुछ प्रतिक्रिया भी पाना चाहते हैं।

ठीक है, चलिए करते हैं, चलिए एक ऐसी सेवा बनाते हैं जो लोगों को कोड करने के लिए प्रेरित करे: हुप, हुप, लोगो, git का इस्तेमाल शुरू कीजिए! चलिए इसका नाम रखते हैं... GitHup.

आप एक REST JSON API बनाना शुरू करते हैं: यूज़र, पुल रिक्वेस्ट, कमेंट, बैकएंड जल्दी ही तैयार हो जाता है। यहाँ एक उदाहरण है, जब आप सर्वर से किसी पुल रिक्वेस्ट पर कमेंट की सूची माँगते हैं तो जो पेलोड मिलता है:

[
  {
    "id": 256,
    "pull_request_review_id": 42,
    "user": {
      "id": 101,
      "login": "octodog",
      "avatar_url": "https://githup.com/images/error/octodog_happy.gif",
      "site_admin": false
    },
    "body": "Great stuff!",
    "side": "RIGHT",
    "_links": {
      "self": {
        "href": "https://api.githup.com/repos/octodog/Hello-World/pulls/comments/1"
      },
      "html": {
        "href": "https://githup.com/octodog/Hello-World/pull/1#discussion-diff-1"
      },
      "pull_request": {
        "href": "https://api.githup.com/repos/octodog/Hello-World/pulls/1"
      }
    }
  },
  {
    "id": 11,
    "pull_request_review_id": null,
    "user": {
      "id": 2,
      "login": "hexacat",
      "name": "Alex Kate",
      "avatar_url": "https://githup.com/images/error/hexacat_happy.gif",
      "site_admin": true
    },
    "body": "Amazing stuff!",
    "side": "LEFT",
    "_links": {
      "self": {
        "href": "https://api.githup.com/repos/octodog/Hello-World/pulls/comments/1"
      }
    }
  }
]

बेशक, फ्रंटएंड Elm में बनेगा, लेकिन पहले आपको समझना होगा कि वे मशहूर डिकोडर और एनकोडर वास्तव में क्या हैं।

Note

हास्य कहानी को एक तरफ रखकर, इस अभ्यास की आवश्यकताएँ सीधे GitHub के REST API एंडपॉइंट से ली गई हैं, जो पुल रिक्वेस्ट रिव्यू कमेंट के लिए हैं। कुछ फील्ड JSON स्कीमा से आसानी के लिए हटा दिए गए हैं, लेकिन यह वास्तविक दुनिया के अनुप्रयोगों के जितना करीब हो सकता है, उतना करीब है।

1. आईडी, प्लीज़!

आपकी तेज़ नज़र ने देख लिया है कि कमेंट और यूज़र, दोनों में एक id फील्ड है, शुरू करने की बढ़िया जगह।

decodeId को इस तरह बनाइए कि यह एक JSON ऑब्जेक्ट डिकोड कर सके, जिसमें एक पूर्णांक id हो।

Decode.decodeString decodeId """{id: 10}"""
    --> Ok 10

2. मेरा नाम फिर से क्या है?

आप ऊपर के उदाहरण में देखते हैं कि सभी यूज़र के पास नाम नहीं होता।

decodeName को इस तरह बनाइए कि अगर name फील्ड में कोई स्ट्रिंग हो तो यह उसे डिकोड कर सके। नाम नहीं है? कोई बात नहीं, बस Nothing लौटाइए। यह डिकोडर कभी फेल नहीं होना चाहिए।

Decode.decodeString decodeName """{"id": 10, "name": "Otto"}"""
    --> Ok (Just Otto)

Decode.decodeString decodeName """null"""
    --> Ok Nothing

3. यूज़र? हम तो इसे जानते ही नहीं!

यूज़र डिकोड करने में हम लगभग आधे रास्ते पर हैं, चलिए इसे पूरा करते हैं।

decodeUser को इस तरह बनाइए कि यह एक JSON यूज़र ऑब्जेक्ट डिकोड कर सके। ध्यान रखिए कि decodeUser में decodeId और decodeName का इस्तेमाल कीजिए।

Decode.decodeString decodeUser
    """
    {
      "id": 101,
      "login": "octodog",
      "avatar_url": "https://githup.com/images/error/octodog_happy.gif",
      "site_admin": false
    }
    """
    --> Ok
    -->   { id = 101
    -->   , name = Nothing
    -->   , login = "octodog"
    -->   , avatarUrl = "https://githup.com/images/error/octodog_happy.gif
    -->   , siteAdmin = False
    -->   }

4. मैं एक मज़बूत और स्वतंत्र कमेंट हूँ

पुल रिव्यू में कुछ कमेंट अलग-थलग होते हैं, और इसलिए उनमें pull_request_review_id नहीं होता। लेकिन स्पेसिफिकेशन कहता है कि ऐसी स्थिति में भी pull_request_review_id फील्ड होना चाहिए, बस उसकी वैल्यू null होनी चाहिए, यानी गरीब आदमी का Nothing।

decodePullRequestReviewId को इस तरह बनाइए कि अगर pull_request_review_id फील्ड में कोई पूर्णांक हो तो यह उसे डिकोड कर सके। अगर पूर्णांक नहीं है, तो वहाँ null होना चाहिए, और अगर null नहीं है तो डिकोडर फेल हो जाना चाहिए।

Decode.decodeString decodePullRequestReviewId """{"pull_request_review_id": 3}"""
    --> Ok (Just 3)

Decode.decodeString decodePullRequestReviewId """{"pull_request_review_id": null}"""
    --> Ok Nothing

Decode.decodeString decodePullRequestReviewId """{"id": 3}"""
    --> Err ...

5. साइड का काम

अगला है यह दिलचस्प दिखने वाला side फील्ड। पुल रिव्यू में आप उस कोड पर कमेंट कर सकते हैं जो हटाया गया था (स्क्रीन के Left तरफ) या उस कोड पर जो जोड़ा गया था (स्क्रीन के Right तरफ)।

decodeSide को इस तरह बनाइए कि यह side फील्ड में "LEFT" या "RIGHT" डिकोड कर सके और उसे उसके मिलते-जुलते टाइप वेरिएंट से मिला सके।

Decode.decodeString decodeSide """{"side": "LEFT"}"""
    --> Ok Left

Decode.decodeString decodeSide """{"side": "middle?"}"""
    --> Err ...

6. लिंक्स की जागृति

हर कमेंट में लिंक का एक समूह होता है, जो हर कमेंट में एक जैसा नहीं लगता।

decodeLinks को इस तरह बनाइए कि यह _links फील्ड में URL के एक संग्रह को डिकोड कर सके। लिंक के नाम और संख्या बदल सकते हैं, ध्यान रखिए कि आप इसे संभाल सकें। लिंक खुद JSON ऑब्जेक्ट होते हैं, जिनमें हमेशा एक href फील्ड होना चाहिए।

Decode.decodeString decodeLinks """
    {
      "_links": {
        "self": { "href": "https://api.githup.com/repos/octodog/Hello-World/pulls/comments/1" },
        "html": { "href": "https://githup.com/octodog/Hello-World/pull/1#discussion-diff-1" },
        "pull_request": { "href": "https://api.githup.com/repos/octodog/Hello-World/pulls/1" }
      }
    }
    """
    --> Ok
    -->   (Dict.fromList
    -->       [ ( "self", "https://api.githup.com/repos/octodog/Hello-World/pulls/comments/1" )
    -->       , ( "html", "https://githup.com/octodog/Hello-World/pull/1#discussion-diff-1" )
    -->       , ( "pull_request", "https://api.githup.com/repos/octodog/Hello-World/pulls/1" )
    -->       ]
    -->   )

7. हाँ, कमेंट

बस थोड़ी ही दूर बाकी है, चलिए इसे पूरा करते हैं।

decodeComment और decodeComments को इस तरह बनाइए कि ये क्रमशः एक अकेले JSON कमेंट ऑब्जेक्ट या कमेंट की एक सूची को डिकोड कर सकें। ध्यान रखिए कि decodeComment में अब तक बनाए गए सभी फंक्शन इस्तेमाल हों, decodeName को छोड़कर। बेशक, decodeComments को भी decodeComment इस्तेमाल करना चाहिए।

8. अब सब जुड़ता है

इन सबमें एक फीचर अभी भी छूटा हुआ है: सर्वर को एक नया कमेंट भेज पाना। इसके लिए आपको डिकोडर के उलट करना है, यानी आपको एक Elm Comment को JSON Value में बदल पाना चाहिए।

encodeComment को इस तरह बनाइए कि यह किसी भी मान्य Comment को एनकोड कर सके। फील्ड का क्रम मायने नहीं रखता, बस एनकोडर ऐसी वैल्यू बनाए जिसे decodeComment डिकोड कर सके।

GitHub के ज़रिए संपादित करें यह लिंक एक नई विंडो या टैब में खुलता है
Elm Exercism

GitHup API शुरू करने के लिए तैयार हैं?

Exercism पर साइन अप कीजिए और Elm को 28 कॉन्सेप्ट110 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।