I am trying to make a generic function that returns objects obtained via a REST API JSON response. I want to provide the type with a generic, have it submit the request/parse the JSON, and return a list of objects of the provided type (such as Item). I have the part of getting the JSON response, but using generics is new for me. Here's a pseudocode of the situation holding me up:
class Model {
func setPropertiesFromJSON(data: NSData) {
// Lookup property names of object and set from JSON fields.
}
}
class Item : Model {
var a
var b
}
class RestEndpoint {
func getModels<T>() -> [T] {
let data: NSData = ... // Submit GET request and receive JSON data.
var models = [T]()
for objectData in data {
// How to create newobj as T (subtype of Model), set its properties,
// and add it to models array?
// let newobj: T as? TrackminiModel = T()
// newobj.setPropertiesFromJSON(objectData)
// models.append(newobj)
}
return models
}
}
let restEndpoint = RestEndPoint()
var items: [Item] = restEndpoint.getModels<Item>()
The commented out code is very incorrect but that is the goal. Any thoughts on how to do this?
From your question it sound like what your are interested in is something that is a fairly common need. The ability to communicate with a backend server using a Restful API. You can continue down the path you seem to be heading an create a lot of code to accomplish this, and this answer will not provide much help in that direction.
However I would like to point you to two open source libraries, ObjectMapper, which I think addresses your question. Here is a brief description of ObjectMapper (from its github page).
ObjectMapper is a framework written in Swift that makes it easy for
you to convert your Model objects (Classes and Structs) to and from
JSON.
The second project is AlamofireObjectMapper which I think in the end might be exactly what you are looking for. Here is a brief description from that projects githup page.
An extension to Alamofire which automatically converts JSON response
data into swift objects using ObjectMapper.
All of this is built on top of Alamofire which handle all the details of communicating with Restful API's.
Again here is a brief description of Alamofire.
Alamofire is an HTTP networking library written in Swift.
Chainable Request / Response methods
URL / JSON / plist Parameter Encoding
Upload File / Data / Stream
Download using Request or Resume data
Authentication with NSURLCredential
HTTP Response Validation
Progress Closure & NSProgress
cURL Debug Output
Comprehensive Unit Test Coverage
Complete Documentation
You might feel like picking up other libraries to accomplish some task is "cheating" you out of an opportunity to learn how to do something yourself, but there are still plenty of challenges in making an app. Some would say not taking advantage of these open source libraries is "undifferentiated heavy lifting"
Related
Using yii2-httpclient, what is the correct way to access the corresponding yii\httpclient\Request instance from the resulting yii\httpclient\Response object?
I am trying to write a custom XML parser which needs to know what URL it is parsing. It does not seem to be possible to access the original Request (through which I could get the URL) from a parser instance (only the Response).
I have considered utilizing yii\httpclient\Client::EVENT_AFTER_SEND to copy the request into a variable, but that would not be thread-safe, so I need a better solution.
If your parser needs to know URL of request to parse response, it is probably not a parser and you're overusing parser API and ParserInterface. I suggest to create some component which will wrap and hide all request-response-parser logic. Then you will be able to implement custom parser and call it manually:
public function get($url) {
$client = new Client();
$response = $client->createRequest()
->setUrl($url)
->send();
return (new MyParser($url, $response))->getContent();
}
I am trying to complete a get request by returning a pre-built JsonArray, and also find a way to stream it. I can easily complete the request without any errors and return Json if I convert the JsonArray to string, like so:
get {
path("getJsonData") {
parameterMap {
params =>
complete(HttpEntity(ContentTypes.`application/json`, myJsonArray.toString))
}
}
}
However, I would like to avoid converting to string, and be able to stream the JsonArray, because the resulting JsonArray can be very large in some cases.
JsonArray is created from scratch from individual JsonObjects, and I do not use case classes, so I could not use the standard approaches I found in the documentation.
I am new to Akka Http and not sure if there is a simple way to solve this problem, would appreciate some help.
With the below you will be streaming each element of your JSON array in a separate HTTP chunk.
complete(HttpEntity(ContentTypes.`application/json`,
Source(myJsonArray.elements).map(j ⇒ ByteString(j.prettyPrint))))
Note that:
The choice of prettyPrinting the JSON can be revisited to fit your needs.
You can adjust the size of your frame by batching elements together using the Akka Streams API.
I'm building an Api Controller and I need to serialize my List to JSON as my action result.but It seems that such statements doesn't work
return Json(data, JsonRequestBehavior.AllowGet);
How can I achieve this ?
As you mentioned that you are using WEB API, I'm assuming it has the JsonFormatter configured. With that said, the responsibility to convert you action result into a JSON is not of your action but from the Media Type Formatter chosen as part of the Content Negotiation process.
That said, it's enough for your Action to return the actual List type and the Web API Media Type formatter will take care of formatting it to JSON.
For example, let's say that data is a List<Foo> where Foo is some type that you created. It is enough for your controller action to be:
public List<Foo> GetFoo()
{
var data = GetListOfFoo();
return data;
}
Have you tried using a JSON serializtion class?
I have had success using the ideas put forward in this article:
Serializing a list to JSON
Or, if you don't want to use serialization, the example for an action result using JSON in MSDN just uses a generic list object.
I need to access REST service from .NET application and it seems it can be done with any of those two packages. It's not clear to me which package is supposed to be used in which scenarios. Can anyone bring more light into this?
The short answer is yes, use Microsoft.AspNet.WebApi.Client.
https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Client/
This package adds support for formatting and content negotiation to
System.Net.Http. It includes support for JSON, XML, and form URL
encoded data.
Microsoft.AspNet.WebApi.Client actually depends on Microsoft.Net.Http, and extends the HttpClient with some more features that you would likely need to talk to a RESTful service such as ASP.NET Web API (e.g. JSON and XML support).
Both packages operate in the System.Net.Http namespace and revolve around the key HttpClient class.
The Microsoft.AspNet.WebApi.Client package contains the System.Net.Http.Formatting.dll assembly, which adds some handy extension methods to HttpClient and HttpContent (and others).
So for example:
using (var client = new HttpClient())
{
var response = await client.GetAsync("http://localhost/foo/api/products/1");
response.EnsureSuccessStatusCode();
var product = await response.Content.ReadAsAsync<ProductInfo>();
}
The ReadAsAsync method is an extension method that Microsoft.AspNet.WebApi.Client adds onto the HttpContent object. This automatically figures out if the response is JSON, XML or form URL encoded (the aforementioned content negotiation), and then uses the corresponding formatter to de-serialize it into your strongly typed model (in this case, ProductInfo).
If you tried to just use Microsoft.Net.Http, the ReadAsAsync method wouldn't be available to you, and you'd only be able to read the content as raw data such as bytes or string, and have to do the serializing / de-serializing yourself.
You also get extension methods to PUT / POST back to the service in JSON or XML without having to do that yourself:
// Save the ProductInfo model back to the API service
await client.PutAsJsonAsync("http://localhost/foo/api/products/1", product);
Key Microsoft.AspNet.WebApi.Client extensions:
https://msdn.microsoft.com/en-US/library/system.net.http.httpclientextensions.aspx
https://msdn.microsoft.com/en-US/library/system.net.http.httpcontentextensions.aspx
Is there a way to deserialize a JSON response to a custom object in Swift WITHOUT having to individually map each element.
Currently I am doing it manually with SwiftyJSON but it still requires me to map every field redundantly:
var myproperty1 = json["myproperty1"].stringValue
However coming from a C# background it is as simple as one line of code:
JsonConvert.DeserializeObject<CustomObject>(jsonString); //No mapping needed.
Source - http://www.newtonsoft.com/json/help/html/DeserializeObject.htm
Since I am writing many API endpoints I would like to avoid all the boilerplate mapping code that can be prone to errors. Keep in mind that my JSON responses will be multiple levels deep with arrays of arrays. So any function would need to be recursive.
Similiar question : Automatic JSON serialization and deserialization of objects in Swift
You could use EVReflection for that. You can use code like:
var user:User = User(json:jsonString)
or
var jsonString:String = user.toJsonString()
See the GitHub page for more detailed sample code
You should be able to use key value coding for this. You'd have to make your object a subclass of NSObject for KVC to work, and then you could loop through the elements of the JSON data and use setValue:forKey to assign a value for each key in the dictionary.
Note that this would be dangerous: If the target object did not contain a value for a specific key then your code would crash, so your program would crash on JSON data that contained invalid keys. Not a good thing.