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 objects returned from open-api.bahn.de are not RFC 4627 compliant #29

Open
nekrondev opened this issue Jan 4, 2017 · 0 comments
Open

Comments

@nekrondev
Copy link

nekrondev commented Jan 4, 2017

UPDATE: Issue is releated to #7 and #8

I did a first test using go-swagger package for Go programming language to use the location service from the OpenData portal. Go's JSON unmarshaler is a RFC 4627 compliant package and it returned unmarshaling errors while processing the result.

I investigated into this matter and found the reasons why. The following code example will show the bad JSON response from the portal and a working RFC compliant result.

Playgound code can be found here: https://play.golang.org/p/UeFSnsVAQp

To make it short:

Server response was

{
"LocationList":{
  "StopLocation":{
    "name":"Itzehoe",
    "lon":"9.510290",
    "lat":"53.923870",
    "id":"008003102"
    }
  }
}

but RFC compliant (and DB API swagger yaml file defined it that way) would be

{
"LocationList":{
  "StopLocation":[{
    "name":"Itzehoe",
    "lon":9.510290,
    "lat":53.923870,
    "id":8003102
    }]
  }
}

Notice the corrected array result for StopLocation with square brackets and the correct double and int32 number formats (DB server returned quoted strings, but yaml file defined double and int32).

As for now using automated tools like go-swagger to create client stubs is not recommended as long as the RFC issues are not fixed.

Cheers,
Nek

Appendix playground code:

package main

import (
	"encoding/json"
	"fmt"
	)

/*
 The http response returned from open-api.bahn.de is not RFC 4627 compliant for the following reasons:

 1. Swagger definition for StopLocation says that lon, lat and id formats are double, double and int32, however the
    returned JSON object returns them as quoted strings and not float point and integer values (i.e. w/out quotes).
    Either the swagger definition file must be modified to return strings or the resulting JSON object must be RFC compliant.

 2. If a single array element is returned the resulting JSON object will not indicate it as an array, i.e. the square brackets are missing.
    For the below example "StopLocation":[{...}] needs to be returned to be again RFC 4627 compliant, even if there is only one element in the StopLocation array.
	The missing array indicator makes parsing JSON objects with single array results not indicated as arrays troublesome and is again not RFC compliant.
*/
 
const (
	HTTP_PAYLOAD_BAD = `{
"LocationList":{
  "StopLocation":{
    "name":"Itzehoe",
    "lon":"9.510290",
    "lat":"53.923870",
    "id":"008003102"
    }
  }
}`

// this is an example for a good response (mark the added square brackets and formatted double and int32 value)
HTTP_PAYLOAD_GOOD = `{
"LocationList":{
  "StopLocation":[{
    "name":"Itzehoe",
    "lon":9.510290,
    "lat":53.923870,
    "id":8003102
    }]
  }
}`
)

// types auto-generated by go-swagger
type LocationResponse struct {

	// location list
	// Required: true
	LocationList *LocationList `json:"LocationList"`
}

type LocationList struct {

	// stop location
	// Required: true
	StopLocation []*StopLocation `json:"StopLocation"`
}

type StopLocation struct {

	// id
	// Required: true
	ID *int32 `json:"id"`

	// lat
	// Required: true
	Lat *float64 `json:"lat"`

	// lon
	// Required: true
	Lon *float64 `json:"lon"`

	// name
	// Required: true
	Name *string `json:"name"`
}

// Main
func main() {
	
	// JSON encoding bad response
	// this will give us json: cannot unmarshal object into Go value of type []*main.StopLocation
	dataBad := &LocationResponse{}
	Decode(HTTP_PAYLOAD_BAD, dataBad)
	
	// if fixed RFC compliant JSON object is parsed everything works like charm
	dataGood := &LocationResponse{}
	Decode(HTTP_PAYLOAD_GOOD, dataGood)
}

// Decode the returned example http response data
func Decode(payload string, result *LocationResponse) {
	err := json.Unmarshal([]byte(payload), result)
	if err != nil {
		fmt.Println(err)
	} else {
		for _, stoploc := range result.LocationList.StopLocation {
			fmt.Printf("Name:%s, Lat:%0.2f, Lon:%0.2f\n", *stoploc.Name, *stoploc.Lat, *stoploc.Lon)
		}
	}
}
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

1 participant