We're developing an API client to a 3rd party REST API. They have a strange way to pass custom fields associated to their objects in their JSON. Here's an example
{
"custom.lcf_v6S011I6MqcbVvB2FA5Nk8dr5MkL8sWuCiG8cUleO9c": "value",
"custom.lcf_8wtBWsdRU2Fur7GDnEeXQ7ra2Vu7R4hG1SNYdiEhh0F": "other value"
}
In the example above, they're adding an ID of a custom field after keyword "custom."
How can I customize JsonProperty on a dictionary object in C# that would properly yield this translation?
Related
I am currently trying to create a custom IRI for one of my entities in API Platform.
I know there is page in the documentation describing how to use a custom IRI (https://api-platform.com/docs/core/identifiers/), but I can't get it working.
My entity uses a value object for the id (currently used for IRI) and also for the name (should be used for IRI). But the values themself are priviate and scalar in the entity.
API Platform seems to get the information what should be used as the identifier, from my XML Doctrine mapping. I already tried to overwrite it by usung annotations, attributues and YAML definitions. Without luck.
The returned error reads:
preg_match(): Argument #2 ($subject) must be of type string
(at this point it receives the value object instead of the actual value)
best regards,
spigandromeda
I solved my problem.
To explain the solution, I have to dig a little into API Platform response generation.
API platform generates an IRI for every entity it returns (colelction and item operation)
it's using the Symfony router go generate the URI
all the necessary information can draw API Platform from different sources (YAML, XML, annotations, attributes)
the information include the identifier(s) defined for the entities resource
API Platform gets the value for the identifier via Symfony property accessor
because the property accessor is using getters before accessing private properties via reflection, it will return the VO
an ordinary VO cannot be used by the Symfony URL generator to create the URL
As I explained, I am using a VO for my Id as well. So I tried to figure out why it was working with the Id VO but not with the name VO.
Simple answer: the Id VO implemented the __toString method and the name VO didn't. So the solution was to let the name VO implement this method as well.
It was interesing to dig into the internal process of API Platform, but I also feel a little stupid :D
I faced the problem with generating React components with api-platform-generate-crud.
Model has property that is object email.
I have serializer that make my email object a string.
API endpoint is serving string.
It works for GET & POST.
When I try to generate React components error message is
TypeError: Cannot read property '0' of undefined
Looking deeper into it, looks like that generator still see my email as object not a string.
Any idea how I can force API to 'see' email property as string not object ?
The data model you define is authoritative. Types in the Hydra documentation reflect the ones in PHP classes.
Here, the email property is of type object. If you set the related data as a string somewhere, you don't respect this contract anymore. The Hydra documentation is not in sync with the returned data.
You can change the type of the email property in the Hydra documentation by decorating the api_platform.hydra.normalizer.documentation service.
But I would recommend to keep the PHP classes' structure of your entities as close as possible of the structure exposed through the API.
Your classes should reflect the output of the API. You can use custom data providers to deal with more complex data structure (ex: ORM entities) before hydrating the structure to expose.
I'm implementing the Azure's Application Insights and the API I found is I can only send there Dictionary of type string and string. Also if I use TraceTelemetry it has properties on it which again is dictionary of string and string.
However when I add one field to the custom properties (cars in my case) which has value of serialized json it will result in such a payload being sent to the Application Insights.
"baseData": {
"ver": 2,
"message": "Test Message",
"properties": {
"cars": "[{\"Id\":0,\"Price\":{\"Value\":12.32,\"Currency\":.....
}
}
notice the backslash making it one json value.
But the appinsight portal will understand it - and parse it.
So I can use Microsoft provided C# API but it just looks ugly and seems like the API is JSON anyway, so why is API limited to Dictionary<string, string> ?
It is because of filtering in Azure Portal. The main purpose of Properties (Dictionary<string, string>) is provide the ability to find specified requests, exceptions etc. You are also limited by count of properties (it was about 200). The typical properties are: "username", "isAuthenticated", "role", "score", "isAnonymous", "portalName", "group", "product" atc. Typically global properties.
If you want to send whole object / json, you can use TrackTrace(). You can find all the traces regarding to concrete request in portal.
I am using Web APi, as I am new to this, I dont know much about it.
I am trying to implement search, as of now I am starting with only text search, but later there may be huge search criteria. for one text that is easy, as web api works good with
primitive data types. Now I want to create a class of filter, say the pagenumber , the pagesize also all the search criteria, so I created a class. I have created a MVC application which is communicating with the web api, the web api returns Json data, then I de-serialize it to model. I am stuck with the complex object part, also as of now I am using a list to get the data, later that will be replaced by data base. Following is the code.
public IEnumerable<Document> Get(PaggingDetails request) //public async Task<IEnumerable<Note>> GetNotes() for Async (DB)
{
return _repository.GetAll(pagedetails.PageNumber, pagedetails.PageSize, pagedetails.PageFilter);
//return await db.Notes.ToListAsync<Note>(); for async
}
public string GetPage(int pagenumber,int pagesize,string pagefilter)
{
try
{
PaggingDetails PageDetails = new PaggingDetails();
PageDetails.PageFilter = pagefilter;
PageDetails.PageSize = pagesize;
PageDetails.PageNumber = pagenumber;
return new System.Net.WebClient().DownloadString
("http://.../api/Document/?pagedetails=" +
PageDetails);
//new HttpClient().GetStringAsync("http://localhost:18545/api/Emails"); for async
//also pass parameters
}
catch (Exception ex)
{
}
return "";
}
By deafult, you cannot use a class as the type of parameter of a GET Web API action. You need to use individual parameters of single types.
If you want to use a class as parameter nothing stops you to use a POST action, in which you can include the data without any problem.
However you can force a complex parameter of a GET action to be read from the URI by decorating the comples attribute with [FromUri].
You can read this document to better understand Web API parameter binding:
Parameter Binding in ASP.NET Web API
By default, Web API uses the following rules to bind parameters:
If the parameter is a “simple” type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string. (More about type converters later.)
For complex types, Web API tries to read the value from the message body, using a media-type formatter.
This is the standard way of working. If you use the [FromUri] attribute, the action selector won't be able to choose between different Get methods that receive different complex types. If you use a route with controller and action segments, you won't have that problem, becaus ethe actions selector will choose by action name, no matter what the aprameters are.
I don't like using the [FromUri] for this reason, and beacuse it's not the natural way to work with the GET action. But you can use it with the necessary precautions.
Enterprise Library Validation Application Block (VAB) integrates with ASP.NET and also with WCF.
Is there a way to integrate ValidationResults created in WCF with ASP.NET?
e.g. an ASP.NET web page invokes a WCF service. The WCF service validates the data using VAB and returns validation information via a FaultContract. The ASP.NET page can take the results and display some error messages. However, a common approach is to indicate which fields have errors (e.g. inline message or asterisk). It seems that most of these approaches will involve being able to correlate the validation result with a control or with a validator.
I don't think there is an out of the box solution but was also curious if anyone had done this and what their approach was.
Since there is no out of the box solution and there aren't any answers posted, I will share what I implemented. I'm not in love with the approach but it is working for me.
Overview
The basic approach is for the ASP.NET page to populate a mapping between properties on the DataContract objects to the ClientId of the control that is being validated. When a validation error occurs the ClientId is returned back from the service to the asp.net page as part of a FaultContract. Then the details from the FaultException are extracted; the ASP.NET page retrieves the ClientId of the control that caused the error and appropriate action can be taken (e.g. change control look and feel or set the text on a validator).
Details
All of the DataContract objects inherit from a base class that exposes a Dictionary. This dictionary is used to map object properties to ASP.NET controls. In the Dictionary, the key is the property name on the DataContract object and the value is the ClientId of the control. Before invoking a service, the client must attach the Dictionary to the DataContract object.
When a ValidationResult is created by Enterprise Library it contains a property called Target which is the object that was validated. ValidationResult also contains a property called key which is the name of the property from the target object that was validated. The ValidationResult key is also a key into the Dictionary that was set in the ASP.NET page before calling the service.
With the ValidationResult key, the ASP.NET supplied information (ClientId) can be extracted from the ValidationResult Target. The information is then added as the Tag of the ValidationResult. Unfortunately, Tag is a readonly property so it has to be set by creating a new ValidationResult and passing the tag to the constructor.
The collection of ValidationResults is then transformed to a pre-existing CustomValidationResults collection (which looks just like ValidationResult) that we needed to use. The CustomValidationResults are then added to a custom ValidationFault and a FaultException is thrown.
The ValidationFaults are then extracted from the FaultException in the ASP.NET page. The ValidationFault contains the ClientId of the control which is associated with the error so the page can choose to display the Messages as it sees fit.