I would like to omit some fields in my JSON Response.
Currently I have a type receiver that returns a new struct userToJson.
I then pass this to the json.NewEncoder(). However I am wondering if this is the best way to omit fields using GORM.
Thank you beforehand!
package server
import (
"gorm.io/gorm"
)
type User struct {
gorm.Model
FirstName string `gorm:"not null;default:null"`
LastName string `gorm:"not null;default:null"`
Email string `gorm:"not null;default:null;unique"`
Password string `gorm:"not null;default:null"`
Posts []Posts
}
type userToJson struct {
Email string
Posts []Posts
}
func (u *User) toJson() userToJson {
return userToJson{
Email: u.Email,
Posts: u.Posts,
}
}
Another approach is to implement the interface Marshaler for your type to modify how marshaling to JSON works. The json package checks for that interface before marshaling, and if it exists, calls that function. Here is the interface from the standard library.
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
One sample implementation for your User type would be as follows.
func (u *User) MarshalJSON() ([]byte, error) {
type Temp struct {
Email string
Posts []Post
}
t := Temp{
Email: u.Email,
Posts: u.Posts,
}
return json.Marshal(&t)
}
you should declare you struct with a json tag for all fields, what Behrooz suggested in the comment should work fine
type User struct {
gorm.Model
FirstName string `json:"-" gorm:"not null;default:null"`
LastName string `json:"-" gorm:"not null;default:null"`
Email string `json:"email" gorm:"not null;default:null;unique"`
Password string `json:"-" gorm:"not null;default:null"`
Posts []Posts`json:"posts"`
}
Related
I am new to whole back-end and golang things and I want to write an edit function for an restAPI. Here is my main function code in golang.
type Profile struct {
UserName string `json:"username"`
Mail string `json:"mail"`
Password string `json:"password"`
UserProfile []Models.UserProfile
}
func EditProfile(c *gin.Context) {
var user Models.User
var modeluser Models.User
var userprofile []Models.UserProfile
Config.DB.First(&user, c.Param("id"))
c.BindJSON(&modeluser)
user.UserName = modeluser.UserName
user.Mail = modeluser.Mail
user.Password = modeluser.Password
Config.DB.Model(&user).Association("UserProfile").Find(&userprofile)
c.BindJSON(&user)
Config.DB.Save(&user)
c.JSON(200, &user)
}
I am trying to update user profile model by taking benefit of its association with user model. Here are my model structures for both.
type User struct {
ID uint `gorm:"primaryKey"`
UserName string
Mail string
Password string
RegisterDate time.Time
LastLogin time.Time
IsDeleted bool
Skills []Skill `gorm:"foreignKey:UserID"`
Languages []Language `gorm:"foreignKey:UserID"`
Applications []Application `gorm:"foreignKey:UserID"`
Mentors []Mentor `gorm:"foreignKey:UserID"`
Mentees []Mentee `gorm:"foreignKey:UserID"`
Companies []Company `gorm:"foreignKey:UserID"`
UserProfile []UserProfile `gorm:"foreignKey:UserID"`
Abouts []About `gorm:"foreignKey:UserID"`
Universities []University `gorm:"foreignKey:UserID"`
}
type UserProfile struct {
ID uint `gorm:"primaryKey"`
Name string
Surname string
Biography string `gorm:"size:500"`
BirthDate string
PhoneNumber string
ProfileImage string `gorm:"size:1000"`
City string
Address string `gorm:"size:500"`
IsDeleted bool
UserID uint `gorm:"foreignKey:ID"`
}
But when I run following json on postman it only updates user not the user profile. Since it takes userprofile as null.
The URL:
POST: http://localhost:8091/EditProfile/ID
The JSON:
{
"username":"elip1",
"mail":"elmb01up#mail.com",
"password":"elhurkusmodel1",
"userprofile":
[
{
"name":"somestring" ,
"surname": "somestring",
"biography": "somestring",
"birthdate" : "sometimeTime",
"phonenumber": "somestring",
"profileimage" :"somestring",
"city":"somestring" ,
"address": "somestring"
}
]
}
I could not figure it out that whether my code or json structure is wrong. I would be glad to take an answer from you. Thanks.
Lets consider the following code
type A struct {
Column1 string `json:"column1"`
Entity CustomInterface `json:"entity"`
}
type CustomInterface interface {
GetType() string
}
type Entity1 struct {
ColumnX string `json:"columnx"`
ColumnY string `json:"columny"`
}
type Entity2 struct {
ColumnP string `json:"columnp"`
ColumnQ string `json:"columnq"`
}
func (*e Entity1) GetType() string {
return "ENTITY1"
}
func (*e Entity2) GetType() string {
return "ENTITY2"
}
Now if I am trying to bind an instance of A type as follows
var bodyJSON A
ShouldBindWith(&bodyJson, binding.JSON)
I am getting the following error
json: cannot unmarshal object into Go struct field A.entity of type package.CustomInterface
Am I doing anything very silly here?
PS: I just started exploring go. Apologies if this question is very noob level.
The json.Unmarshal function by itself does not let you unmarshal into interface types except for the empty interfaces (interface{}) that don't have any methods:
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
However, in some simple cases the following scheme can work.
type CustomerEntity struct {
CustomerName string `json:"customer_name"`
Address string `json:"customer_address"`
}
type EmployeeEntity struct {
EmployeeName string `json:"employee_name"`
ID int `json:"employee_id"`
}
If we know that an entity is either an employee or a customer, then we can define an Entity that embeds each:
type Entity struct {
CustomerEntity
EmployeeEntity
}
We can give it methods to check whether it's a customer or an employee:
func (s Entity) IsCustomer() bool {
return s.CustomerEntity != CustomerEntity{}
}
func (s Entity) IsEmployee() bool {
return s.EmployeeEntity != EmployeeEntity{}
}
Really, these are just checking that at least one field is set.
Then we unmarshal the following JSON:
{
"entity": {
"employee_name": "Bob",
"employee_id": 77
}
}
Here's a complete example:
import (
"encoding/json"
"fmt"
)
type Example struct {
Entity Entity `json:"entity"`
}
type Entity struct {
CustomerEntity
EmployeeEntity
}
func (s Entity) IsCustomer() bool {
return s.CustomerEntity != CustomerEntity{}
}
func (s Entity) IsEmployee() bool {
return s.EmployeeEntity != EmployeeEntity{}
}
type CustomerEntity struct {
CustomerName string `json:"customer_name"`
CustomerAddress string `json:"customer_address"`
}
type EmployeeEntity struct {
EmployeeName string `json:"employee_name"`
EmployeeID int `json:"employee_id"`
}
func main() {
var example Example
if err := json.Unmarshal([]byte(`{"entity":{"employee_name":"Bob", "employee_id":77}}`), &example); err != nil {
panic("won't fail")
}
fmt.Printf("%#v\n", example)
if example.Entity.IsCustomer() {
fmt.Printf("customer %s lives at %d\n", example.Entity.CustomerName, example.Entity.CustomerAddress)
}
if example.Entity.IsEmployee() {
fmt.Printf("employee %s has id %d\n", example.Entity.EmployeeName, example.Entity.EmployeeID)
}
}
which outputs
main.Example{Entity:main.Entity{CustomerEntity:main.CustomerEntity{CustomerName:"", CustomerAddress:""}, EmployeeEntity:main.EmployeeEntity{EmployeeName:"Bob", EmployeeID:77}}}
employee Bob has id 77
as we might expect.
There are a few caveats. First, this won't work if there's overlap in either the JSON or the Go field names for the entity types. Second, nothing stops you from (accidentally) initializing some fields in both the customer and employee types and causing it to return true for both IsCustomer and IsEmployee.
If your JSON data has a "type" field, then you could use it to decide what is held instead:
type Entity struct {
Type string `json:"type"`
CustomerEntity
EmployeeEntity
}
although this has the same drawbacks as the other solution mentioned above.
type TestObject struct {
kind string `json:"kind"`
id string `json:"id, omitempty"`
name string `json:"name"`
email string `json:"email"`
}
func TestCreateSingleItemResponse(t *testing.T) {
testObject := new(TestObject)
testObject.kind = "TestObject"
testObject.id = "f73h5jf8"
testObject.name = "Yuri Gagarin"
testObject.email = "Yuri.Gagarin#Vostok.com"
fmt.Println(testObject)
b, err := json.Marshal(testObject)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(b[:]))
}
Here is the output:
[ `go test -test.run="^TestCreateSingleItemResponse$"` | done: 2.195666095s ]
{TestObject f73h5jf8 Yuri Gagarin Yuri.Gagarin#Vostok.com}
{}
PASS
Why is the JSON essentially empty?
You need to export the fields in TestObject by capitalizing the first letter in the field name. Change kind to Kind and so on.
type TestObject struct {
Kind string `json:"kind"`
Id string `json:"id,omitempty"`
Name string `json:"name"`
Email string `json:"email"`
}
The encoding/json package and similar packages ignore unexported fields.
The `json:"..."` strings that follow the field declarations are struct tags. The tags in this struct set the names of the struct's fields when marshaling to and from JSON.
Ru it on the playground.
When the first letter is capitalised, the identifier is public to any
piece of code that you want to use.
When the first letter is lowercase, the identifier is private and
could only be accessed within the package it was declared.
Examples
var aName // private
var BigBro // public (exported)
var 123abc // illegal
func (p *Person) SetEmail(email string) { // public because SetEmail() function starts with upper case
p.email = email
}
func (p Person) email() string { // private because email() function starts with lower case
return p.email
}
In golang
in struct first letter must uppercase
ex. phonenumber -> PhoneNumber
======= Add detail
First, I'm try coding like this
type Questions struct {
id string
questionDesc string
questionID string
ans string
choices struct {
choice1 string
choice2 string
choice3 string
choice4 string
}
}
golang compile is not error and not show warning. But response is empty because something
After that, I search google found this article
Struct Types and Struct Type Literals
Article then... I try edit code.
//Questions map field name like database
type Questions struct {
ID string
QuestionDesc string
QuestionID string
Ans string
Choices struct {
Choice1 string
Choice2 string
Choice3 string
Choice4 string
}
}
Is work.
Hope for help.
I am writing an app using the Instagram API.
I am receiving a JSON request and that gets Unmarshal'ed into nested structs.
// the nested structs
type ResponseData struct {
ID string `json:"id"`
Link string `json:"link"`
Type string `json:"type"`
User struct {
FullName string `json:"full_name"`
ID int `json:"id"`
ProfilePicture string `json:"profile_picture"`
Username string `json:"username"`
}
Images struct {
Standard_Resolution struct {
URL string `json:"url"`
}
}
}
For the Image url to be added it needs to have the underscore in Standard_Resolution , I am using Go Plus Package for Atom and I get the lint warning:
don't use underscores in Go names; struct field Standard_Resolution
should be StandardResolution
Is there another way for me fix the error and still have the value in my struct.
Update:
I can add an identifier after the last brace for StandardResolution.
StandardResolution struct {
URL string `json:"url"`
} `json:"standard_resolution"`
Anyway it is easier to read if you don't use nested structs.
type RDUser struct { ... }
type RDStandardResolution struct { ... }
type RDImages struct {
StandardResolition RDStandardResolution `json:"standard_resolution"`
}
type ResponseData struct {
...
User RDUser `json:"user"`
Images RDImages `json:"images"`
}
I have to parse some nested JSON, which translates into a Go type, like this:
type Config struct {
Mail struct {
From string
To string
Password string
}
Summary struct {
Send bool
Interval int
}
}
Now I want to call a function for each key (Mail, Summary), I tried it like this:
utils.StartNewMailer(config.Mail)
The problem is, how do I construct the called function, I tried to mirror the Mail struct (and called it mailConfig), since I can't pass an arbitrary struct as an argument.
func StartNewMailer(conf mailConfig){ //..., but that doesn't work either, I get the following compiler error message:
cannot use config.Mail (type struct { From string; To string; Password string }) as type utils.mailConfig in argument to utils.StartNewMailer
Do I have to pass in every single value to the called function or is there a nicer way to do this?
utils.mailConfig fields should be exported, as in the literal struct field in Config type.
type mailConfig struct {
From string
To string
Password string
}
I suggest declaring inner structs as types themselves instead of using struct literals.
type Mail struct {
From string
To string
Password string
}
type Summary struct {
Send bool
Interval int
}
type Config struct {
Mail
Summary
}
func StartNewMailer(Mail mailConfig)