Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I have a backend response that has the format:
{
"Items": [
{
"Id": "blabla",
"Text": "blabla",
"Description": "blabla"
},
{
"Id": "blabla",
"Text": "blabla",
"Description": "blabla"
}]
}
Which will be the best Swift approach to directly decode the array?
For the moment I have a struct for the response, but I have also to take in account the "Items" key, which hasn't any business logic implication for the project.
struct SearchResult: Decodable {
let Id: String
let Text: String
let Description: String
}
Your JSON is missing a trailing ] on the end of the array.
Besides that, you just need a wrapper than gives you the Items array. This, for example, works fine:
let jsonData = """
{
"Items": [
{
"Id": "blabla",
"Text": "blabla",
"Description": "blabla"
},
{
"Id": "blabla",
"Text": "blabla",
"Description": "blabla"
}
]
}
""".data(using: .utf8)!
struct ResultWrapper: Decodable {
var Items : [SearchResult]
}
struct SearchResult: Decodable {
let Id: String
let Text: String
let Description: String
}
do {
let results = try JSONDecoder().decode(ResultWrapper.self, from: jsonData)
print(results.Items) //this is your array
} catch {
print(error)
}
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Generally, I understand how Codable works. A simple example would be:
[
{
"id": 1,
"name": "Paul",
"photo": {
"id": 48,
"url": "https://..."
}
},
{
"id": 2,
"name": "Andrew",
"photo": {
"id": 389,
"url": "https://..."
}
}
]
which would require two simple structs:
struct User: Codable {
var id: Int
var name: String
var photo: Photo
}
struct Photo: Codable {
var id: Int
var url: String
}
Given the example above, my API's response json comes in a more complicated format:
{
"data": [
{
"data": {
"id": 1,
"attributes": {
"name": "Paul"
},
"relationships": {
"photo": {
"data": {
"id": 48,
"attributes": {
"url": "https://..."
}
}
}
}
}
},
{
"data": {
"id": 2,
"attributes": {
"name": "Andrew"
},
"relationships": {
"photo": {
"data": {
"id": 389,
"attributes": {
"url": "https://..."
}
}
}
}
}
}
]
}
I've played around with SwiftyJSON to pre-parse / flatten the json by removing all the noise and trying to make the format like in the first json example. However, I feel like there's probably a better, more obvious way to do it, and manipulating the json seems very error prone.
I've read about CodingKeys, but at this point, that's almost as much extra work as it would be to parse the json all manually using SwiftyJSON.
Does anyone know how to do this efficiently?
Use quicktype.io to generate the response models for you from the specified JSON.
import Foundation
// MARK: - Root
struct Root: Codable {
let data: [Datum]
}
// MARK: - Datum
struct Datum: Codable {
let data: DatumData
}
// MARK: - DatumData
struct DatumData: Codable {
let id: Int
let attributes: PurpleAttributes
let relationships: Relationships
}
// MARK: - PurpleAttributes
struct PurpleAttributes: Codable {
let name: String
}
// MARK: - Relationships
struct Relationships: Codable {
let photo: Photo
}
// MARK: - Photo
struct Photo: Codable {
let data: PhotoData
}
// MARK: - PhotoData
struct PhotoData: Codable {
let id: Int
let attributes: FluffyAttributes
}
// MARK: - FluffyAttributes
struct FluffyAttributes: Codable {
let url: String
}
let root = try JSONDecoder().decode(Root.self, from: jsonData)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I want to build a json like
{
"data": {
"posts": [
{"title": "first", "body": "first body"},
{"title": "second", "body": "second body"}
],
"categories": [
{"name": "red"},
{"name": "white"}
]
}
}
It includes two parts of data: post and category. They are different structure. But want to send them together one time.
With this code
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
type Article struct {
Data struct {
Post []struct {
Title string `json:"title"`
Body string `json:"body"`
} `json:"posts"`
Category []struct {
Name string `json:"name"`
} `json:"categories"`
} `json:"data"`
}
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
article := &Article{}
data := article.Data
post := data.Post
post[0].Title = "first"
post[0].Body = "first body"
post[1].Title = "second"
post[1].Body = "second body"
category := data.Category
category[0].Name = "red"
category[1].Name = "white"
return c.JSON(http.StatusOK, article)
})
e.Logger.Fatal(e.Start(":8008"))
}
I tried to make a root struct Article, then define its children, then set data to tree one by one.
When run the server and call / endpoint, got error
echo: http: panic serving [::1]:49501: runtime error: index out of range [0] with length 0
goroutine 35 [running]:
net/http.(*conn).serve.func1(0xc00012afa0)
/Users/user/.goenv/versions/1.15.7/src/net/http/server.go:1801 +0x147
panic(0x1314380, 0xc00001a200)
/Users/user/.goenv/versions/1.15.7/src/runtime/panic.go:975 +0x47a
main.main.func1(0x139b160, 0xc000208000, 0x0, 0x0)
/Users/user/test/testecho/server.go:28 +0x13b
github.com/labstack/echo/v4.(*Echo).add.func1(0x139b160, 0xc000208000, 0x0, 0x0)
/Users/user/go/1.15.7/pkg/mod/github.com/labstack/echo/v4#v4.2.0/echo.go:536 +0x62
github.com/labstack/echo/v4.(*Echo).ServeHTTP(0xc000180000, 0x1397680, 0xc000200000, 0xc000072000)
/Users/user/go/1.15.7/pkg/mod/github.com/labstack/echo/v4#v4.2.0/echo.go:646 +0x187
Then tried this
e.GET("/", func(c echo.Context) error {
article := &Article{
Data: struct{
"Post": {
{
"Title": "first",
"Body": "first body",
},
{
"Title": "second",
"Body": "second body",
},
},
"Category": {
{
"Name": "red",
},
{
"Name": "white",
},
},
}
a, err := json.Marshal(article)
if err != nil {
fmt.Println(err)
}
return c.JSON(http.StatusOK, a)
})
But the Data: struct{ line got expected expression.
You can simplify the code required by declaring a named type for each object in the output:
type Post struct {
Title string `json:"title"`
Body string `json:"body"`
}
type Category struct {
Name string `json:"name"`
}
type Data struct {
Posts []Post `json:"posts"`
Categories []Category `json:"categories"`
}
type Article struct {
Data Data
}
With this change, it's easy to write the composite literal:
article := &Article{
Data: Data{Posts: []Post{
{
Title: "first",
Body: "first body",
},
{
Title: "second",
Body: "second body",
},
},
Categories: []Category{
{
Name: "red",
},
{
Name: "white",
},
},
},
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
How can I unmarshal the following json into golang struct
{
"VM": {
"0": {
"component": "A",
"name": "hostname1",
"hostname": "hostname1",
"role": "NODE",
"this": true,
"type": "t1"
},
"1": {
"component": "B",
"name": "hostname2",
"hostname": "hostname2",
"role": "role2",
"type": "t2"
},
"2": {
"component": "C",
"name": "hostname3",
"hostname": "hostname3",
"role": "role3",
"type": "t3"
},
"n": { //this can go upto n levels
"component": "N",
"name": "hostnamen",
"hostname": "hostnamen",
"role": "rolen",
"type": "tn"
}
}
}
This is a handy online resource to get you started: https://mholt.github.io/json-to-go/
It does however get tripped up by defining specific struct fields instead of using a map - which appears the case here.
Striking a balance:
type Collection map[string][string]Component
type Component struct {
Component string `json:"component"`
Name string `json:"name"`
Hostname string `json:"hostname"`
Role string `json:"role"`
This bool `json:"this"`
Type string `json:"type"`
}
If your output always has a "VM" key at the top-level, then the Collection type could be flattened to something like:
type Collection struct {
VM map[string]Component `json:"VM"`
}
// Component def stays the same
If you're confident the component indices will always be numeric, this may work too:
type Collection struct {
VM map[int]Component `json:"VM"` // index by `int` instead of `string`
}
PlayGround example: https://play.golang.org/p/ewHnlq8h1Vc
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
How would I parse this JSON into Codeable struct. I am also using Moya library to make request
{
"categories": [
{
"categories": {
"id": 1,
"name": "Delivery"
}
},
{
"categories": {
"id": 2,
"name": "Dine-out"
}
},
{
"categories": {
"id": 3,
"name": "Nightlife"
}
}
]
}
Right now my Codeable struct looks like below:
struct Response: Codable {
struct Category: Codable {
let id: Int
let name: String
}
var categories: Category
}
I am gettig an error saying Expected to decode Array but found a Dictionary instead.
UPDATE
provider.request(.categories) { (result) in
// guard let self = self else { return }
switch result {
case .success(let response):
let data = response.data
//let json = try? JSON(data: data)
// swiftlint:disable:next force_try
let test = try! JSONDecoder().decode([Respo].self, from: data)
print(test)
// self.collectionView.reloadData()
case .failure(let error):
print(error)
}
}
Reason:
In you model Response, categories is of type Category. But as per your JSON response, categories is an array of dictionary. That's the reason it is giving Expected to decode Array but found a Dictionary instead
Solution:
categories in Response model must be of type [[String:Category]] instead.
So, The models for parsing the above data should be,
struct Response: Codable {
let categories: [[String:Category]]
}
struct Category: Codable {
let id: Int
let name: String
}
Edit:
Parse it like,
do {
let response = try JSONDecoder().decode(Response.self, from: data)
print(response)
} catch {
print(error)
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I need to get all the "students_id" value in the below json and store that in an array.Please tell me the efficient way to do this.Please help.Thanks
{
"status": "success",
"user": [
{
"student_id": 1,
"first_name": "Student 1",
"last_name": "Student 1",
"emergency_contact_person": null,
"dob": "0000-00-00",
"class_section_id": 1,
"class_section_name": "A",
"class_id": 1,
"class_name": "10th"
},
{
"student_id": 2,
"first_name": "Student 2",
"last_name": "Student 2",
"emergency_contact_person": null,
"dob": "0000-00-00",
"class_section_id": 1,
"class_section_name": "A",
"class_id": 1,
"class_name": "10th"
}
],
"response": 200
}
You could make use of the Codable protocol. Just create a struct that mirrors the structure if your JSON return:
struct Response: Codable {
let status: String
let user: [Student]
}
struct Student: Codable {
let student_id: Int
let first_name: String
let last_name: String
let emergency_contact_person: String?
let dob: String
let class_section_id: Int
let class_section_name: String
let class_id: Int
let class_name: String
}
From there, you'd use JSONDecoder to decode your JSON and then extract the IDs you need from it using map:
let jsonData = json.data(using: .utf8)
let decoder = JSONDecoder()
var studentIDs: [Int] = []
if let jsonData = jsonData {
do {
let responseStruct = try decoder.decode(Response.self, from: jsonData)
studentIDs = responseStruct.user.map{$0.student_id}
} catch {
print("\(error): \(error.localizedDescription)")
}
}
Here's a link to a post re: decoding JSONs in Swift 4.
If you don't need everything from the JSON, then you could just abbreviate your structs to parse only the elements you need. In this example, you could abbreviate your struct to something like this:
struct Response: Codable {
let user: [Student]
}
struct Student: Codable {
let student_id: Int
}
You could always use a for loop and iterate through each section under user
for string["users"].each do |x| # => string has your PARSED json
return x["student_id"]
end
The code is written in ruby but you will have a basic idea of what to do.