Validation for Nested JSON object - json

{
"firstname": "sathish",
"lastname": "kumar",
"city": {
"id": 12,
"name": "coimbatore"
},
"referrals": [
{
"name": "vignesh",
"mobile": "1234567890"
},
{
"name": "melvin",
"mobile": "1234567890"
}
]
}
Above is my JSON request for creating new profile. I need to do validation for above JSON using Beego validation package
type ProfileForm struct {
Firstname string `json:"firstname" valid:"Required"`
Lastname string `json:"lastname" valid:"Required"`
City struct {
ID int `json:"id" valid:"Required"`
Name string `json:"name" valid:"Required"`
} `json:"city"`
Referrals []struct {
Name string `json:"name" valid:"Required"`
Mobile string `json:"mobile" valid:"Required"`
} `json:"referrals"`
}
I need to know the how can write the validation for JSON request using struct in Beego. Let me know are the any package or tutorial for this kind of requirement.
In official beego documentation I didn't see anything matches my requirement.

Related

Go unmarshal JSON with unknown field name but known struct

I retrieve a acme.json from traefik tls where traefik stores ssl/tls certificate information.
Now I want to unmarshal with golang the acme.json into my go struct "Traefik". But I don't know how to handle dynamic/unknown json field names because certificateresolver1 and certificateresolver2 are names I don't know at compile time. These names should be dynamic configured in go.
I know the structure of the json (it is always the same) but not know the field name of the certificateresolver.
Does anyone know the best way to do this?
Traefik acme.json
{
"certificateresolver1": {
"Account": {
"Email": "email#example.com",
"Registration": {
"body": {
"status": "valid",
"contact": [
"mailto:email#example.com"
]
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/124448363"
},
"PrivateKey": "PRIVATEKEY",
"KeyType": "4096"
},
"Certificates": [
{
"domain": {
"main": "example.com",
"sans": [
"test.example.com"
]
},
"certificate": "CERTIFICATE",
"key": "KEY",
"Store": "default"
},
{
"domain": {
"main": "example.org"
},
"certificate": "CERTIFICATE",
"key": "KEY",
"Store": "default"
}
]
},
"certificateresolver2": {
"Account": {
"Email": "email#example.com",
"Registration": {
"body": {
"status": "valid",
"contact": [
"mailto:email#example.com"
]
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/126945414"
},
"PrivateKey": "PRIVATEKEY",
"KeyType": "4096"
},
"Certificates": [
{
"domain": {
"main": "example.net"
},
"certificate": "CERTIFICATE",
"key": "KEY",
"Store": "default"
}
]
}
}
Go struct for acme.json
type Traefik struct {
Provider []struct {
Account struct {
Email string `json:"Email"`
Registration struct {
Body struct {
Status string `json:"status"`
Contact []string `json:"contact"`
} `json:"body"`
URI string `json:"uri"`
} `json:"Registration"`
PrivateKey string `json:"PrivateKey"`
KeyType string `json:"KeyType"`
} `json:"Account"`
Certificates []struct {
Domain struct {
Main string `json:"main"`
Sans []string `json:"sans"`
} `json:"domain"`
Certificate string `json:"certificate"`
Key string `json:"key"`
Store string `json:"Store"`
} `json:"Certificates"`
} `json:"certificateresolver"` <-- What to write there? It should fit for certificateresolver1 and certificateresolver2
}
I think something like this will help you:
type ProviderMdl map[string]Provider
type Provider struct {
Account struct {
Email string `json:"Email"`
Registration struct {
Body struct {
Status string `json:"status"`
Contact []string `json:"contact"`
} `json:"body"`
URI string `json:"uri"`
} `json:"Registration"`
PrivateKey string `json:"PrivateKey"`
KeyType string `json:"KeyType"`
} `json:"Account"`
Certificates []struct {
Domain struct {
Main string `json:"main"`
Sans []string `json:"sans"`
} `json:"domain"`
Certificate string `json:"certificate"`
Key string `json:"key"`
Store string `json:"Store"`
} `json:"Certificates"`
}
So you could work with this data in this way:
bres := new(ProviderMdl)
if err := json.Unmarshal(data, bres); err != nil {
panic(err)
}
// fmt.Printf("%+v - \n", bres)
for key, value := range *bres {
fmt.Printf("%v - %v\n", key, value)
}
Full example here

Unwinding nested data responses into structs when a slice is part of the response

I'd like to get some input into how you would all go about unwinding nested response data into custom structs. Below is an example of the data i'm being returned. I'm trying to get to the user data.
{
"_links": {
"self": {
"href": "/api/v2/user-search/default/test?after=1585612800000&limit=20&offset=0&q=johnsmith%40test.com",
"type": "application/json"
}
},
"totalCount": 1,
"items": [
{
"lastPing": "2020-04-30T02:56:10.430867577Z",
"environmentId": "xxxx",
"ownerId": "xxxx",
"user": {
"key": "johnsmith#test.com",
"email": "johnsmith#test.com",
"firstName": "john",
"lastName": "smith"
},
"_links": {
"parent": {
"href": "/api/v2/users/default/test",
"type": "application/json"
},
"self": {
"href": "/api/v2/users/default/test/johnsmith#test.com",
"type": "application/json"
},
"settings": {
"href": "/api/v2/users/default/test/johnsmith#test.com/flags",
"type": "text/html"
},
"site": {
"href": "/default/test/users/johnsmith#test.com",
"type": "text/html"
}
}
}
]
}
Currently I'm doing the below
respData := map[string][]map[string]map[string]interface{}{}
json.Unmarshal(respBody, &respData)
userData := respData["items"][0]["user"]
I'd love to be able to unmarshal it into a custom struct but I can't seem to get it to work. The nested slice that the user object sits within is what keeps throwing me off.
type User struct {
Key string `json:"key"`
Email string `json:"email"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
type LinkInfo struct {
Href string `json:"href"`
Type string `json:"type"`
}
type Item struct {
LastPing time.Time `json:"lastPing"`
EnvironmentID string `json:"environmentId"`
OwnerID string `json:"ownerId"`
User User `json:"user"`
Links LinkInfo `json:"_links"`
Self LinkInfo `json:"self"`
Settings LinkInfo `json:"settings"`
Parent LinkInfo `json:"parent"`
Site LinkInfo `json:"site"`
}
type ItemDetails struct {
Links LinkInfo `json:"_links"`
TotalCount int `json:"total_count"`
Items []Item
}
Can you try this?
https://play.golang.org/p/S_CUN0XEh-d
From what you mentioned it sounds like you were on the right track. Your JSON is pretty large, so let me give you a smaller example similar to the part you mentioned you're having trouble with (the user object inside the items list).
type response struct {
TotalCount int `json:"totalCount"`
Items []*itemStruct `json:"items"`
}
type itemStruct struct {
LastPing string `json:"lastPing"`
User *userStruct `json:"user"`
}
type userStruct struct {
Key string `json:"key"`
}
Basically to map to a JSON list of objects, just put a field like this in your struct: Objects []*structWhichMapsToMyObject
Edit: Here's the code running in Go Playground: https://play.golang.org/p/EvSvv-2s8y8
If you want this:
"user": {
"key": "johnsmith#test.com",
"email": "johnsmith#test.com",
"firstName": "john",
"lastName": "smith"
}
Declare a matching Go struct:
type User struct {
Key string `json:"key"`
Email string `json:"email"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
Then, since the user's parent object looks like this:
"items": [
{
"lastPing": "2020-04-30T02:56:10.430867577Z",
"environmentId": "xxxx",
"ownerId": "xxxx",
"user": { ... },
"_links": { ... }
}
]
you also need to declare a matching Go struct for that (you can omit fields you don't need):
type Item struct {
User User `json:"user"`
}
and then the parent of the parent:
{
"_links": {
"self": {
"href": "/api/v2/user-search/default/test?after=1585612800000&limit=20&offset=0&q=johnsmith%40test.com",
"type": "application/json"
}
},
"totalCount": 1,
"items": [ ... ]
}
and the matching Go struct for the grandparent, again, include only the fields you need:
type ResponseData struct {
Items []Item `json:"items"`
}
Once you have this you can decode the json into an instance of ResponseData:
var rd ResponseData
if err := json.Unmarshal(data, &rd); err != nil {
panic(err)
}
for _, item := range rd.Items {
fmt.Println(item.User)
}
https://play.golang.com/p/7yavVSBcHQP

Fill struct dynamically from parameters

I've the following struct which works as expected Im getting
data and I was able
type Service struct {
Resources []struct {
Model struct {
Name string `json:"name"`
Credentials struct {
path string `json:"path"`
Vts struct {
user string `json:"user"`
id string `json:"id"`
address string `json:"address"`
} `json:"vts"`
} `json:"credentials"`
} `json:"model"`
} `json:"resources"`
}
service:= Service{}
err := json.Unmarshal([]byte(data), &service
The data is like following,
service1
{
"resources": [
"model": {
"name": "cred",
"credentials": {
"path": "path in fs",
"vts": {
"user": "stephane",
"id": "123",
"address": "some address"
}
},
}
},
Now some services providing additional data under vts for example now we have 3 fields (user/id/address) but some services (service1) can provides additional data like email, secondName ,etc . but the big problem here is that
I need to get it from parameters since (service 2) education, salary etc
Service2
{
"resources": [
"model": {
"name": "cred",
"credentials": {
"path": "path in fs",
"vts": {
"user": "stephane",
"id": "123",
"address": "some address",
"email" : "some email",
"secondName" : "secondName"
}
},
}
},
service N
{
"resources": [
"model": {
"name": "cred",
"credentials": {
"path": "path in fs",
"vts": {
"user": "stephane",
"id": "123",
"address": "some address",
"salary" : "1000000"
}
},
}
},
Of course If I know in advance the fields I can put them all in the struct and use omitempty but I dont know, I just get it as parameter to the function (the new properties names) , some service can provide 10 more fields in this struct (which I should get the properties name of them as args[]to the functions) but I don't know them in advance, this should be dynamic somehow ....is there a nice way to handle it in Golang ?
If you don't know the fields in advance, then don't use a struct but something that is also "dynamic": a map.
type Service struct {
Resources []struct {
Model struct {
Name string `json:"name"`
Credentials struct {
Path string `json:"path"`
Vts map[string]interface{} `json:"vts"`
} `json:"credentials"`
} `json:"model"`
} `json:"resources"`
}
map[sting]interface{} can hold values of any type. If you know all fields will hold a string value, you may also use a map[string]string so it will be easier to work with it.
Example with input JSON:
{
"resources": [
{
"model": {
"name": "cred",
"credentials": {
"path": "path in fs",
"vts": {
"user": "stephane",
"id": "123",
"address": "some address",
"dyn1": "d1value",
"dyn2": "d2value"
}
}
}
}
]
}
Testing it:
service := Service{}
err := json.Unmarshal([]byte(data), &service)
fmt.Printf("%q %v", service, err)
Output (try it on the Go Playground):
{[{{"cred" {"path in fs" map["dyn2":"d2value" "user":"stephane" "id":"123"
"address":"some address" "dyn1":"d1value"]}}}]} <nil>
Now if you want to collect values from the Vts map for a set of keys, this is how you can do it:
args := []string{"dyn1", "dyn2"}
values := make([]interface{}, len(args))
for i, arg := range args {
values[i] = service.Resources[0].Model.Credentials.Vts[arg]
}
fmt.Println(values)
Output of the above will be (try it on the Go Playground):
[d1value d2value]

json object with nested structures in golang

I have the following json object that I am trying to represent with Go as a type JsonObject struct
and pass it back in its original json so that I can return the json as an api endpoint. Any advice/example?
[{
"time": 173000,
"id": "VLSuEE5m1kmIhgE7ZhHDFe",
"height": "",
"DATASTRUCTURE": {
},
"language": "en",
"size": 0,
"url": "http://www.gstatic.com/play.m3u8",
"type": "vid",
"definitionid": "h264",
"reference": "PAN-EN",
"content": "This is some content",
"revisiondate": "2017-11-29T00:00:00",
"data": {
},
"id": "BBBB3424-153E-49DE-4786-013B6611BBBB",
"thumbs": {
"32": "https://www.gstatic.com/images?q=tbn:ANd9GcRj",
"64": "https://www.gstatic.com/images?q=tbn:DPd3GcRj"
},
"title": "Cafeteria",
"hash": "BBBB5d39bea20edf76c94133be61BBBB"
}]
You can use https://mholt.github.io/json-to-go/ to generate struct for the given json schema.
For example, json given in the question can be represented like:
type AutoGenerated []struct {
Time int `json:"time"`
ID string `json:"id"`
Height string `json:"height"`
DATASTRUCTURE struct {
} `json:"DATASTRUCTURE"`
Language string `json:"language"`
Size int `json:"size"`
URL string `json:"url"`
Type string `json:"type"`
Definitionid string `json:"definitionid"`
Reference string `json:"reference"`
Content string `json:"content"`
Revisiondate string `json:"revisiondate"`
Data struct {
} `json:"data"`
Thumbs struct {
Num32 string `json:"32"`
Num64 string `json:"64"`
} `json:"thumbs"`
Title string `json:"title"`
Hash string `json:"hash"`}
Hope this helps!

Unable to decode the JSON response

I have the following response from a graph api
{
"data": [
{
"name": "Mohamed Galib",
"id": "502008940"
},
{
"name": "Mebin Joseph",
"id": "503453614"
},
{
"name": "Rohith Raveendranath",
"id": "507482441"
}
],
"paging": {
"next": "https://some_url"
}
}
I have a struct as follows
type Item struct {
Name, Id string
}
I wanted to parse the response and get an array of Item, How do I do that?
You need to update your struct like so:
type Item struct {
Name string `json:"name"`
Id string `json:"id"`
}
and add a struct to represent the wrapper:
type Data struct {
Data []Item `json:"data"`
}
You can then use json.Unmarshal to populate a Data instance.
See the example in the docs.