I'm using the ASP.Net Web API to build a RESTful Service. I'm struggling to find a clean way to add HATEAOS links into the json returned to my clients.
For example I have
public class LongRequest
{
public int Id {get;set;}
public int Progress {get;set;}
}
public HttpResponseMessage Post(LongRequest request)
{
var response = Request.CreateResponse(HttpStatusCode.Accepted, request);
string uri = Url.Link("DefaultApi", new { Id = request.Id });
response.Headers.Location = new Uri(uri);
return response;
}
I want my returned json to include a Cancel and Self link in the json that looks like
'
{
"LongRequest":{
"Id":"32",
"Progress":"33",
"link":{
"rel":"self",
"href":"/LongRequest/32"
},
"link":{
"rel":"cancel",
"href":"/LongRequest/32"
},
}
}
'
What I've done right now is created a link class.
public class Link
{
public string method { get; set; }
public string href { get; set; }
}
and modified LongRequest to be
public class LongRequest
{
public int Id {get;set;}
public int Progress {get;set;}
public Link self
{
get{
return new Link(){href="/Status/"+Id,method="GET"};
}
}
public Link cancel
{
get{
return new Link() { href = "/Status/" + Id, method = "DELETE" };
}
}
}
Which results in json that looks like
{
"Id":0,
"Progress":1,
"self":{"method":"GET","href":"/Status/0"},
"cancel":{"method":"DELETE","href":"/Status/0"}
}
If you want to include links in a standardized way then take a look at some of the hypermedia enabled formats:
Mason: https://github.com/JornWildt/Mason
HAL: https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-07
Siren: https://github.com/kevinswiber/siren
Collection+JSON: http://amundsen.com/media-types/collection/format/
JSON API: http://jsonapi.org/
Hydra: http://www.markus-lanthaler.com/hydra/
Related
I have the following dotnet core code and I'm trying to return a TestResponse JSON object that has a few nodes under it. However, using the return Enumerable.Range(1, 4).Select(index => new Entities.TestResponse call in the post return for some reason all the attributes of response are not found in the enclosure when clearly Entities.TestResponse has the response definition. I'm probably not configuring the Enumerable enclosure correctly. Does anyone know how to resolve this, so I can set the response.result & response.exception and return response JSON from my REST POST method?
namespace TestApi.Entities
{
public class TestResponse
{
public TestResponseNodes response { get; set; }
}
public class TestResponseNodes
{
public string result { get; set; }
public string exception { get; set; }
}
}
[HttpPost]
public Task<IEnumerable<Entities.TestResponse>> Post([FromBody] String input)
{
return Enumerable.Range(1, 4).Select(index => new Entities.TestResponse
{
response.result = "No Error",
response.exception = "None"
}).ToArray();
}
Your syntax is wrong, you need to also new up the inner object, for example:
new Entities.TestResponse
{
response = new Entities.TestResponseNodes
{
result = "No Error",
exception = "None"
}
}
As an aside, you should follow common C# conventions and capitalise your property names, for example:
public class TestResponse
{
public TestResponseNodes Response;
}
public class TestResponseNodes
{
public string Result { get; set; }
public string Exception { get; set; }
}
How can I upload file?
So my model looks like this:
public class HtPermitOrderRequest
{
public IFormFile FormFile { get; set; }
public List<string> Woids { get; set; }
public string Io { get; set; }
public string Contractor { get; set; }
public string NavisionWo { get; set; }
}
Service
requestPermitsForOrders(model: HtPermitOrderRequest){
return this.http.post(baseUrl + '/api/mass-actions/request-permits', model);
}
calling service like this:
let formData = new FormData();
formData.append("formFile", result.formFile[0]);
this.dataToSend = {formFile: formData, io: result.io, woids: woids, contractor: result.contractor, navisionWo: result.navisionWo};
console.log(this.dataToSend);
this.configurationService.requestPermitsForOrders(this.dataToSend).subscribe(res => {
});
This is error that I am getting:
I tried to make request with postman and it was ok so I guess I am doing something wrong in angular.
You are trying to send json. But you need to send it with formdata.
let formData = new FormData();
formData.append("formFile", result.formFile[0]);
formData.append("io", result.io);
formData.append("woids",woids);
formData.append("contractor", result.contractor);
formData.append("navisionWo", result.navisionWo);
this.configurationService.requestPermitsForOrders(formData).subscribe(res => {
});
accept formdata in function
requestPermitsForOrders(model: any){
return this.http.post(baseUrl + '/api/mass-actions/request-permits', model);
}
In one of my API actions (PostOrder) I may be consuming another action in the API (CancelOrder). Both return a JSON formatted ResultOrderDTO type, set as a ResponseTypeAttribute for both actions, which looks like this:
public class ResultOrderDTO
{
public int Id { get; set; }
public OrderStatus StatusCode { get; set; }
public string Status { get; set; }
public string Description { get; set; }
public string PaymentCode { get; set; }
public List<string> Issues { get; set; }
}
What I need is reading/parsing the ResultOrderDTO response from CancelOrder, so that I can use it as response for PostOrder. This is what my PostOrder code looks like:
// Here I call CancelOrder, another action in the same controller
var cancelResponse = CancelOrder(id, new CancelOrderDTO { Reason = CancelReason.Unpaid });
if (cancelResponse is OkNegotiatedContentResult<ResultOrderDTO>)
{
// Here I need to read the contents of the ResultOrderDTO
}
else if (cancelResponse is InternalServerErrorResult)
{
return ResponseMessage(Request.CreateResponse(HttpStatusCode.InternalServerError, new ResultError(ErrorCode.InternalServer)));
}
When I use the debugger, I can see that the ResultOrderDTO it is there somewhere in the response (looks like the Content) as shown in the pic below:
but cancelResponse.Content does not exist (or at least I don't have access to it before I cast my response to something else) and I have no idea about how to read/parse this Content. Any idea?
Simply cast the response object to OkNegotiatedContentResult<T>. The Content property is object of type T. which in your case is object of ResultOrderDTO.
if (cancelResponse is OkNegotiatedContentResult<ResultOrderDTO>)
{
// Here's how you can do it.
var result = cancelResponse as OkNegotiatedContentResult<ResultOrderDTO>;
var content = result.Content;
}
i use RestSharp to access a Rest API. I like to get Data back as an POCO.
My RestSharp Client looks like this:
var client = new RestClient(#"http:\\localhost:8080");
var request = new RestRequest("todos/{id}", Method.GET);
request.AddUrlSegment("id", "4");
//request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
//With enabling the next line I get an new empty object of TODO
//as Data
//client.AddHandler("*", new JsonDeserializer());
IRestResponse<ToDo> response2 = client.Execute<ToDo>(request);
ToDo td=new JsonDeserializer().Deserialize<ToDo>(response2);
var name = response2.Data.name;
my Class for the JsonObject looks like this:
public class ToDo
{
public int id;
public string created_at;
public string updated_at;
public string name;
}
and the Json Response:
{
"id":4,
"created_at":"2015-06-18 09:43:15",
"updated_at":"2015-06-18 09:43:15",
"name":"Another Random Test"
}
Per the documentation, RestSharp only deserializes to properties and you're using fields.
RestSharp uses your class as the starting point, looping through each
publicly-accessible, writable property and searching for a
corresponding element in the data returned.
You need to change your ToDo class to the following:
public class ToDo
{
public int id { get; set; }
public string created_at { get; set; }
public string updated_at { get; set; }
public string name { get; set; }
}
I am developing an app for iOS using Xamarin Studio (C#) in Mac OS X. I want to get a list of the user's friends on Facebook, so I added Facebook's component from Xamarin's component store and made a request(code at the bottom). This is the response I get:
{
data = (
{
"first_name" = Dev;
id = 100001438778777;
"last_name" = Accu;
}
);
paging = {
next = "https://graph.facebook.com/v2.0/100005203000814/friends?fields=id,first_name,last_name&format=json&access_token=CAAK3hGOIm2ABANPUcr2QU1t8gqLNsZCJBrc8ZCZCqUSwHkX2f43VHarvc1ZABbjDrY7jIO0OT5ZBRBiZC1audQnIvxCsOu60y30iR84jVa56beNTptixj7AFqT92ZBGdyxDshFHHxkFDgCg9JyRZBYfqaGKkeJkuxJVUXDq8eR8ZCmRlslpOVSavQZC1hCcxOwdgFS2jWQdGZBFVSYTkrhkavfP&limit=5000&offset=5000&__after_id=enc_Aey-LjP59ZnmKMcZKcEr94tTUPIHIvWj9JnMwkIVSvxJ9RBYBqhBt3bGKlURY4SHBCDeH8BM_wSsqICzEFgKiZvh";
};
}
There is 2 problems with this response, it only includes 1 friend for some unknown reason, and the JSON is not valid, so ultimately parsing this fails. The following is the code I use to make the request:
var friendsRequest = await new FBRequest(FBSession.ActiveSession, "/me/friends?fields=id,first_name,last_name").StartAsync();
var friendsArray = friendsRequest.Result as MonoTouch.Foundation.NSMutableDictionary;
var response = FriendResponse.FromJson(friendsArray.ToString());
List<FacebookProfile> friends = new List<FacebookProfile>();
foreach (var friend in response.Data)
{
friends.Add(new FacebookProfile(friend.ID, friend.FirstName, friend.LastName));
}
And here is the parsing classes:
public class NextPage
{
public string Next { get; set; }
}
public class Friend
{
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class FriendResponse
{
public List<Friend> Data { get; set; }
public NextPage Paging { get; set; }
public static FriendResponse FromJson(string json)
{
JsConfig.EmitLowercaseUnderscoreNames = true;
return JsonSerializer.DeserializeFromString<FriendResponse>(json);
}
}
The component is a 1:1 binding to the objective-c SDK. The response that Facebook returns is an NSDictionary underneath, and if you run ToString() on it, it will return the string representation of the NSDictionary which is totally different from a JSON
string. What you have to do is serialize that NSDictionary object back into a JSON string. Here is an example of how to do this:
var friendsRequest = await new FBRequest(FBSession.ActiveSession, "/me/friends?fields=id,first_name,last_name").StartAsync();
// Convert back the object into a Json
NSError error;
var jsonData = NSJsonSerialization.Serialize (friendsRequest.Result, 0, out error);
var jsonString = (string) NSString.FromData (jsonData, NSStringEncoding.UTF8);
var response = FriendResponse.FromJson(jsonString);
"jsonString" will have the correct JSON string data representation this time.
Courtesy of Alex DeSoto. =)