Golang How to template a nested struct? - go

I'm trying to template a JSON response onto a front end, my current struct is this:
type Response struct {
WhoisRecord struct {
CreatedDate time.Time `json:"createdDate"`
UpdatedDate time.Time `json:"updatedDate"`
ExpiresDate time.Time `json:"expiresDate"`
Registrant struct {
Name string `json:"name"`
Organization string `json:"organization"`
Street1 string `json:"street1"`
City string `json:"city"`
State string `json:"state"`
Country string `json:"country"`
CountryCode string `json:"countryCode"`
Email string `json:"email"`
Telephone string `json:"telephone"`
Fax string `json:"fax"`
} `json:"registrant"`
AdministrativeContact struct {
Name string `json:"name"`
Organization string `json:"organization"`
Street1 string `json:"street1"`
City string `json:"city"`
State string `json:"state"`
Country string `json:"country"`
CountryCode string `json:"countryCode"`
Email string `json:"email"`
Telephone string `json:"telephone"`
Fax string `json:"fax"`
} `json:"administrativeContact"`
TechnicalContact struct {
Name string `json:"name"`
Organization string `json:"organization"`
Street1 string `json:"street1"`
City string `json:"city"`
State string `json:"state"`
Country string `json:"country"`
CountryCode string `json:"countryCode"`
Email string `json:"email"`
Telephone string `json:"telephone"`
Fax string `json:"fax"`
} `json:"technicalContact"`
DomainName string `json:"domainName"`
NameServers struct {
HostNames []string `json:"hostNames"`
} `json:"nameServers"`
RegistrarName string `json:"registrarName"`
Ips []string `json:"ips"`
} `json:"WhoisRecord"`
}
I then unmarshal this json response, and pass it onto the front end (I'm using GIN)
(Response is redeclared as res)
c.HTML(200,"homework.html", gin.H{
"whois": res,
})
But this is where i run into problems, the code works, but i'm not sure how to template it since it's nested.
For example, i want to show Registrant, Administrative, and Technical contact details (all fields returned) into separate tables. Along with displaying the created, updated, and expired dates. Then Finalizing by showing the The registrar, the ips, and the nameservers (in this case the hostnames field under the NameServers )
How would i go about serving this in my homework.html file? I've tried everything. Usually i would just do something like:
To Display IPs:
{{ range .Ips }}
<div>
<p>IP</p>
<h6>{{ . }}</h6>
</div>
{{end}}
To Display Register Data:
<div>
<p>Name</p>
<h6>{{ .Name }}</h6>
<p>Email</p>
<h6>{{ .Email }}</h6>
//etc
</div>
To display the Registrar:
<div>
<p>Registrar</p>
<h6>{{ .RegistrarName }}</h6>
</div>
But none of this is working (How do i display registrant name in one field, then display technical name in another? i'm obviously messing up the templates big time and my understanding of it is a bit skewed). I've read everything i could, i tried to divide the structs and serve as separate structs, etc. Nothing is working. Can someone point me in the right direction and give examples?
Thanks!

Templates fields are evaluated relative to the current context {{.}}. The following evaluates the template using a map containing "whois" as key, and res as the value:
in.H{ "whois": res})
The value of {{.whois}} is your struct, and you can access the struc field from there. So you can do:
{{.whois.Registrant.Name}}

Related

PATCH http request validation of single field

I have a struct snippet which is something like this
type Talent struct {
Code string `json:"code" gorm:"type:varchar(10);not null"`
FirstName string `json:"firstName" example:"Ravi" gorm:"type:varchar(50)"`
LastName string `json:"lastName" example:"Sharma" gorm:"type:varchar(50)"`
Email string `json:"email" example:"john#doe.com" gorm:"type:varchar(100)"`
Contact string `json:"contact" example:"1234567890" gorm:"type:varchar(15)"`
AcademicYear *uint8 `json:"academicYear" example:"1" gorm:"type:tinyint(2)"`
Type *uint8 `json:"talentType" example:"4" gorm:"type:tinyint(2)"`
Resume *string `json:"resume" gorm:"type:varchar(200)"`
ExperienceInMonths *uint `json:"experienceInMonths"`
Image *string `json:"image" gorm:"type:varchar(200)"`
Gender *string `json:"gender" gorm:"type:varchar(50)"`
DateOfBirth *string `json:"dateOfBirth" gorm:"type:date"`
}
I want to update one field at a time, so I am sending only one field in json to the API as a PATCH http request and in backend(Golang) I am converting the json to struct where in only that field in json will have value in the struct... all other fields will be nil.
For example I am sending firstName, now when I convert it to struct only the firstName field is filled. Now I want to validate that field.. like firstName is a compulsary field so it will have two validations.. one for checking if its empty and one for the max number of characters.
Like wise all fields have some validations. Now how do I validate only that particular field. Having switch cases is what I had considered but is there any other optimal way to do this in golang??

Using a pointer reference to a foreign-key related model in Gorm (golang)

Suppose you have database models as follows:
package storage
type Country struct {
ID string `json:"id" gorm:"type:uuid"`
Name string `json:"name"`
Code string `json:"code"`
}
type City struct {
ID string `json:"id" gorm:"type:uuid"`
Name string `json:"name"`
Code *string `json:"code"`
CountryId string `json:"country_id"`
Country *Country `json:"country" gorm:"references:ID"`
IATA *string `json:"iata"`
Latitude *string `json:"latitude"`
Longitude *string `json:"longitude"`
}
The city should have a pointer to a Country model to make it easier to understand whether Country has been joined (in sql) or not (e.g. if city.Country == nil {panic("for whatever reason")} )
The problem appears when I try to get the list of all cities:
package example
var cities []storage.City
tx.Joins("Country").Find(&cities)
Here, all the cities have been fetched from DB nicely, but the countries became the same in all the cities.
EXPECTED OUTPUT
[
{
ID:51e415ab-4301-4268-9345-deed6b1d72f6
Name:Bergen
Code:0xc0004d6ec0
CountryId:0bd3890c-b6b7-4b27-8071-55c8f64562bb
Country:{
ID:0bd3890c-b6b7-4b27-8071-55c8f64562bb
Name:Norwegen
Code:NO
}
SkyScannerId:0xc0004d6ee0
IATA:0xc0004d6ef0
Latitude:0xc0004d6f00
Longitude:0xc0004d6f10
},
{
ID:2468c7f0-0275-4bff-8b7e-4e87bfa63604
Name:Banská Bystrica
Code:0xc0004d6bc0
CountryId:00ba76d3-9591-4d45-a39d-f554375d790f
Country: {
ID:00ba76d3-9591-4d45-a39d-f554375d790f
Name:Slovakei
Code:SK
}
SkyScannerId:<nil>
IATA:<nil>
Latitude:0xc0004d6c00
Longitude:0xc0004d6c10
},
{
ID:75501988-3c80-4ef9-8081-73d20cbcc29b
Name:Prag
Code:0xc0004d6a60
CountryId:f4e819b2-5c1a-43f9-bfa1-fe56b6ee173e
Country:{
ID:f4e819b2-5c1a-43f9-bfa1-fe56b6ee173e
Name:Tschechien
Code:CZ
}
SkyScannerId:0xc0004d6a90
IATA:0xc0004d6aa0
Latitude:0xc0004d6ac0
Longitude:0xc0004d6ad0
}
]
ACTUAL OUTPUT:
[
{
ID:51e415ab-4301-4268-9345-deed6b1d72f6
Name:Bergen
Code:0xc0004d6ec0
CountryId:0bd3890c-b6b7-4b27-8071-55c8f64562bb
Country:{
ID:f4e819b2-5c1a-43f9-bfa1-fe56b6ee173e
Name:Tschechien
Code:CZ
}
SkyScannerId:0xc0004d6ee0
IATA:0xc0004d6ef0
Latitude:0xc0004d6f00
Longitude:0xc0004d6f10
},
{
ID:2468c7f0-0275-4bff-8b7e-4e87bfa63604
Name:Banská Bystrica
Code:0xc0004d6bc0
CountryId:00ba76d3-9591-4d45-a39d-f554375d790f
Country:{
ID:f4e819b2-5c1a-43f9-bfa1-fe56b6ee173e
Name:Tschechien
Code:CZ
}
SkyScannerId:<nil>
IATA:<nil>
Latitude:0xc0004d6c00
Longitude:0xc0004d6c10
},
{
ID:75501988-3c80-4ef9-8081-73d20cbcc29b
Name:Prag
Code:0xc0004d6a60
CountryId:f4e819b2-5c1a-43f9-bfa1-fe56b6ee173e
Country:{
ID:f4e819b2-5c1a-43f9-bfa1-fe56b6ee173e
Name:Tschechien
Code:CZ
}
SkyScannerId:0xc0004d6a90
IATA:0xc0004d6aa0
Latitude:0xc0004d6ac0
Longitude:0xc0004d6ad0
}
]
Please pay attention to Country field of the outputs. In the ACTUAL OUTPUT all the cities have the same country. I think this has something to do with the pointer.
I got EXPECTED OUTPUT when I removed the pointer from Country (so *Country became Country without *). But I would like to get the same output with the pointer (*Country).
Also, please do not pay attention to the values printed out in other fields. My main focus is the Country field.
Any ideas how to fix it ?
P.S. I know that i can survive without using the pointers too in the Country field, but I just want to know if there are any possibilities to do that.
Try to put countryId as a pointer too.
Like this
CountryId *string `json:"country_id"`
Actually I tried to replicate the error with you code example, but it's working well.
I have noticed that this is the behavior with gorm-v1.23.6. Switching back to gorm-v1.23.5 solved the problem.

Associations not working with test entries

I have two models User and Address in GORM defined:
File user.go
type User struct {
gorm.Model
Identity string `json:"identity"`
Password string `json:"password"`
Address Address
AddressID int
}
type Address struct {
gorm.Model
Street string `json:"street"`
StreetNumber string `json:"streetnumber"`
}
In the main.go file I initiate the DB, automigrate and want to add a test user to the DB:
database.InitDatabase()
database.DBConn.AutoMigrate(&user.User{})
database.DBConn.AutoMigrate(&user.Address{})
userRec := &user.User{ Identity: "John Wayne", Password: "mysecretpassword", Address: user.Address{Street: "Teststreet", StreetNumber: "1"}}
database.DBConn.Create(userRec)
The user gets created and the address as well, however, the address is not associated with the user, just
empty Address fields come up. What did I forget?
Is this the normal way to setup a test entry if you have associations in your entities (with nested models)?
Try using the "address_id" field as a foreignKey.
for example
type User struct {
gorm.Model
Identity string `json:"identity"`
Password string `json:"password"`
Address Address `gorm:"foreignKey:address_id;association_autoupdate:false"`
AddressID uint `json:"address_id"`
}
Online documentation
Maybe it will help.

Microsoft calendar event response to Go struct

been trying to unmarshal a response from Microsoft's Graph API into a Go struct but I keep getting an error "json: cannot unmarshal object into Go struct field .value.start of type []struct { DateTime string "json:"dateTime""; TimeZone string "json:"timeZone"" }".
Below is my struct:
type MicrosoftCalendarEventsResponse struct {
Value []struct {
Etag string `json:"#odata.etag"`
Id string `json:"id"`
Subject string `json:"subject"`
Start []struct {
DateTime string `json:"dateTime"`
TimeZone string `json:"timeZone"`
} `json:"start"`
End []struct {
DateTime string `json:"dateTime"`
TimeZone string `json:"timeZone"`
} `json:"end"`
OriginalStartTimeZone string `json:"originalStartTimeZone"`
OriginalEndTimeZone string `json:"originalEndTimeZone"`
ICalUId string `json:"iCalUId"`
ReminderMinutesBeforeStart int `json:"reminderMinutesBeforeStart"`
IsReminderOn bool `json:"isReminderOn"`
} `json:"value"`
}
The response I received is this:
{"#odata.etag":"W/\"8COqS12xxxhwcMA==\"","id":"xxxxx","createdDateTime":"2019-12-05T17:09:41.018502Z","lastModifiedDateTime":"2019-12-05T17:09:41.8919929Z","changeKey":"xxxx","categories":[],"originalStartTimeZone":"W. Europe Standard Time","originalEndTimeZone":"W. Europe Standard Time","iCalUId":"xxx","reminderMinutesBeforeStart":15,"isReminderOn":true,"hasAttachments":false,"subject":"Something","bodyPreview":"","importance":"normal","sensitivity":"normal","isAllDay":false,"isCancelled":false,"isOrganizer":true,"responseRequested":true,"seriesMasterId":null,"showAs":"busy","type":"singleInstance","webLink":"xxx","onlineMeetingUrl":null,"isOnlineMeeting":false,"onlineMeetingProvider":"unknown","allowNewTimeProposals":true,"recurrence":null,"onlineMeeting":null,"responseStatus":{"response":"organizer","time":"0001-01-01T00:00:00Z"},"body":{"contentType":"html","content":""},"start":{"dateTime":"2019-12-17T17:00:00.0000000","timeZone":"UTC"},"end":{"dateTime":"2019-12-17T17:30:00.0000000","timeZone":"UTC"},"location":{"displayName":"","locationType":"default","uniqueIdType":"unknown","address":{},"coordinates":{}},"locations":[],"attendees":[],"organizer":{"emailAddress":{"name":"John Doe","address":"someone#somewhere.com"}}}
In which you can clearly see the part that is giving the error:
"start":{"dateTime":"2019-12-17T17:00:00.0000000","timeZone":"UTC"}
can anyone please tell me what I am doing wrong? been trying for hours without any progress and I really have no clue whats wrong.
The other stuff like Etag, Id, Subject and so on are working properly. Its only the nested []structs that do not work.
To capture calender events (plural) it makes sense that the top-level Values is a slice of structs.
However, within a particular Value, your Start and End fields are defined also as slices of structs which is probably not what you want.
Try just a plain struct:
Start struct {
DateTime string `json:"dateTime"`
TimeZone string `json:"timeZone"`
} `json:"start"`
End struct {
DateTime string `json:"dateTime"`
TimeZone string `json:"timeZone"`
} `json:"end"`

How to set unique at struct Beego

How to set unique at the struct specific columns. first name
type User struct {
ID int64 `orm:"size(100)", pk`
Lastname string `orm:"size(100)"`
Firstname string `orm:"size(100)"`
Role string `orm:"size(100)"`
Created time.Time `orm:"size(100)"`
Updated time.Time `orm:"size(100)"`
}
I'm using "github.com/astaxie/beego/orm"
According to the documentation, you just add the word "unique" to the tag:
Add unique key for one field
Name string `orm:"unique"`
To combine tags, you must use a semicolon as documented here. For example:
Firstname string orm:"unique;size(100)"

Resources