Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON responses are not always uniform when response contains an array #15

Open
Zharktas opened this issue Jun 2, 2020 · 1 comment
Open

Comments

@Zharktas
Copy link

Zharktas commented Jun 2, 2020

When calling some SOAP service which returns array of things, the response contains an array if there are more than one thing and object if there is only one thing.

For example calling ListMembers, the response might contain the following:

No services, services is an empty string:

{
    "memberCode": "somecode",
    "xRoadInstance": "someinstance",
    "created": "2018-02-12T08:28:18.799+02:00",
    "name": "somename",
    "subsystems": {
        "subsystem": {
            "created": "2018-03-23T13:45:50.804+02:00",
            "services": "",
            "subsystemCode": "somesubsystemcode",
            "changed": "2018-03-23T13:45:50.804+02:00",
            "fetched": "2020-05-20T10:37:36.775+03:00"
        }
    },
    "memberClass": "someclass",
    "changed": "2018-02-12T08:28:18.799+02:00",
    "fetched": "2020-05-20T10:37:36.775+03:00"
}

Member has a single service, service is an object:

{
    "memberCode": "somecode",
    "xRoadInstance": "someinstance",
    "created": "2017-08-08T15:48:09.458+03:00",
    "name": "somename",
    "subsystems": {
        "subsystem": [{
            "created": "2017-09-13T09:27:16.103+03:00",
            "services": {
                "service": {
                    "serviceVersion": "v1",
                    "wsdl": {
                        "created": "2017-09-18T15:06:19.588+03:00",
                        "externalId": "someid",
                        "changed": "2018-02-02T13:47:49.381+02:00",
                        "fetched": "2019-11-20T06:30:44.414+02:00"
                    },
                    "serviceCode": "somecode",
                    "created": "2017-09-18T15:06:19.449+03:00",
                    "changed": "2017-09-18T15:06:19.449+03:00",
                    "fetched": "2019-11-20T06:30:43.824+02:00"
                }
            },
            "subsystemCode": "somecode",
            "changed": "2017-09-13T09:27:16.103+03:00",
            "fetched": "2020-05-20T10:37:36.775+03:00"
        }, {
            "created": "2017-12-05T09:57:07.870+02:00",
            "services": "",
            "subsystemCode": "somesubsystem",
            "changed": "2017-12-05T09:57:07.870+02:00",
            "fetched": "2020-05-20T10:37:36.775+03:00"
        }]
    }
}

Member has multiple services, services is an array:

{
    "memberCode": "somecode",
    "xRoadInstance": "someinstance",
    "created": "2016-05-20T15:15:48.213+03:00",
    "name": "somename",
    "subsystems": {
        "subsystem": [{
            "created": "2018-11-27T14:37:59.714+02:00",
            "services": "",
            "subsystemCode": "somecode",
            "changed": "2018-11-27T14:37:59.714+02:00",
            "fetched": "2020-05-20T10:37:36.775+03:00"
        }, {
            "created": "2016-06-16T16:53:54.074+03:00",
            "services": "",
            "subsystemCode": "somecode",
            "changed": "2016-06-16T16:53:54.074+03:00",
            "fetched": "2020-05-20T10:37:36.775+03:00"
        }, {
            "created": "2016-05-20T15:15:48.213+03:00",
            "services": {
                "service": [{
                    "serviceVersion": "v1",
                    "wsdl": {
                        "created": "2017-01-27T12:17:18.502+02:00",
                        "externalId": "someid",
                        "changed": "2018-02-05T13:26:34.900+02:00",
                        "fetched": "2018-02-05T13:26:34.900+02:00"
                    },
                    "serviceCode": "somecode",
                    "created": "2017-01-27T12:17:14.600+02:00",
                    "changed": "2017-01-27T12:17:14.600+02:00",
                    "fetched": "2019-08-21T11:09:31.979+03:00"
                }, {
                    "serviceVersion": "v1",
                    "wsdl": {
                        "created": "2017-01-27T12:17:15.866+02:00",
                        "externalId": "someid",
                        "changed": "2018-02-05T13:26:36.870+02:00",
                        "fetched": "2018-02-05T13:26:36.870+02:00"
                    },
                    "serviceCode": "somecode",
                    "created": "2017-01-27T12:17:14.600+02:00",
                    "changed": "2017-01-27T12:17:14.600+02:00",
                    "fetched": "2019-08-21T11:09:31.979+03:00"
                }]
            },
            "subsystemCode": "somecode",
            "changed": "2016-05-20T15:15:48.213+03:00",
            "fetched": "2020-05-20T10:37:36.775+03:00"
        }]
    },
    "memberClass": "someclass",
    "changed": "2016-05-20T15:15:48.213+03:00",
    "fetched": "2020-05-20T10:37:36.775+03:00"
}

This gets cumbersome in more complex responses when parsing them and have to accommodate all three options every time.

@petkivim
Copy link
Contributor

petkivim commented Sep 5, 2020

The REST Adapter Service has been implemented so that it does the message conversions between XML and JSON based on the messages that it receives. In other words, it does not read the schema of the message, but it tries to interpret the correct data type (string, object, array) of an element / property based on the data that's available in the message. Unfortunately, it sometimes produces the outcome that you described.

For example, data about the available services is produced using the listMethods metaservice. The response returned by the listMethods metaservice looks like this when 1) there are no services, 2) there's one service and 3) there are multiple services:

  1. No services:
<xrd:listMethodsResponse>
</xrd:listMethodsResponse>
  1. One service:
<xrd:listMethodsResponse>
   <xrd:service iden:objectType="SERVICE">
      <iden:xRoadInstance>PLAYGROUND</iden:xRoadInstance>
      <iden:memberClass>GOV</iden:memberClass>
      <iden:memberCode>8765432-1</iden:memberCode>
      <iden:subsystemCode>TestService</iden:subsystemCode>
      <iden:serviceCode>getRandom</iden:serviceCode>
      <iden:serviceVersion>v1</iden:serviceVersion>
   </xrd:service>
</xrd:listMethodsResponse>
  1. Multiple services:
<xrd:listMethodsResponse>
   <xrd:service iden:objectType="SERVICE">
      <iden:xRoadInstance>PLAYGROUND</iden:xRoadInstance>
      <iden:memberClass>GOV</iden:memberClass>
      <iden:memberCode>8765432-1</iden:memberCode>
      <iden:subsystemCode>TestService</iden:subsystemCode>
      <iden:serviceCode>getRandom</iden:serviceCode>
      <iden:serviceVersion>v1</iden:serviceVersion>
   </xrd:service>
   <xrd:service iden:objectType="SERVICE">
      <iden:xRoadInstance>PLAYGROUND</iden:xRoadInstance>
      <iden:memberClass>GOV</iden:memberClass>
      <iden:memberCode>8765432-1</iden:memberCode>
      <iden:subsystemCode>TestService</iden:subsystemCode>
      <iden:serviceCode>helloService</iden:serviceCode>
      <iden:serviceVersion>v1</iden:serviceVersion>
   </xrd:service>
</xrd:listMethodsResponse>

Since the REST Adapter Service does not read the schema of the message, it does not know what kind of a data format it should expect - it only sees the data included in the message to be converted. Therefore, case 1 is interpreted as a string, case 2 is interpreted as an object and case 3 is interpreted as an array.

Changing the current behavior so that the REST Adapter Service could reliably recognize the correct data type of an element would require processing the schema of the message to be converted too. Of course, it would require the schema to be available, up-to-date and accessible to the REST Adapter Service both on consumer and provider side. Since the conversion from XML to JSON takes place on the consumer side, the REST Adapter Service on the consumer side should have access to the provider side schema to be able to convert the message correctly. Therefore, implementing a generic support for this kind of conversions is very complicated and error prone.

Another alternative would be to implement the support for predefined services, for example the metaservices provided by the Security Server. However, it does not remove the need to support all the options on the client side in all other cases.

Regards,
Petteri

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants