I am using fetch API to send two values to my POST request handler...
fetch('http://localhost:8080/validation', {
method:'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
email:this.state.email,
password:this.state.password
})
I want to save both email and password as strings on the server side. Here is my attempt...
type credentials struct {
Test string
}
func Validate(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
decoder := json.NewDecoder(req.Body)
var creds credentials
err := decoder.Decode(&creds)
if err != nil {
panic(err)
}
fmt.Println(creds.Test)
}
The problem is I do not know how exactly the format of the structure being sent to the POST. I am attempting to save req.Body as a string but this yields nothing.
When I print fmt.Println I get a blank space. What is the proper way of parsing it?
Try with
type credentials struct {
Email string `json:"email"`
Password string `json:"password"`
}
You are receiving a JSON with two values. Receiving struct should have a structure matching your request. Otherwise, there are no placeholders to decode the JSON into, as in your case - email and password do not have matching struct fields. Btw. if you send "Test" in your JSON, this would work, as you have a Test field in your struct!
Regarding field names. If fields in JSON do not start with a capital letter or even have different names, then you should use so called tags.
More on tags: https://golang.org/pkg/encoding/json/#Marshal
In my example I used them to match struct field names to your json fields, i.e. to make email from json match Email field of the credentials struct.
req.Body is an io.Reader, and you can get use ioutil.ReadAll to drain it:
data, err := ioutil.ReadAll(req.Body)
asString := string(data) // you can convert to a string with a typecast
But I'm not sure if that's what you meant by trying to save req.Body as a string.
To parse the response into a data structure, you can unmarshal it into a variable of type *interface{}:
var creds interface{}
decoder.Decode(&creds)
And then examine the value:
fmt.Printf("%#v\n", creds)
Or perhaps using pp.Println(creds) which I find easier to read.
The creds variable will represent the JSON object found in the body, for your example input this will be a map[string]interface{} with two entries, presumably both of them strings. Something like:
map[string]interface{}{
"email": email_value,
"password": password_value,
}
and you check the values with:
email, ok := creds["email"].(string)
if ok {
// email will contain the value because creds["email"] passed the type check
fmt.Printf("submitted email is %#v\n", email)
} else {
// "email" property was a string (may be missing, may be something else)
}
The documentation of json.Unmarshal explains the semantics of how arbitrary JSON strings can be parsed without knowing their structure in advance in the discussion about unmarshalling to interface values.
Related
Send the request over and over again until I get the expected value in the body of the reply
I have two chained request:
In the first request, I send a parameter in the URL,
and expect to receive in the response a unique string value
this string value that I get from the first response I send as a parameter at a second request
in the second response is expected to receive a string value: "done", assigned at the status property
if actually receive as string value the string "in-process" the postman should send the same request over and over again until I get the expected string value "in process" in the body response at the postman
let jsonData = pm.response.json();
let val = jsonData.status
if (val === "in process") {
postman.setNextRequest(pm.info.requestName)
}
This will send the current reqeust multiple time if status property value is "in process"
I want to know how can I force all the properties from this struct to be able to send a POST request to our API?
First of all. I need all those optional properties because I make a GET request, I receive all those documents, I process the data, I add the file property (which is an object) then I need to send all those documents back to our server with a file added.
We have our Document
struct Document: Codable {
let allowedFormats: [String]?
let processWhereApply: [String]?
let isRequired: Bool?
let id, key, title, description: String?
var file: File?
// More properties
}
But it fails every time, because I'm not sending a string for example. I'm sending an Optional<String>
Is there anyway possible I can "force" all those properties to send them back? without like writting 25 lines of guard let var = var else { return } ?
I'm sending the POST request with the parameters like this
let params = [
"userId": userId,
"groupId": groupId,
"fileDocuments": documents! //sends all properties optional
] as [String: Any]
Api().saveDocuments(params: params)
I'm assuming that you are sending the data back as Json. In that case just use the Json encode method to convert the struct to Json which can be sent as a POST request. Json encode will deal with the null value issue by setting a corresponding value to the key in your json if the value exists and not creating the key if it doesn't exist.
For example just to get the json:
let doc1 = Document(!here you will be initialising variables!)
// below gives you json as data
let json = try! JSONEncoder().encode(doc1)
// if you want your json as string
let str = String(decoding: json, as: UTF8.self)
Here is an example making an alamofire POST request. In the case of alamofire it automatically encodes your struct as long as it conforms to Codable:
let doc1 = Document(!here you will be initialising variables!)
AF.request("https://yoururl.com",method: .post,parameters: doc1, encoder: JSONParameterEncoder.default).responseJSON { response in
switch response.result {
case .success(let json):
print("good response")
break
case .failure(let error):
print("bad response"
}
}
The Jsend protocol is a simple 'standard' of how to format json responses in a REST API. https://github.com/omniti-labs/jsend
I am generating Swagger documentation using https://github.com/swaggo/swag but am having great trouble working out how to use the declarative comment format to describe Jsend responses.
If anyone has done this, I would greatly appreciate an example snippet of how they defined the jsend response using the swag declarative comment format.
I solved this by switching to goswagger.io which had easier to handle syntax. These are the models used for the basic jsend types. For other responses I replaced the Data element with the name of the relevent struct and swagger did the rest.
// Success: no response data required
// swagger:response responseSuccess
type responseSuccess struct {
// in: body
Body struct {
// enum: success
Status string `json:"status"`
Data interface{} `json:"data"`
} `json:"body"`
}
// Error: Incorrect use of the API or the requested data is not available
// swagger:response responseError
type responseError struct {
// in: body
Body struct {
// enum: error
Status string `json:"status"`
Data interface{} `json:"data"`
Message string `json:"message"`
} `json:"body"`
}
// Fail: Backend or system failure.
// swagger:response responseFail
type responseFail struct {
// in: body
Body struct {
// enum: fail
Status string `json:"status"`
Data interface{} `json:"data"`
Message string `json:"message"`
} `json:"body"`
}
I want to retrieve a value from a URL. Provided I have a URL such as http://myurl.com/theValue1/iWantToRetrieveThis, I want to split this value and want to retrieve theValue1 and iWantToRetrieveThis. How can I do this?
I tried the code below but it seems that it's only retrieving the query string:
func decodeGetTokenRequest(_ context.Context, r *http.Request) (request interface{}, err error) {
fmt.Println("decoding here", path.Base(r.URL))
return getTokenRequest{
SellerID: r.URL.Query().Get("sellerid"), <<--- THis is empty
Scope: r.URL.Query().Get("scope"), <<-- This is also empty
Authorization: Validation{
credential: r.Header.Get("ETM-API-AUTH-KEY"),
},
}, nil
}
Ok I just had to go with #Rafal answer since what I'm trying to retrieve is not a query parameter but part of the url.
I'm connecting to my server on localhost to fetch some data. The data returned to this request is a JSON, on Postman the JSON is correctly shown, but when I'm playing with iOS, Alamofire returns me an error:
responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error
Domain=NSCocoaErrorDomain Code=3840 "Garbage at end."
UserInfo={NSDebugDescription=Garbage at end.}))
The JSON in question is:
{
"name": "TestName",
"surname": "TestSurname"
}
The thing that I do not understand is that if I force my server to return the json in form of a string so something like
"{"name": "TestName after update","surname": "TestSurname"}"
Alamofire does not complain and parses it correctly. How is that? I thought that specifying the parameter responseJSON it would have worked the other way around.
Alamofire.request("http://192.168.1.4:8080/user/abcdf").validate().responseJSON { response in
switch response.result {
case .success:
// DO stuff
case .failure(let error):
print(error)
}
}
This means your API response string is not a proper JSON. Ensure your response is valid JSON. In my case (below), JSON String had some HTML characters which broke the JSON.
If you are using Alamofire, change .responseJSON to .responseString and verify the response structure is valid JSON.
Note : if you are using Postman, you may not notice the extra unwanted character in JSON response. You need to change the response type from "Pretty" to "Raw" to observe this.
I think you need to get the data so you should have it written like this I am not sure though
Alamofire.request("http://192.168.1.4:8080/user/abcdf",method:.get).responseJSON {
response in
if response.result.isSuccess {
//do stuff
}
else {
// do other stuff
}
}