I am trying to use generics to implement my api library (the following code mocks api request and response). But I always get this error
(NonEmptyList (NonEmpty (ErrorAtProperty "contents" (TypeMismatch "String" "Undefined")) ((ErrorAtProperty "contents" (TypeMismatch "String" "Undefined")) : Nil)))
I understand that when we decode json and if it has nested types then it needs data in certain format. But I cannot provide that from js. What is the best way to decode the json to a type in purescript.
module GenericsExample where
import Prelude
import Control.Monad.Except
import Data.Either (Either(..))
import Data.Foreign (ForeignError(..))
import Data.Foreign.Class (class Decode, class Encode)
import Data.Foreign.Generic (decodeJSON, defaultOptions, encodeJSON, genericDecode, genericEncode, genericEncodeJSON, genericDecodeJSON)
import Data.Generic (toSignature)
import Data.Generic (class Generic) as G
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Data.Foreign.Generic.Class
type Headers = Array (Array String)
data METHOD = POST | GET | PUT | DELETE
data STATUS = SUCCESS | FAILURE
type StatusCode = Int
type URL = String
newtype Request = Request {
method :: METHOD,
url :: String,
payload :: String,
headers :: Headers
}
class Requestables a where
toRequest :: Encode a => METHOD -> URL -> Headers -> a -> Request
class Responsables a where
fromResponse :: Decode a => String -> a
class ApiRequest a b where
callApi :: Requestables a => Responsables b => METHOD -> URL -> Headers -> a -> b
newtype RegisterRequest = RegisterRequest {
merchantId ::String,
merchantChannelId ::String,
mcc ::String,
merchantCustomerId ::String,
deviceId ::String,
os ::String,
version ::String,
appVersion ::String,
packageName ::String,
manufacturer ::String,
model ::String,
merchantRequestId ::String,
customerMobileNumber ::String,
customerEmail ::String,
udfParameters ::String,
checksum ::String,
merchantChecksum ::String
}
newtype RegisterResponsePayload = RegisterResponsePayload{
status:: String,
merchantId:: String,
merchantCustomerId:: String,
merchantChannelId:: String,
merchantRequestId:: String,
customerVpa::String,
customerMobileNumber::String,
bankCode :: String,
maskedAccountNumber :: String,
bankAccountUniqueId:: String,
customResponse :: String,
checksum :: String,
sessionToken :: String
}
newtype RegisterResponse = RegisterResponse {
statusCode :: String,
payload :: RegisterResponsePayload,
status :: String
}
newtype ErrorPayload = ErrorPayload {
error :: Boolean,
errorCode :: String,
errorDescription :: String
}
type ErrorResponse = {
statusCode :: String,
status :: String,
payload :: ErrorPayload
}
derive instance genericRegisterRequest :: Generic RegisterRequest _
instance registerRequest :: Requestables RegisterRequest where
toRequest method url headers request = Request { method : method , url : url , headers : headers, payload : payload} where
payload = genericEncodeJSON (defaultOptions { unwrapSingleConstructors = true }) request
data ResponsePayload a = ResponsePayload a | ERR ErrorResponse
instance decodeResponsePayloadRegisterResponse :: Decode (ResponsePayload RegisterResponse) where
decode x = genericDecode (defaultOptions { unwrapSingleConstructors = true }) x
instance decodeRegisterResponse :: Decode RegisterResponse where
decode x = genericDecode (defaultOptions { unwrapSingleConstructors = true }) x
instance decodeErrorPayload :: Decode ErrorPayload where
decode x = genericDecode (defaultOptions { unwrapSingleConstructors = true }) x
instance decodeRegisterResponsePayload :: Decode RegisterResponsePayload where
decode x = genericDecode (defaultOptions { unwrapSingleConstructors = true }) x
instance encodeResponsePayloadRegisterResponse :: Encode (ResponsePayload RegisterResponse) where
encode x = genericEncode (defaultOptions { unwrapSingleConstructors = true }) x
instance encodeRegisterResponse :: Encode RegisterResponse where
encode x = genericEncode (defaultOptions { unwrapSingleConstructors = true }) x
instance encodeRegisterRequest :: Encode RegisterRequest where
encode x = genericEncode (defaultOptions { unwrapSingleConstructors = true }) x
instance encodeErrorPayload :: Encode ErrorPayload where
encode x = genericEncode (defaultOptions { unwrapSingleConstructors = true }) x
instance encodeRegisterResponsePayload :: Encode RegisterResponsePayload where
encode x = genericEncode (defaultOptions { unwrapSingleConstructors = true }) x
derive instance genericErrorPayload :: Generic ErrorPayload _
derive instance genericRegisterResponsePayload :: Generic RegisterResponsePayload _
derive instance genericRegisterResponse :: Generic RegisterResponse _
derive instance genericResponseRegisterResponse :: Generic (ResponsePayload RegisterResponse) _
instance responsablesType :: Responsables (ResponsePayload RegisterResponse) where
fromResponse response = case runExcept (decodeJSON response) of
Right x -> x
Left x -> ERR { status : "200", statusCode : "HIHELLO", payload : ErrorPayload {error : true, errorCode : "-50", errorDescription : show x}}
foreign import callApi' :: Request -> String
instance apiRequestRegister :: ApiRequest RegisterRequest (ResponsePayload RegisterResponse) where
callApi method url headers request = (fromResponse <<< callApi' <<< (toRequest method url headers)) request
test :: RegisterRequest -> ResponsePayload RegisterResponse
test payload = callApi POST "abcdef" [["a", "b"]] payload
main = test $ RegisterRequest {
merchantId :"a",
merchantChannelId :"a",
mcc :"a",
merchantCustomerId :"a",
deviceId :"a",
os :"a",
version :"a",
appVersion :"a",
packageName :"a",
manufacturer :"a",
model :"a",
merchantRequestId :"a",
customerMobileNumber :"a",
customerEmail :"a",
udfParameters :"a",
checksum :"a",
merchantChecksum :"a"
}
exports["callApi'"] = function(a) {
var v = JSON.stringify({
status : "b",
statusCode : "b",
payload : {
status: "a",
merchantId: "a",
merchantCustomerId: "a",
merchantChannelId: "a",
merchantRequestId: "a",
customerVpa: "a",
customerMobileNumber: "a",
bankCode : "a",
maskedAccountNumber : "a",
bankAccountUniqueId: "a",
customResponse : "a",
checksum : "a",
sessionToken : "a"
}
});
console.log(v);
return v
}