I am sending a JSON body in my POST Request, but http.DetectContentType is identifying it as a text/plain type.
I want to have flexibility to process request payload based on their content type - if XML {} if JSON {} else {NO Processing}
To achieve this conditional processing, I am using http.DetectContentType to return the content type o the request but it is returning text/plain is every scenario.
func Test(w http.ResponseWriter, r *http.Request) *ErrorObject {
reqBuffer := make([]byte, 512)
_, err := r.Body.Read(reqBuffer)
if err != nil {
return ErrorObject{}.New(1, err, nil)
}
contentType := GetContentType(reqBuffer)
fmt.Printf(contentType)
if contentType == "application/xml" || contentType == "text/xml" {
w.Header().Set("Content-Type", "application/xml; charset=UTF-8") ...}
if contentType == "application/json" || contentType == "text/json" {
w.Header().Set("Content-Type", "application/json; charset=UTF-8") ... }
else return Invalid Request Type error
}
func GetContentType(buffer []byte) string {
fmt.Println(string(buffer))
contentType := http.DetectContentType(buffer)
fmt.Printf(contentType)
return contentType
}
Expect to return the function - Content Type as application/json but getting text/plain
Using POSTMAN to send request to server with Body as raw and JSON
{
"data": [
{
"group": "TEST",
"name": "TEST",
"released": true,
"version": 1,
"teststeps": [
{
"bin": 32,
"comment": "PAA",
"dataType": "J",
"format": "R6.2",
"id": "PAA3",
"osg": 8,
"usg": 0
}
],
"parameters": [
{
"comment": "test",
"description": "test",
"format": "R7.0",
"id": 1,
"teststepId": "PAA",
"value": 30,
"type": "teststep"
}
]
}
]
}
I am using http.DetectContentType to return the content type o the request but it is returning text/plain is every scenario.
According to the documentation DetectContentType "... implements the algorithm described at https://mimesniff.spec.whatwg.org/ to determine the Content-Type of the given data". The algorithm there is primarily for handling content types which the browser can handle by itself.
And if you look at the actual code you'll see that it does not care about application/json or similar at all and that it returns text/plain for anything which looks non-binary (and was not matched before as with text/html).
In other words: this is the wrong tool for the job. The proper way would be for the client to specify what kind of content is sent using the Content-Type header and not to let the server guess the kind of content.
Related
Is there any way to dynamically include JSON from the request body in the response?
Input Request
{
"id":"1234",
"message":"{\"key\":\"value\"}"
}
Expected Output
{
"status":"CREATED",
"id":"1234",
"message":"{\"key\":\"value\"}"
}
The message and id fields are dynamic and need to be picked from the request.
I have tried the below mapping to dynamically load the response from the request but \" inside message json is converted to "
{
"request": {
"method": "POST",
"urlPath": "/test"
},
"response": {
"status": 200,
"transformers": [
"response-template"
],
"jsonBody": {
"status": "CREATED",
"id": "{{jsonPath request.body '$.id'}}",
"message": "{{jsonPath request.body '$.message'}}"
}
}
}
This returns message as {"key":"value"}.
Even, I have tried changing the mapping to {{{jsonPath request.body '$.message'}}}. But this messes up the whole response json and message value is being returned as "{"key":"value"}" without escape characters.
I'm looking for suggestions to map message dynamically. Thanks in advance.
I am trying to return a JSON response something like this:
c.JSON(http.StatusOK, gin.H{"data": resp, "code": http.StatusOK, "status": "success"})
where resp contains data from a db table (struct) which I have converted to JSON.
I need to return the response in data key in this format:
data["result"] = resp
Sample response should look like:
{
"data": {"result" : ["This is a sample response"]}
}
The response can either be an object or a list of objects.
This is in Python format, how do I do this in Go?
You could see it in the source of gin:
type H map[string]interface{}
So you could use(nested gin.H):
c.JSON(http.StatusOK, gin.H{"data":
gin.H{
"result": []string{"This is a sample response"},
},
"code": http.StatusOK,
"status": "success",
})
I am reading in a .json file. It's an array of objects in valid JSON format, example:
[
{
"Id": 13,
"Location": "Australia",
"Content": "Another string"
},
{
"Id": 145,
"Location": "England",
"Content": "SomeString"
},
{
"Id": 12,
"Location": "England",
"Content": "SomeString"
},
{
"Id": 12331,
"Location": "Sweden",
"Content": "SomeString"
},
{
"Id": 213123,
"Location": "England",
"Content": "SomeString"
}
]
I want to filter these objects out - say, removing anything where "Location"doesn't equal "England".
What I've tried so far is creating a custom UnmarshalJSON function. It does unmarshal it, but the objects it produces are empty - and as many as the input.
Sample code:
type languageStruct struct {
ID int `json:"Id"`
Location string `json:"Location"`
Content string `json:"Content"`
}
func filterJSON(file []byte) ([]byte, error) {
var x []*languageStruct
err := json.Unmarshal(file, &x)
check(err)
return json.MarshalIndent(x, "", " ")
}
func (s *languageStruct) UnmarshalJSON(p []byte) error {
var result struct {
ID int `json:"Id"`
Location string `json:"Location"`
Content string `json:"Content"`
}
err := json.Unmarshal(p, &result)
check(err)
// slice of locations we'd like to filter the objects on
locations := []string{"England"} // Can be more
if sliceContains(s.Location, locations) {
s.ID = result.ID
s.Location= result.Location
s.Content = result.Content
}
return nil
}
// helper func to check if a given string, f.e. a value of a key-value pair in a json object, is in a provided list
func sliceContains(a string, list []string) bool {
for _, b := range list {
if b == a {
fmt.Println("it's a match!")
return true
}
}
return false
}
While this runs - the output is wrong. It creates as many objects as comes in - however, the new ones are empty, f.e.:
// ...
[
{
"Id": 0,
"Location": "",
"Content": ""
},
{
"Id": 0,
"Location": "",
"Content": ""
}
]
//...
Whereas my desired output, from the first given input, would be:
[
{
"Id": 145,
"Location": "England",
"Content": "SomeString"
},
{
"Id": 12,
"Location": "England",
"Content": "SomeString"
},
{
"Id": 213123,
"Location": "England",
"Content": "SomeString"
}
]
When languageStruct.UnmarshalJSON() is called, there is already a languageStruct prepared that will be appended to the slice, no matter if you fill its content (fields) or not.
The easiest and my suggested solution is to just unmarshal normally, and post-process the slice: remove elements according to your requirements. This results in clean code, which you can easily adjust / alter in the future. Although it could be implemented as custom marshaling logic on a custom slice type []languageStruct, I would still not create custom marshaling logic for this but implement it as a separate filtering logic.
Here's a simple code unmarshaling, filtering and marshaling it again (note: no custom marshaling is defined / used for this):
var x []*languageStruct
err := json.Unmarshal(file, &x)
if err != nil {
panic(err)
}
var x2 []*languageStruct
for _, v := range x {
if v.Location == "England" {
x2 = append(x2, v)
}
}
data, err := json.MarshalIndent(x2, "", " ")
fmt.Println(string(data), err)
This will result in your desired output. Try it on the Go Playground.
The fastest and most complex solution would be to use event-driven parsing and building a state machine, but the complexity would increase by large. The idea would be to process the JSON by tokens, track where you're at currently in the object tree, and when an object is detected that must be excluded, don't process / add it to your slice. For details and ideas how this can be written, check out this anwser: Go - Decode JSON as it is still streaming in via net/http
I was hoping someone could explain what the POST request (with parameters) accomplishes. When I run the following command, provided by Alamofire's documentation, this is what is produced:
Code
let url = "https://httpbin.org/post"
let parameters: Parameters = [
"foo": "bar",
"baz": ["a", 1],
"qux": [
"x": 1,
"y": 2,
"z": 3
]
]
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default).responseJSON { response in
if((response.result.value) != nil) {
let jsonVar: JSON = JSON(response.result.value!)
print(jsonVar)
}
}
Result
{
"files" : {
},
"origin" : "192.104.181.247",
"data" : "{\"baz\":[\"a\",1],\"qux\" {\"y\":2,\"x\":1,\"z\":3},\"foo\":\"bar\"}",
"headers" : {
"Accept" : "*\/*",
"Accept-Encoding" : "gzip;q=1.0, compress;q=0.5",
"Content-Type" : "application\/json",
"Host" : "httpbin.org",
"Content-Length" : "53",
"User-Agent" : "HTTPRequest\/1.0 (com.dexstrum.HTTPRequest; build:1; iOS 10.2.0) Alamofire\/4.3.0",
"Accept-Language" : "en;q=1.0"
},
"json" : {
"baz" : [
"a",
1
],
"foo" : "bar",
"qux" : {
"x" : 1,
"y" : 2,
"z" : 3
}
},
"form" : {
},
"args" : {
},
"url" : "https:\/\/httpbin.org\/post"
}
What exactly is occurring with the parameters and the POST request?
The url you are hitting it allows a post request. You can get json response by get or post method. Usually you fetch data by get method and send data by post method. When sending data with post request it needs some parameter to satisfy its requirement , usually its predefined.
SO you are sending a post request here with alamofire and along with some parameter which satisfy its requirements. Here you are encoding the parameter as JSONEncoding.default which means it sends the parameter data encoded as json finally you get the response as json coz you declared .responseJSON . Hope that helps.
This question already has answers here:
My structures are not marshalling into json [duplicate]
(3 answers)
Closed 7 years ago.
This is my first attempt at Go and I feel I'm missing something important here. Trying to decode a JSON message from a webservice but the output I'm getting is:
{response:{requests:[]}}
All I'm really interested in is the data within the request node. My for-loop obviously isn't getting called because the array is empty. I feel like my structs need to be declared exactly as they appear in the webservice?
Sample JSON:
{
"response": {
"requests": [
{
"request": {}
},
{
"request": {
"id": 589748,
"image_thumbnail": "",
"description": "Blah blah",
"status": "received",
"user": "test"
}
}
],
"count": "50",
"benchmark": 0.95516896247864,
"status": {},
"debug": {}
}
}
type Request struct {
id int `json:"id"`
description string `json:"description"`
user string `json:"user"`
}
type Requests struct {
request Request `json:"request"`
}
type Response struct {
requests []Requests `json:"requests"`
}
type RootObject struct {
response Response `json:"response"`
}
url := "<webservice>"
req, err := http.NewRequest("GET", url, nil)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var r RootObject
decoder := json.NewDecoder(resp.Body)
decoder.Decode(&r)
fmt.Printf("%+v", r)
for _, req := range r.response.requests {
fmt.Printf("%d = %s\n", req.request.id, req.request.user)
}
Field names need to begin with upper case character to be exported identifiers.