I've been trying to extract some JSON by unmarshalling my json response into structs, but I have no idea why it's not doing it properly. I've also tried gjson but same result. Am I missing something here?
JSON Result:
{"availabilities":[{"pickup":{"status":"OnlineOnly","purchasable":false},"shipping":{"status":"InStockOnlineOnly","purchasable":true},"sku":"12341231","sellerId":"438178","saleChannelExclusivity":"OnlineOnly","scheduledDelivery":false,"isGiftCard":false,"isService":false}]}
Code:
// Inventory ...
type Inventory struct {
Availabilities []Availability `json:"availabilities"`
}
// Availability ...
type Availability struct {
Sku string `json:"sku"`
SellerID string `json:"sellerId"`
SaleChannelExclusivity string `json:"saleChannelExclusivity"`
ScheduledDelivery bool `json:"scheduledDelivery"`
IsGiftCard bool `json:"isGiftCard"`
IsService bool `json:"isService"`
Pickup Statuses `json:"pickup"`
Shipping Statuses `json:"shipping"`
}
// Statuses ..
type Statuses struct {
Status string `json:"status"`
Purchasable bool `json:"purchasable"`
}
func (pr *Program) checkInventory() {
url := fmt.Sprintf("https://www.bestbuy.ca/ecomm-api/availability/products?accept-language=en-CA&skus=%s", pr.Sku)
log.Infof("URL %s", url)
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Info(string(bodyBytes))
var inv Inventory
json.Unmarshal(bodyBytes, &inv)
log.Infof("%+v", inv)
}
Console:
INFO[2020-04-07T03:01:10-07:00] URL https://www.bestbuy.ca/ecomm-api/availability/products?accept-language=en-CA&skus=12341231
INFO[2020-04-07T03:01:10-07:00] {"availabilities":[{"pickup":{"status":"OnlineOnly","purchasable":false},"shipping":{"status":"InStockOnlineOnly","purchasable":true},"sku":"12341231
,"sellerId":"438178","saleChannelExclusivity":"OnlineOnly","scheduledDelivery":false,"isGiftCard":false,"isService":false}]}
INFO[2020-04-07T03:01:10-07:00] {Availabilities:[]}
The problem is in the json.Unmarshall call. It is returning an error: "invalid character 'ï' looking for beginning of value” from json.Unmarshal
As it is explained here: The server is sending you a UTF-8 text string with a Byte Order Mark (BOM). The BOM identifies that the text is UTF-8 encoded, but it should be removed before decoding.
This can be done with the following line (using package "bytes"):
body = bytes.TrimPrefix(body, []byte("\xef\xbb\xbf"))
So the resulting working code is:
// Inventory ...
type Inventory struct {
Availabilities []Availability `json:"availabilities"`
}
// Availability ...
type Availability struct {
Sku string `json:"sku"`
SellerID string `json:"sellerId"`
SaleChannelExclusivity string `json:"saleChannelExclusivity"`
ScheduledDelivery bool `json:"scheduledDelivery"`
IsGiftCard bool `json:"isGiftCard"`
IsService bool `json:"isService"`
Pickup Statuses `json:"pickup"`
Shipping Statuses `json:"shipping"`
}
// Statuses ..
type Statuses struct {
Status string `json:"status"`
Purchasable bool `json:"purchasable"`
}
func (pr *Program) checkInventory() {
url := fmt.Sprintf("https://www.bestbuy.ca/ecomm-api/availability/products?accept-language=en-CA&skus=%s", pr.Sku)
log.Infof("URL %s", url)
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
body := bytes.TrimPrefix(bodyBytes, []byte("\xef\xbb\xbf"))
log.Info(string(body))
var inv Inventory
err = json.Unmarshal([]byte(body), &inv)
if err != nil {
log.Fatal(err)
}
log.Infof("%+v", inv)
}
Related
Im trying to unmarshal json response from vcenter rest api. when the response body is simply printed it looks like the o/p below
{"value":[{"memory_size_MiB":16384,"vm":"vm-10236","name":"Normal_Windows_192.168.1.10","power_state":"POWERED_OFF","cpu_count":8},{"memory_size_MiB":8192,"vm":"vm-10238","name":"Normal_Windows_192.168.1.11","power_state":"POWERED_OFF","cpu_count":4}]}
i have exported both struct and struct fields however the fields like memory_size_MiB, power_state,cpu_count is not being unmarshalled. when the struct is printed it looks like below:-
{Value:[{Mem:0 Vm:vm-10236 Name:Normal_Windows_192.168.1.10 Powerstat: Cpu:0} {Mem:0 Vm:vm-10238 Name:Normal_Windows_192.168.1.11 Powerstat: Cpu:0} {Mem:0 Vm:vm-10582 Name:Normal_Windows_192.168.1.12 Powerstat: Cpu:0}]}%
Below is my main.go
package main
import (
...
)
type SessionData struct {
VmwareApiSessionId string `json:"value"`
}
//{"memory_size_MiB":16384,"vm":"vm-10236","name":"Normal_Windows_192.168.19.100","power_state":"POWERED_OFF","cpu_count":8}
type Vm struct {
Mem int `json: "memory_size_MiB"`
Vm string `json: "vm"`
Name string `json: "name"`
Powerstat string `json: "power_state"`
Cpu int `json: "cpu_count"`
}
//{Value:[{Mem:0 Vm:vm-10236 Name:Normal_Windows_192.168.1.10 Powerstat: Cpu:0} {Mem:0 Vm:vm-10238 Name:Normal_Windows_192.168.1.11 Powerstat: Cpu:0} {Mem:0 Vm:vm-10582 Name:Normal_Windows_192.168.1.12 Powerstat: Cpu:0}]}
type ColVmList struct {
Value []Vm `json: "value"`
}
func getVmList(sessid string,cli *http.Client) ColVmList {
vms := ColVmList{}
req,err:=http.NewRequest("GET","https://sandbox.vmware.local/rest/vcenter/vm",nil)
req.Header.Add("vmware-api-session-id",sessid)
resp,err := cli.Do(req)
if err != nil {
log.Fatal("Error %s", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
err = json.Unmarshal([]byte(body),&vms)
if err != nil {
log.Fatal("error %s", err)
}
return vms
}
func main(){
//authpart
loginurl = "https://sandbox.vmware.local/rest/com/vmware/cis/session"
//login...
err = json.Unmarshal([]byte(string(body)),&sessVal)
if err != nil{
log.Fatal(err)
}
var allvmlist ColVmList
allvmlist = getVmList(sessVal.VmwareApiSessionId,&cli)
fmt.Printf("%v",allvmlist)
}
Your struct tags are not well formed. Remove the space between json: and the string "..." in the struct tags. i.e. it MUST be json:"..." not json: "...".
And the reason some fields are correctly unmarshaled even with not well-formed struct tags is because the fields' names match the json property names.
func main() {
data := []byte(`{"memory_size_MiB":16384}`)
var obj1 struct {
Mem int `json: "memory_size_MiB"`
}
if err := json.Unmarshal(data, &obj1); err != nil {
panic(err)
}
fmt.Println(obj1)
var obj2 struct {
Mem int `json:"memory_size_MiB"`
}
if err := json.Unmarshal(data, &obj2); err != nil {
panic(err)
}
fmt.Println(obj2)
}
https://go.dev/play/p/gUR5ed2n0D1
How can I do something Like this?
I am trying to pass a struct as a parameter to function in Go.
func handleEntityProperties(w http.ResponseWriter, r *http.Request) {
const sliceSize = 100
var entityProperties struct {
Instance string `json:"instance"`
Entities []struct {
Id string `json:"id"`
Properties map[string]string `json:"properties"`
Type string `json:"type"`
} `json:"entities"`
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
if !json.Valid([]byte(body)) {
fmt.Fprintf(w, "invalid json")
return
}
err = json.Unmarshal(body, &entityProperties)
sendData(entityProperties.Entities[0:100])
return
}
func sendData(entities struct) {
log.Println("Doing things with entities ", entities)
}
as you can see in code I am trying to send first 100 elements of entityProperties.Entities struct to a sendData. I know this is syntactically wrong.
Just declare your type outside of the functions:
type entity struct {
Id string `json:"id"`
Properties map[string]string `json:"properties"`
Type string `json:"type"`
}
And reuse it in handleEntityProperties() and in the signature of sendData():
func handleEntityProperties(w http.ResponseWriter, r *http.Request) {
const sliceSize = 100
var entityProperties struct {
Instance string `json:"instance"`
Entities []entity `json:"entities"`
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
if !json.Valid([]byte(body)) {
fmt.Fprintf(w, "invalid json")
return
}
err = json.Unmarshal(body, &entityProperties)
sendData(entityProperties.Entities[0:sliceSize])
return
}
func sendData(entities []entity) {
log.Println("Doing things with entities ", entities)
}
Also note that there is no guarantee that the client will send at least 100 entities, so you should check that else the slicing expression might result in a runtime panic:
max := 100
if len(entityProperties.Entities) < max {
max = len(entityProperties.Entities)
}
sendData(entityProperties.Entities[:max])
Also that check for invalid JSON is unnecessary: if the JSON is invalid, json.Unmarshal() will report a (non-nil) error and you'll know it.
Going further, you don't even have to read the complete body into memory (into a byte slice), you may use json.Decoder to read from it directly (without the intermediate memory buffer) like this:
dec := json.NewDecoder(r.Body)
if err := dec.Decode(&entityProperties); err != nil {
// handle error
}
And the final return statement is also unnecessary.
So an improved version may look like this:
func handleEntityProperties(w http.ResponseWriter, r *http.Request) {
var entityProperties struct {
Instance string `json:"instance"`
Entities []entity `json:"entities"`
}
dec := json.NewDecoder(r.Body)
if err := dec.Decode(&entityProperties); err != nil {
// handle error
http.Error(w, "invalid json", http.StatusBadRequest)
return
}
max := 100
if len(entityProperties.Entities) < max {
max = len(entityProperties.Entities)
}
sendData(entityProperties.Entities[:max])
}
In my api server I return a json object which has string arrays in it. I am finding that my arrays are being embedded into another array like this:
"Items": [
"[\"QQTISGXSJIS4DEV36JCBWQ4X\", \"HCOWEB7NVIQEUAINMM2KUV6J\", \"FCKP7D3H6Q7RQIRKSPVZBRHL\", \"UQLVH65PPBTVK6KMIV5KMGY6\", \"UR2XTXJFVURE5ERBLNW7ZUCR\", \"75N66F4DYGPM57V47N3IBMKD\", \"HQ2CRXQFPQM7TNNDZXZ2MQ2B\", \"3SLGKFR5GPHVZMQM4YM6KI4U\", \"UCQ3J7GYAYPZOCQKWIRGNGNY\", \"6INWDYWUFX6L5JYX2HEVMMHX\", \"ASQBRMKYSK2TINHBYQIWATS5\", \"QPCHVJ4HXYTUJNEZWQCKM5I3\", \"7JPYYH64Y3FQK6YJX5NBXMM6\", \"BI4NIBBOFBYAAS7ZROD6XEMB\", \"RGU3X36VYMXX4N3XPEZKY76K\", \"PLHVIQ7QT6TBWI5BZX6EJI74\", \"YATHGR6W6BIKFYXVZMGVBRB4\", \"ZZ5KZ5ZSBVLQRDKR2SJQ5CXW\", \"TNH56AOIMFSLOX5AW5I6WYP2\", \"VIFSURNJWJ6YYKXIWTWRNY6F\"]"
]
You can a complete JSON object here: https://gist.github.com/yshuman1/31b39333e2cd187707d98817171c3914
I am using gorm and saving my array as pq.StringArray.
Here is my function that returns that json:
func (u *Users) RetrieveItemCatModSort(w http.ResponseWriter, r *http.Request) {
var l model.ItemCatModSort
type data struct {
Email string
Password string
Location string
}
var form data
if err := parseForm(r, &form); err != nil {
log.Infof("error parsing form for logging in Kiosk %v", err)
return
}
user, err := u.us.ByEmail(string(form.Email))
if err != nil {
log.Infof("error looking up user by email while retrieving items %v", err)
return
}
bcrypt.CompareHashAndPassword([]byte(user.KioskPwHash), []byte(form.Password))
if err != nil {
log.Infof("invalid login credentials error: %v submitted data:\n%#v", err, form)
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(422) // unprocessable entity
if err := json.NewEncoder(w).Encode(err); err != nil {
panic(err)
}
}
//lookup oauth token in DB
token, err := u.os.Find(user.ID, "square")
if err != nil {
fmt.Println(err)
}
l.LocationID = form.Location
l.Modifiers, err = pos.GetModifiers(token.AccessToken, l.LocationID)
if err != nil {
log.Infof("Error grabbing modifiers using GetInventory. %#v", err)
}
l.Categories, err = pos.GetCategories(token.AccessToken)
if err != nil {
log.Infof("Error grabbing categories using GetInventory. %#v", err)
}
l.Items, err = pos.GetItems(token.AccessToken, l.LocationID)
if err != nil {
log.Infof("Error grabbing items using GetInventory. %#v", err)
}
l.ItemSort, err = u.is.FindItemSortByLocation(l.LocationID)
if err != nil {
log.Infof("Error grabbing item sort. %#v", err)
}
l.CatSort, err = u.is.FindCatSortByLocation(l.LocationID)
if err != nil {
log.Infof("Error grabbing cat sort. %#v", err)
}
lJSON, err := json.Marshal(l)
if err != nil {
log.Infof("error marshalling data to lJSON inside RetrieveLocationInv %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(lJSON)
}
Here are some of the models that I use:
type Categories struct {
Categories []Category `json:"objects"`
}
type ItemCatModSort struct {
LocationID string
Categories Categories
Items []Item
Modifiers []Modifier
ItemSort []ItemSort
CatSort CatSort
}
type CatSort struct {
gorm.Model
LocationID string
Category pq.StringArray `gorm:"type:varchar(10485760)[]"`
}
type Item struct {
gorm.Model
Type string `json:"type"`
ID string `json:"id"`
UpdatedAt time.Time `json:"updated_at"`
Version int64 `json:"version"`
IsDeleted bool `json:"is_deleted"`
PresentAtAllLocations bool `json:"present_at_all_locations"`
PresentAtLocationIds []string `json:"present_at_location_ids"`
AbsentAtLocationIds []string `json:"absent_at_location_ids"`
ItemData struct {
Name string `json:"name"`
Description string `json:"description"`
Visibility string `json:"visibility"`
CategoryID string `json:"category_id"`
ModifierListInfo []struct {
ModifierListID string `json:"modifier_list_id"`
Visibility string `json:"visibility"`
MinSelectedModifiers int `json:"min_selected_modifiers"`
MaxSelectedModifiers int `json:"max_selected_modifiers"`
Enabled bool `json:"enabled"`
} `json:"modifier_list_info"`
ImageURL string `json:"image_url"`
Variations []struct {
Type string `json:"type"`
ID string `json:"id"`
UpdatedAt time.Time `json:"updated_at"`
Version int64 `json:"version"`
IsDeleted bool `json:"is_deleted"`
PresentAtAllLocations bool `json:"present_at_all_locations"`
PresentAtLocationIds []string `json:"present_at_location_ids"`
AbsentAtLocationIds []string `json:"absent_at_location_ids"`
ItemVariationData struct {
ItemID string `json:"item_id"`
Name string `json:"name"`
Sku string `json:"sku"`
Ordinal int `json:"ordinal"`
PricingType string `json:"pricing_type"`
PriceMoney struct {
Amount int `json:"amount"`
Currency string `json:"currency"`
} `json:"price_money"`
} `json:"item_variation_data"`
} `json:"variations"`
ProductType string `json:"product_type"`
SkipModifierScreen bool `json:"skip_modifier_screen"`
} `json:"item_data"`
}
basically instead of
"Items": [
"[\"QQTISGXSJIS4DEV36JCBWQ4X\", \"HCOWEB7NVIQEUAINMM2KUV6J\",... \"VIFSURNJWJ6YYKXIWTWRNY6F\"]" ]
looking like that, I'd want it to look like this:
"Items": ["QQTISGXSJIS4DEV36JCBWQ4X\", \"HCOWEB7NVIQEUAINMM2KUV6J\",... \"VIFSURNJWJ6YYKXIWTWRNY6F\" ]
I'm trying to get informations from my db, and one of my fields is actually JSON stored as a string and I would like to get it as a struct.
This is my row's struct :
//there is json flag because I use it to get data from redis too
type InfoClip struct {
ClipId string `json:clipId`
StreamUrl string `json:streamUrl`
StartTimeCode int `json:startTimeCode`
EndTimeCode int `json:endTimeCode`
CreatedAt string `json:createdAt`
Metas string `json:metas` // here I get a string instead of a 'metas' struct
SourceId string `json:sourceId`
ProviderName string `json:providerName`
ProviderReference string `json:providerReference`
PublicationStatus string `json:publicationStatus`
UserId string `json:userId`
Name string `json:name`
FacebookPage string `json:facebookPage`
TwitterHandle string `json:twitterHandle`
PermaLinkUrl string `json:permalinkUrl`
Logo string `json:logo`
Link string `json:link`
}
This is my metas struct :
type metas struct {
Title string `json:title`
Tags []string `json:tags`
categories []string `json:permalink`
}
This is how I'm trying to get this field
func decodeJsonSql (met string) (*metas, error) {
m := metas{}
if err := json.Unmarshal([]byte(met), &m); err != nil {
fmt.Printf("Error decode metas: ", err)
return nil, err
} else {
return &m, err
}
}
func CheckIdSql(mediaId string) (error){
datab, err := sql.Open("mysql", "tcp()")
if err != nil {
fmt.Printf("[SQL ERROR] Cannot Open db => ", err)
return err
}
if err := datab.Ping(); err != nil {
fmt.Printf("[SQL ERROR] db connection => ", err)
return err
}
fmt.Printf("[SQL ONLINE] =>", datab)
defer datab.Close()
q := "SELECT c.id AS clipId, c.streamUrl, c.startTimecode, c.endTimecode, c.createdAt, s.metas,... FROM clips WHERE c.id = ?"
rows, err := datab.Query(q, mediaId)
if err != nil || err == sql.ErrNoRows {
fmt.Printf("SQL Err: %s", err)
return err
}
clips := InfoClip{}
for rows.Next() {
rows.Scan(&clips.ClipId, &clips.StreamUrl, &clips.StartTimeCode, &clips.EndTimeCode, &clips.CreatedAt, &clips.Metas, ...)
}
ret, err := decodeJsonSql(clips.Metas)
if err != nil{
return err
}
clips.Metas = ret
fmt.Printf("\n\n[SQL DEBUG RESPONSE]: %v", clips)
return nil
}
But this process is pretty heavy, surely there is an easier way?
Thanks.
You can make your metas struct implement the sql.Scanner interface
It should look something like this:
func (m *metas) Scan(src interface{}) error {
strValue, ok := src.(string)
if !ok {
return fmt.Errorf("metas field must be a string, got %T instead", src)
}
return json.Unmarshal([]byte(strValue), m)
}
After that you can use it as an InfoClip field and pass it directly to Scan and drop the decodeJsonSql:
type InfoClip struct {
// [...]
Metas metas `json:metas`
// [...]
}
and
q := "SELECT c.id AS clipId, c.streamUrl, c.startTimecode, c.endTimecode, c.createdAt, s.metas,... FROM clips WHERE c.id = ?"
row := datab.QueryRow(q, mediaId)
clips := InfoClip{}
err := row.Scan(&clips.ClipId, &clips.StreamUrl, &clips.StartTimeCode, &clips.EndTimeCode, &clips.CreatedAt, &clips.Metas) // [...]
if err != nil {
fmt.Printf("SQL Err: %s", err)
return err
}
(BTW, as you can see, I replaced datab.Query with datab.QueryRow as you are expecting only one result)
Is it possible to generate an error if a field was not found while parsing a JSON input using Go?
I could not find it in documentation.
Is there any tag that specifies the field as required?
There is no tag in the encoding/json package that sets a field to "required". You will either have to write your own MarshalJSON() method, or do a post check for missing fields.
To check for missing fields, you will have to use pointers in order to distinguish between missing/null and zero values:
type JsonStruct struct {
String *string
Number *float64
}
Full working example:
package main
import (
"fmt"
"encoding/json"
)
type JsonStruct struct {
String *string
Number *float64
}
var rawJson = []byte(`{
"string":"We do not provide a number"
}`)
func main() {
var s *JsonStruct
err := json.Unmarshal(rawJson, &s)
if err != nil {
panic(err)
}
if s.String == nil {
panic("String is missing or null!")
}
if s.Number == nil {
panic("Number is missing or null!")
}
fmt.Printf("String: %s Number: %f\n", *s.String, *s.Number)
}
Playground
You can also override the unmarshalling for a specific type (so a required field buried in a few json layers) without having to make the field a pointer. UnmarshalJSON is defined by the Unmarshaler interface.
type EnumItem struct {
Named
Value string
}
func (item *EnumItem) UnmarshalJSON(data []byte) (err error) {
required := struct {
Value *string `json:"value"`
}{}
all := struct {
Named
Value string `json:"value"`
}{}
err = json.Unmarshal(data, &required)
if err != nil {
return
} else if required.Value == nil {
err = fmt.Errorf("Required field for EnumItem missing")
} else {
err = json.Unmarshal(data, &all)
item.Named = all.Named
item.Value = all.Value
}
return
}
Here is another way by checking your customized tag
you can create a tag for your struct like:
type Profile struct {
Name string `yourprojectname:"required"`
Age int
}
Use reflect to check if the tag is assigned required value
func (p *Profile) Unmarshal(data []byte) error {
err := json.Unmarshal(data, p)
if err != nil {
return err
}
fields := reflect.ValueOf(p).Elem()
for i := 0; i < fields.NumField(); i++ {
yourpojectTags := fields.Type().Field(i).Tag.Get("yourprojectname")
if strings.Contains(yourpojectTags, "required") && fields.Field(i).IsZero() {
return errors.New("required field is missing")
}
}
return nil
}
And test cases are like:
func main() {
profile1 := `{"Name":"foo", "Age":20}`
profile2 := `{"Name":"", "Age":21}`
var profile Profile
err := profile.Unmarshal([]byte(profile1))
if err != nil {
log.Printf("profile1 unmarshal error: %s\n", err.Error())
return
}
fmt.Printf("profile1 unmarshal: %v\n", profile)
err = profile.Unmarshal([]byte(profile2))
if err != nil {
log.Printf("profile2 unmarshal error: %s\n", err.Error())
return
}
fmt.Printf("profile2 unmarshal: %v\n", profile)
}
Result:
profile1 unmarshal: {foo 20}
2009/11/10 23:00:00 profile2 unmarshal error: required field is missing
You can go to Playground to have a look at the completed code
You can just implement the Unmarshaler interface to customize how your JSON gets unmarshalled.
you can also make use of JSON schema validation.
package main
import (
"encoding/json"
"fmt"
"github.com/alecthomas/jsonschema"
"github.com/xeipuuv/gojsonschema"
)
type Bird struct {
Species string `json:"birdType"`
Description string `json:"what it does" jsonschema:"required"`
}
func main() {
var bird Bird
sc := jsonschema.Reflect(&bird)
b, _ := json.Marshal(sc)
fmt.Println(string(b))
loader := gojsonschema.NewStringLoader(string(b))
documentLoader := gojsonschema.NewStringLoader(`{"birdType": "pigeon"}`)
schema, err := gojsonschema.NewSchema(loader)
if err != nil {
panic("nop")
}
result, err := schema.Validate(documentLoader)
if err != nil {
panic("nop")
}
if result.Valid() {
fmt.Printf("The document is valid\n")
} else {
fmt.Printf("The document is not valid. see errors :\n")
for _, err := range result.Errors() {
// Err implements the ResultError interface
fmt.Printf("- %s\n", err)
}
}
}
Outputs
{"$schema":"http://json-schema.org/draft-04/schema#","$ref":"#/definitions/Bird","definitions":{"Bird":{"required":["birdType","what it does"],"properties":{"birdType":{"type":"string"},"what it does":{"type":"string"}},"additionalProperties":false,"type":"object"}}}
The document is not valid. see errors :
- (root): what it does is required
code example taken from Strict JSON parsing