Home > Software engineering >  Parse remote JSON without creating models in Swift, in a single function
Parse remote JSON without creating models in Swift, in a single function

Time:01-23

My app must fetch JSON via HTTPS request, and then parse that data.

What I'm looking for is to have a "one function rules all" approach to it, like so.

func call(endpoint: String) {
   let url = URL(string: "https://example.com/api/" endpoint)

   URLSession.shared.dataTask(with: url!) { (data, response, error) in
      // Parse JSON here without using a model.
      // Just convert the data into a JSON object and return it
   }
}

Every single example code I've come across seems to me that you need to make a model with the expected values, and then do this:

JSONDecoder().decode(ModelHere.self, from: data)

This means that I need to make a new function for each endpoint.

Why not just use a separate function for each endpoint?

I have a lot of endpoints that could be called from within a function.

Creating a new function for each endpoint to pass it a separate model to then parse the data from the response ... that is a lot of junk to sift through in the code.

I'm sure there is a better way to do it that is just obscure, or I'm missing.

Essentially, I'm looking for this:

a function needs remote data to load a view -> fires call('endpoint/example/') -> call() returns the json object -> the function can now take the data it needs

Multiple processor functions, one call() function. I hope I'm making sense.

Thanks

EDIT

Here is the solution to the problem:

private var host = "https://jsonplaceholder.typicode.com/"

func call<T: Codable>(endpoint: String, completion: @escaping (T)->()) {
    let url = URL(string: host endpoint)
    
    URLSession.shared.dataTask(with: url!) { (data, response, error) in
        do {
            let model = try JSONDecoder().decode(T.self, from: data!)
            completion(model)
        } catch let error {
            print(error.localizedDescription)
        }
    }.resume()
}

Please make your necessary adjustments as this has just been lifted from my playground env, can't guarantee it's "proper".

CodePudding user response:

That's what generic is for, for instance:

You can define T as a your date model which is a generic type, and you fetch it and return it with completion. Making T as codable so any model that conforms codable will make this call.

func call<T: Codable>(endpoint: String, completion: (T) -> ()) {
   let url = URL(string: "https://example.com/api/" endpoint)

   URLSession.shared.dataTask(with: url!) { (data, response, error) in
      // Parse JSON here without using a model.
      // Just convert the data into a JSON object and return it
      let model = JSONDecoder().decode(T.self, from: data)
      completion(model)
   }
}

And when you call the function:

call(endpoint: "something") { model: ModelHere in 
   // Use your model
}

So you don't have to make separate functions for every model you have.

** Code not been tested, just as an idea

  •  Tags:  
  • Related