I currently have a form post that is coming in like
{
"stuff":"cool text",
"otherthing":"neat thing",
"captions":[
{"first":"the list",
"second":"how are you"},
{"first":"wow",
etc....
]
}
Now I don't know how many captions there will be. It might be one in the array, it might be twenty.
I have set up two structures as well
type ThingContext struct {
Stuff string `json:"stuff"`
OtherThing string `json:"otherthing"`
Captions []ArrayText `json:"captions"`
}
type ArrayText struct {
First string `json:"first"`
Second string `json:"second"`
}
And in my golang function I have something like this
func (c *ThingContext) SetThingContext(rw web.ResponseWriter, req *web.Request, next web.NextMiddlewareFunc) {
if err := req.ParseForm(); err != nil {
}
c.Stuff = req.FormValue("stuff")
c.OtherThing = req.FormValue("otherthing")
}
This works fine till I try and parse the array.
When I do something along the lines of c.Captions = req.ParseForm("captions")
I get the error
.cannot use req.Request.ParseForm("captions") (type error) as type []ArrayText in assignment
You're doing it right, except for the assignment. When you run req.Request.ParseForm(), rather than returning a value, or passing in a reference to a buffer, it populates the req.Request.Form and req.Request.PostForm structures.
The related GoDoc explaining said function
So rather than
c.Captions = req.Request.ParseForm()
It would look more like
err := req.Request.ParseForm()
//check for errors as usual here
c.Captions = req.Request.Form
//or
c.Captions = req.Request.PostForm
Approaching it from this direction should put you on the right track.
Cheers!
Taylor
Related
I'm building a graphql interface using golang. I'm using gqlgen package to implement it.
Here I need to pass all field names in a query to get it in response, But the problem is my data is huge, it is having more than 30 fields it would be difficult to pass all fields in a query.
This is my query
{Model{id, name, email, mobile,...............}}
Like this I need to pass all fields name.
Instead Im looking for a result which will return all fields without passing any fields. I mean if not passing any field names it should return all.
For example
{Model{}}
First, you really should list out all the fields in your query. That is the nature of graphql. It is verbose, but most client libraries get the fields from your data structure anyway, so it's not that bad.
So I recommend listing out all fields manually!
Using Scalars (must be on v0.11.3 or below, see https://github.com/99designs/gqlgen/issues/1293)
But if you insist, if there is a will, there is way. You can use GraphQL's scalar types and make your own. See this doc for how to make them with gqlgen: https://gqlgen.com/reference/scalars/
In your schema, you can make a JSON scalar:
scalar JSON
type Query {
random: JSON!
}
Make a model for this
// in your own models.go
// You can really play with this to make it better, easier to use
type JSONScalar json.RawMessage
// UnmarshalGQL implements the graphql.Unmarshaler interface
func (y *JSONScalar) UnmarshalGQL(v interface{}) error {
data, ok := v.(string)
if !ok {
return fmt.Errorf("Scalar must be a string")
}
*y = []byte(data)
return nil
}
// MarshalGQL implements the graphql.Marshaler interface
func (y JSONScalar) MarshalGQL(w io.Writer) {
_, _ = w.Write(y)
}
Then link the scalar to your custom type in the gql.yml
models:
JSON:
model: github.com/your-project/path/graph/model.JSONScalar
When you run the generate (use gqlgen v0.11.3 or below, gqlgen version), your resolvers will now use the custom type you made. And it's easy to use:
func (r *queryResolver) random(ctx context.Context) (model.JSONScalar, error) {
// something is the data structure you want to return as json
something := struct {
Value string
}{
Value: "Hello World",
}
d, _ := json.Marshal(something)
return model1.JSONScalar(d), nil
}
The resulting query of
// Query
{
random
}
// Response
{
"random" : {
"Value": "Hello World!"
}
}
I have a struct defined in fruits.go
package domain
type AppleImages struct {
Front string `json:"frontImage"`
Back string `json:"backImage"`
Top string `json:"topImage"`
}
And I defined the same in process.go (which returns this data to the handler). This definition is only for demonstration purposes since I'm getting values from the database using gorm so we cannot append the required URL here.
package process
func getApple() (apple domain.Apple){
apple = domain.Apple{
Front: "front-image.png"
Back: "back-image.png"
Top: "top-image.png"
}
return
}
For my output is want to return
{
frontImage: "https://www.example.com/front-image.png",
backImage: "https://www.example.com/back-image.png",
topImage: "https://www.example.com/top-image.png",
}
I don't want to manually add https://www.example.com/ to each of the images in the struct.
Is there a way of parsing through the struct and automatically appending this string to all existing values?
Use gorm AfterFind hook. Every time after load data from database gorm call AfterFind and your data will be updated for Apple model. Then you don't need to manually do it after every time fetching from the database.
func (u *Apple) AfterFind() (err error) {
u.Front= "https://www.example.com/"+ u.Front
u.Back= "https://www.example.com/"+ u.Back
u.Top= "https://www.example.com/"+ u.Top
return
}
See details here
Is there a way of parsing through the struct and automatically appending this string to all existing values?
No.
I don't want to manually add https://www.example.com/ to each of the images in the struct.
Go provides no magic for thing to happen without you programming it. You must do this "manually".
You could use reflect to add a prefix for each filed in the struct.
See details here.
func getApple() (apple domain.Apple) {
apple = domain.Apple{
Front: "front-image.png",
Back: "back-image.png",
Top: "top-image.png",
}
addURL(&apple, "https://www.example.com/")
//fmt.Println(apple)
return
}
func addURL(apple *domain.Apple, url string) {
structValue := reflect.ValueOf(apple).Elem()
for i := 0; i < structValue.NumField(); i++ {
fieldValue := structValue.Field(i)
// skip non-string field
if fieldValue.Type().Kind() != reflect.String {
continue
}
structValue.Field(i).SetString(url + fieldValue.String())
}
}
I have big structure with more than 50 params
type Application struct {
Id int64 `json:"id"`
FullName string `json:"fullName,omitempty"`
ActualAddress string `json:"actualAddress,omitempty"`
.....
}
I use gin-gonic and when I return application I need to omit some params I've created a function which makes empty some params (playLink) and then gin returns me correct json (without unnecessary values). I heard that reflection isn't fast operation so in our case we can use a lot of ugly if-else or switch-cases. Is there any other solutions faster than reflecting and more beautiful than if-elses?
The thing is that structure params have non-empty values, so they wont by omitted by gin. That's why I've created function to make some params empty before return
The thing is, if you only want to zero a few fields, it's more readable to do it without a function, e.g.
app := Application{}
app.FullName, app.ActualAddress = "", ""
If you want to create a function for it, at least use variadic parameter, so it's easier to call it:
func zeroFields(application *Application, fields ...string) {
// ...
}
So then calling it:
zeroFields(&app, "FullName", "ActualAddress")
Yes, this will have to use reflection, so it's slower than it could be, and error prone (mistyped names can only be detected at runtime). If you want to avoid using reflection, pass the address of the fields:
func zeroFields(ps ...*string) {
for _, p := range ps {
*p = ""
}
}
This way you have compile-time guarantee that you type field names correctly, and that they have string type.
Calling it:
zeroFields(&application.FullName, &application.ActualAddress)
Try it on the Go Playground.
If I understand correctly: you want to return some values from your struct but not all of them? Perhaps a nested struct?
type Application struct {
ID struct {
ID int64 `json:"id"`
} `json:"id"`
Person struct {
Fullname string `json:"Fullname"
} `json:"person"
}
That should let you filter out the fields you want to use.
I have a couple of structures, like:
type SomeObject struct {
sample int
}
I want to fill the sample variable based on what I get in the request body. To do this, I want to create a function, pass request body as a string to it, create an empty structure inside, fill the structure with data, return it, and replace chosen structure with this.
How do I do this? What do I return from the function? Is there a way to do this?
If you're dealing with multiple types then you should make your method return an interface{}. For all of the applicable types, create a convenience method like;
func NewSomeObject(reqBody string) *SomeObject {
return &SomeObject{sample:reqBody}
}
Which takes a string and returns a new instance of the type with that field set to whatever was passed in. Your question is missing information about how you determine which type should be instantiated but assuming you have a few, you'll likely need an if/else or a switch in the method which receives the request body so to give a very vague example it would be something like;
func ProcessRequest(reqBody string) interface{} {
if someCondition {
return NewSomeObject(reqBody)
} else if otherCondition {
return NewSomeOtherObject(reqBody)
} // potentially several other statements like this
return nil // catch all, if no conditions match
}
How about
func foo (s *SomeObject) {
s.sample = 123
}
or
func (s *SomeObject) foo() {
s.sample = 123
}
Note: Im just picking the current struct/example to explain the problem.
type MsgBoxFactory struct{
db *dbSql //contains conn-pool and other DB related settings/flags
}
func (f *MsgBoxFactory) NewMsgBox(userId string) {
return MsgBox{userId, f.db} //f.db link is inevitable
}
type MsgBox struct {
ownerId string
db *dbSql
}
func (m *MsgBox) NewMessage(content string) *Message {
return Message{content, *m.dbSql} //m.dbSql link is inevitable
}
type Message struct {
content string
//other fields such as recipents, isRead, created time etc.
db *dbSql
}
func (m *Message) Send(to string) {
message.to = to //just imagine this saves the message to database.
m.db.Save(message)
}
I tend to call this "backward-referencing"[i don't know actual name]... Is this the only way? Previously i was "backward-referencing" entire parent objects. Now i find myself "backward-referencing" objects such as config/dbconn etc...
Is this a good way? what is better?
Oh i have also tried closure to get rid of it atleast from view.
type Message Struct{
content string
Send func(string) error // the problem is `json:"-"` needs to be added. Else the objects are not json compatible
}
func (m *MsgBox) NewMsg(content string) *Message {
msg := &Message{ content }
msg.Send = func(to string) error {
return m.db.Save(msg)
}
}
Basically the code looks almost equally cluttered with unnecessary complexity/code
EDIT: The question is not specific to go. Just posted it because i use go. Any tag suggestion is appreciated to open the question for wider community.
I usually implement a model helper relationship.
Where MsgBox is your model which has all the data specific elements (No DB related elements).
The MsgBoxHelper does all your database related work.
(i.e.
err := MsgBoxHelper.Save(MsgBox)
msgBox, err := MsgBoxHelper.Load(Key)
)
Edit:
The advantage with this method is it decouples your Model from the datastore, which should inturn make it easier should you wish to change your underlying technology (Which doesn't often happen). In practice it's more useful should you start doing things like caching.
If generically you are referencing other structures within your model i.e.
type MsgBox struct {
Colour *MsgBoxColour
...
}
type MsgBoxColor struct {
ID int
...
}
then when you load the Model in your MsgBoxHelper you call the MsgBoxColourHelper with the ID you stored in the MsgBoxColour table, this then returns your MsgBoxColour that you then associate with the returning MsgBox.