Unmarshall Jsona złego formatu.

0

Czy jest możliwość zwrócenia erroru, w przypadku gdy JSON z Body nie reprezentuje Struktury? W poniższym przykładzie, gdy JSON jest niepoprawny, err jest nilem. W teorii, można sprawdzić czy struktura ma wszystkie pola puste ale co w przypadku gdy ktoś kto korzysta z API się po prostu pomylił i zrobił literówkę? Co w przypadku gdy np. ktoś chciał oddać jakiś produkt i jako cenę poda 0 (taka sama jak warość defaultowa) Nie da się tego rozróżnić od celowego wysłania JSONa z defaultowymi polami.

func main() {
	wrongJson := "{\"nonExistingProperty\": 123}"
	exampleStruct := new(ExampleStruct)
	err := json.Unmarshal([]byte(wrongJson), &exampleStruct)
	fmt.Println(*exampleStruct, err) // OUTPUT: { 0} <nil>
}

type ExampleStruct struct {
	Foo string
	Boo int
}

Znalazłem to: https://stackoverflow.com/questions/49585021/how-to-check-if-a-json-matches-a-struct-struct-fields ale czy jest jakaś inna opcja?

1

A jak ktoś chciał wysłać 10, a przez przypadek wpisze 100?

Albo jeśli chciał 1000 a wpisze 100?

Zastanów się, jaki jest faktycznie problem który chcesz rozwiązać, i czy jest jakiś problem.

0

Musisz dac dokumentacje, i nie mozesz sie zamartwiac co zrobi osoba uzywajaca api po swojej stronie, nie przewidzisz wszystkich przypadkow

1

panowie, to jest bardzo dobre pytanie. Dokumentacja to jedno, ale po cichu ignorowanie dziwnego zachowania klienta to drugie.

Jeśli Ci zależy na tym, aby dać feedback użytkownikowi API, że jakiś klucz jest niepoprawny, to możesz zrobić to np tak

package main

import (
    "fmt"
    "encoding/json"
    )

func main() {
    src_json := []byte(`{"age":21,"married":true}`)
    // Map of interfaces can receive any value types
    u := map[string]interface{}{}
    err := json.Unmarshal(src_json, &u)
    if err != nil {
        panic(err)
    }
    // Type assert values
    // Unmarshal stores "age" as a float even though it's an int.
    fmt.Printf("Age: %1.0f\n", u["age"].(float64))
    fmt.Printf("Married: %v\n", u["married"].(bool))
}

Możesz sobie zrobić listę kluczy, które są spodziewane i wywalić je z mapy. Wtedy to co w mapie zostanie, to te wartości, których się nie spodziewałeś.

Jeśli w Twoim przypadku wyjdzie to przekombinowane, to możesz ugryźć temat jeszcze inaczej. Odmarshalować danę do struktury, zamarshalować ją ponownie i zobaczyć czy są to te same JSONy. Może to też być trochę upierdliwe przy np białych znakacj w pliku JSON. Aby i tego problemu się pozbyć, to możesz użyć json.Compact i operować już na tych danych.

Inny pomysł nie przychodzi mi do głowy :)

0

Dopiero teraz zobaczyłem odpowiedź. A co w przypadku zagnieżdżonych struktrur? Ręczne marshalowanie tego do Mapy, potem sprawdzanie dla każdego z pola czy jest stringiem, marshalowanie tego znowu do mapy itd. Problem jest taki, że w przypadku jeszcze bardziej zagnieżdżonych struktur to będzie bardzo uciążliwe i zdecydowanie "prościej" byłoby, zignorować to i zrobić jakąś dokumentację / trzymać to w yamlu i tworzyć struktury / klasy w miejscu w którym to będzie konsumowane za pomocą Openapi.

Poza tym, nawet dla prostej struktury jest to uciążliwe, bo każde "pole" trzeba wyciągnąć z Mapy i ustawić odpowiednie pole w strukturze. Co w przypadku gdy pole w DTO się zmieni? Trzeba będzie szukać odpowiedniego pola w mapie, zmienić jego nazwę itd. Chyba jednak będę korzystał z defaultowych wartości, z tego względu, że TomRiddle ma rację - zwłaszcza, jeśli takie API nie byłoby do użytku "publicznego".

2

A rozwiązaniem nie będzie użycie JSON schema https://github.com/xeipuuv/gojsonschema ?

0

Wydaje mi się, że to może zadziałać. Dzięki, spróbuję jutro się z tym pobawić. Mniej więcej coś takiego kiedyś w JSie próbowałem napisać :D

0

Jest też coś takiego jak CUE https://github.com/cue-lang/cue, który też wydaje się być ciekawym rozwiązaniem

1 użytkowników online, w tym zalogowanych: 0, gości: 1