I got a response from redash as follows:
{'PP_DOM': '{"DEFAULT":100}',....................., 'Myst':'["a","b","c","d"]',
I want to unmarshal "myst" key's value as a list in golang.I am newbie here.
You can unmarshall into map[string]interface{} if you have an unknown data structure to explore it. you then may later want to define a struct which maps to the data properly. So to get started, use something like this:
var jsonData = []byte(`{"PP_DOM": {"DEFAULT":100},"Myst":["a","b","c","d"]}`)
var data map[string]interface{}
err := json.Unmarshal(jsonData, &data)
if err != nil {
fmt.Println("json: error decoding", err)
}
fmt.Printf("Myst:%+v", data["Myst"])
https://play.golang.org/p/V5GBtLH6oLs
Your json doesn't appear to be valid, better to post what you have tried instead, which should at least involve valid json.
You should take a look at the docs for the json pkg, in particular the examples.
Related
If I use the standard library to make this response, the type Writer Interface only takes a slice of bytes as an argument, but an array wrapped JSON is [][]byte
I know there must be something I'm missing here...
And as a note, I tried using the Echo Framework for this and it does successfully send but it's auto encoding the contents into base64 which is not what I want for my API right now.
json, err := json.Marshal(j)
check(err)
arrJSON := [][]byte {
json,
}
fmt.Printf("arrJSON: %s", arrJSON) // this prints correctly
return c.JSONPretty(http.StatusOK, arrJSON, "") //this returns a base64 encoded array wrapped JSON (it works but I wan't decoded)
I am building an app where people need to fill out a form and then it creates an HTTP post where the API will return a Json file to the app with data I need. Everything is working fine with accessing the API however I want to parse the data in another view controller. How can I access the JSON file from another view controller?
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else {
return
}
guard let data = data else {
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print(json)
^^^^^^^
How do I take this JSON file to the next view controller so I dont have to do the parsing below?
let jsonData = json
let ratesJson = jsonData["rates"]!
let rates = ratesJson as! NSArray
print("Rates: \(rates)")
print("*************")
print(rates.count)
print("*************")
for item in 0..<rates.count {
let specificRate = rates[item]
let price = (specificRate as AnyObject)["amount_local"]!
let provider = (specificRate as AnyObject)["provider"]!
print("--\(item)--")
print("Price: \(price!)")
print("Provider: \(provider!)")
}
}
} catch let error {
print(error.localizedDescription)
}
})
I assume by your comment, your intention is to actually pass a JSON object, not a JSON file to the next view controller.
Therefore, you just need to pass the JSON object to your segue and assign it as a property to the next view controller.
Since the question was very open ended, here is one possible solution and interpretation.
Example:
//Sample snippet from code from question
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
performSegue(withIdentifier: "MySegue", sender: json);
}
override func prepare(for segue: UIStoryboardSegue!, sender: Any?) {
if (segue.identifier == "MySegue") {
let vc = segue.destinationViewController as! RandomViewController
vc.json = sender as! [String:Any];
}
}
One of the things that usually cause bugs in programs is state. What you are asking here in my opinion is state.
What I would do is i would write a generic function ( Swift encourages functional programming in a lot of cases, have a look at: swift map, filter etc. that deals with the HTTP request and returning the data in a closure.
This closure will then live within the view controller you want your json object in, thus solving your problem of accessing said data.
Now I don't believe that is the right approach either. I would create an object for your specific data returned, like say a "struct Person" or whatever your needs are.
This has 2 advantages:
In swift 3.1 you can have a custom init() method that parses the JSON safely ( remember, optionals! ) and populates the structs data accordingly
In swift 4.0 and Xcode9.0 You will be able to morph the struct you just created to conform to the Codable and Decodable protocols with wich json parsing will be greatly simplified, as explained here: ultimate swift json guide
Hope this was of any help.
I want to build my endpoint, which accept JSON array of below format:
[
{
"test":"Math",
"result":"Pass"
},
{
"test":"Science",
"result":"FirstClass"
}
]
It will be a POST call with the above JSON to my endpoint.
I tried it with servlet too but did not get the required result, and also tried to with list and inserting in a new class and posting to that class. Thanks in advance.
Is that an accurate representation of the JSON object which is being sent over? Because one does not simply send a a POST request with a JSON object of their param object to a cloud endpoint. See here for a thorough guide to Endpoint API interaction from a javascript perspective - notice how the client library exposes an object "gapi" through which calls are made. If you're sending this JSON from an iOS or Android app, there are similar client libraries which can be generated for you by a cloud endpoints build tool.
After much frustration, I resorted to reading the docs more carefully. In that quest, I found an important note in the doc:
https://cloud.google.com/endpoints/docs/frameworks/java/parameter-and-return-types
"Any type except a parameter or injected type is considered an entity type. ... Entity types cannot be annotated with #Named"
With all examples showing named parameters, I was stumped as the docs don't explain further, but then found a solution. It ends up that if you do not have named parameters, everything is just passed in as a LinkedHashMap. Usually, you can do any work you need to with just that data structure, but if you HAVE to have it in JSON, you can convert it. Here are some examples:
#ApiMethod(name = "endpointIterfaceName.createItems", httpMethod = "post", path = "test/items")
public WhateverReturnType createItems(LinkedHashMap<String, Object> itemsMap) {
// Do Stuff with map values
return whateverReturnValue;
}
With this, you need to be sure that you post your data with the Content-Type of json (i.e. Content-Type:application/json; charset=UTF-8). So, for example, when testing, with a jquery ajax call you would need to set dataType to "json" or with Postman, you would select "Raw" then JSON (application/json).
If you really want to convert this to a JSON object in Java because for whatever reason you can not use a hash map, you can do the following in your method:
// Use gson library to convert the map to a string
Gson gson = new Gson();
String mapAsJsonString = gson.toJson(itemsMap);
// create a JSON object from the new string representation
JSONObject obj = new JSONObject(mapAsJsonString);
As a side note, if this is passed as Content-Type:text then the whole body will be in the map as the first key of the map. You could do some inadvisable things here and just get that key and avoid converting the map to a string and then to a json object, but, like I said, that is inadvisable. :)
Google's docs omit the most important aspect: How a Task is created. Can anybody complete the sample code:
import (
"appengine/datastore"
"appengine/taskqueue"
)
func f(c appengine.Context) {
err := datastore.RunInTransaction(c, func(c appengine.Context) error {
t := ... // WHY DOES GOOGLE NOT EXPLAIN THIS PART???
// Use the transaction's context when invoking taskqueue.Add.
_, err := taskqueue.Add(c, t, "")
// ...
})
// ...
}
I think what you need is described in the docs for datastore transactions.
So the missing code to create a task is:
t := &taskqueue.Task{Path: "/path/to/workertask"}
The reference for the Task type shows that Task is a struct with 10 or so fields, so you probably don't want to construct a Task yourself. However, it also provides the NewPOSTTask function (just below that):
NewPOSTTask creates a Task that will POST to a path with the given form data
I agree the documentation could be much better though.
I am trying to upload a file in my GAE app. How do I the upload of a file in Google App Engine using Go and using the r.FormValue()?
You have to go through the Blobstore Go API Overview to get an idea and there is a full example on how could you store & serve user data on Google App Engine using Go.
I would suggest you to do that example in a completely separate application, so you'll be able to experiment with it for a while before trying to integrate it to your already existing one.
I managed to solve my problem by using the middle return param, "other". These code below are inside the upload handler
blobs, other, err := blobstore.ParseUpload(r)
Then assign corresponding formkey
file := blobs["file"]
**name := other["name"]** //name is a form field
**description := other["description"]** //descriptionis a form field
And use it like this in my struct value assignment
newData := data{
Name: **string(name[0])**,
Description: **string(description[0])**,
Image: string(file[0].BlobKey),
}
datastore.Put(c, datastore.NewIncompleteKey(c, "data", nil), &newData )
Not 100% sure this is the right thing but this solves my problem and it is now uploading the image to blobstore and saving other data and blobkey to datastore.
Hope this could help others too.
I have tried the full example from here https://developers.google.com/appengine/docs/go/blobstore/overview, and it worked fine doing the upload in blobstore and serving it.
But inserting extra post values to be saved somewhere in the datastore erases the values of "r.FormValue() "? Please refer to the code below
func handleUpload(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
//tried to put the saving in the datastore here, it saves as expected with correct values but would raised a server error.
blobs, _, err := blobstore.ParseUpload(r)
if err != nil {
serveError(c, w, err)
return
}
file := blobs["file"]
if len(file) == 0 {
c.Errorf("no file uploaded")
http.Redirect(w, r, "/", http.StatusFound)
return
}
// a new row is inserted but no values in column name and description
newData:= data{
Name: r.FormValue("name"), //this is always blank
Description: r.FormValue("description"), //this is always blank
}
datastore.Put(c, datastore.NewIncompleteKey(c, "Data", nil), &newData)
//the image is displayed as expected
http.Redirect(w, r, "/serve/?blobKey="+string(file[0].BlobKey), http.StatusFound)
}
Is it not possible to combine the upload with regular data? How come the values of r.FormValue() seems to disappear except for the file (input file type)? Even if I would have to force upload first before associating the blobkey, as the result of the upload, to other data, it would not be possible since I could not pass any r.FormValue() to the upload handler(which like I said becomes empty, or would raised an error when accessed prior the blobs, _, err := blobstore.ParseUpload(r) statement). I hope someone could help me solve this problem. Thank you!
In addition to using the Blobstore API, you can just use the Request.FormFile() method to get the file upload content. Use net\http package documentation for additional help.
Using the Request directly allows you to skip setting up an blobstore.UploadUrl() before handling the upload POST message.
A simple example would be:
func uploadHandler(w http.ResponseWriter, r *http.Request) {
// Create an App Engine context.
c := appengine.NewContext(r)
// use FormFile()
f, _, err := r.FormFile("file")
if err != nil {
c.Errorf("FormFile error: %v", err)
return
}
defer f.Close()
// do something with the file here
c.Infof("Hey!!! got a file: %v", f)
}