How to create swagger documentation for dynamic request/response - asp.net

We have an API application which is driven dynamically based on SQL defined metadata. This API app is a reporting application and the report is driven by what kind of request is passed into the API. This means if JSON request is passed like this -
ex 1
{
"Field1": "Value1"
"GroupBy": ["GroupByValue1", "GroupByValue2"]
}
Then it gives below resultset -
{
"GroupByValue1": "SomeValue1"
"GroupByValue2": "SomeValue2"
... other fields based on GroupBy1 and GroupBy2
}
ex 2
{
"Field1": "Value1"
"GroupBy": ["GroupByValue3"]
}
Then it gives below resultset -
{
"GroupByValue3": "SomeValue1"
... other fields based on GroupBy3
}
So the mapping of request v/s fields for that request is defined in the SQL database.
And we need to generate swagger documentation for this kind of dynamic requests. So my question is since we use swashbuckle for swagger documentation, we have to give it specific resultset based on the request being passed. Now we have APIs to give us those request/resultset relationship, but is there a way to generate documentation completely dynamically based on this API (using c# code or typescript) that gives us request/resultset relationship.

You can create dynamic Swagger documentation using IDocumentFilter.
We also use dynamic SQL metadata at this example.

Related

How to have a Symfony API GET call return an embedded json object instead of an IRI

I have been working on a Symfony API with Api Platform and have autogenerated all the endpoints which works fine. Except for one thing, when GETting a entity with a child entity, the child entity is not given in json but in an IRI format so this means that we get "/api/locations/1" instead of a JSON Object. I have been trying for hours but can't figure out how to change this. We are using annotations for the routes and the database relations.
You can use some nice tool like POSTMAN.
Then you can see the JSON response pretty printed.
You have to use the same, common normalization group for all embeded entities as desribed in docs.
The same is required for GraphQL when you need embeded fields other than id - asking for more than available results "Internal server error" "Cannot return null for non-nullable field XXX.YYY" - using GraphiQL helps with debugging more than POSTMAN (great tool) - when GraphQL will be working as expected, REST should be OK, too.
Unfortunatelly standard admin-on-rest doesn't like 'already fetched' values, expecting strings/IRIs only, not objects.
You can choose the response content type:

How to send Json to Azure Appinsights with c# library

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.

BreezeJS modified route not working

My application has two databases with exactly the same schema. Basically, I need to change the DbContext based on what data I'm accessing. Two countries are in one Db and 4 countries in the other. I want the client to decide which context is being used. I tried changing my BreezeWebApiConfig file so that the route looks like this:
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "BreezeApi",
routeTemplate: "breeze/{dbName}/{controller}/{action}/{id}",
defaults: new {id=RouteParameter.Optional,dbName="db1"}
);
I added the string to the controller actions:
[HttpGet]
public string Metadata(string dbName="")
{
return _contextProvider.Metadata();
}
And changed the entityManager service Name.
Now when the client spins up, it accesses the corrent metadata action and I get a message:
Error: Metadata query failed for: /breeze/clienthistory/kenya/Metadata. Unable to either parse or import metadata: Type .... already exists in this MetadataStore
When I go to the metadata url from the browser, I get the correct metadata (exactly the same as when I remove the {dbName} segment from the route). If I remove the {dbName} segment from the route I get no error and everything works fine
(I have not started implementing the multiple contexts yet -- I am just trying to make the additional segment work).
Thanks.
I think the problem is that your Breeze client is issuing two separate requests for the same metadata, once under each of the two "serviceNames". Breeze tries to blend them both into the same EntityManager.metadataStore ... and can't because that would mean duplication of EntityType names.
One approach that should work is to begin your application by fetching the metadata immediately upon app start and then adding all the associated "DataServiceNames" to the MetadataStore.
Try something along these lines (pseudo-code):
var manager;
var store = new breeze.MetadataStore();
return store.fetchMetadata(serviceName1)
.then(gotMetadata)
.catch(handleFail);
function gotMetadata() {
// register the existing metadata with each of the other service names
store.addDataService(new breeze.DataService(serviceName2));
... more services as needed ...
manager = new breeze.EntityManager({
dataService: store.getDataService(serviceName1), // service to start
metadataStore: store
});
return true; // return something
}
Alternative
Other approaches to consider don't involve 'db' placeholder in the base URL nor any toying with the Web API routes. Let's assume you stay vanilla in that respect with your basic service name
var serviceName = '/breeze/clienthistory/';
..
For example, you could add an optional parameter to your routes (let's call it db) as needed via a withParameters clause.
Here is a query:
return new breeze.EntityQuery.from('Clients')
.where(...)
.withParameters({db: database1}); // database1 == 'kenya'
.using(manager).execute()
.then(success).catch(failed);
which produces a URL like:
/breeze/clienthistory/Clients/?$filter=...&db=kenya
It makes an implicit first-time-only metadata request that resolves to:
/breeze/clienthistory/Metadata
Your server-side Web API query methods can expect db as an optional parameter:
[HttpGet]
public string Metadata(string db="")
{
... do what is right ...
}
Saves?
I assume that you also want to identify the target database when you save. There are lots of ways you can include that in the save request
in a custom HTTP header via a custom AJAX adapter (you could do this for queries too)
in a query string parameter or hash segment on the saveChanges POST request URL (again via a custom AJAX adapter).
in the tag property of the saveOptions object (easily accessed by the server implementation of SaveChanges)
in the resourceName property of the saveOptions object (see "named save")
You'll want to explore this variety of options on your own to find the best choice for you.

Web API and queries with foreign keys

I'm playing around with Web API, and I'm struggling a bit with creating queries to pull back data based on a filter. The classic example would be pulling back a list of items based on a foreign key.
Let's say I have the following entity:
Movie
======
id
directorId
categoryId
It would not be uncommon for me to build a DAO with the following methods:
MovieRepo.GetByDirector(int directoryId);
MovieRepo.GetByCategory(int category);
Recently, I have been using Linq and the Entity Framework to build retrieval methods that can be used by multiple calling clients, but whose returned list can filtered based on whatever criteria is passed to a filter
public IEnumerable<Movie> Get(MovieFilter filter){
IQueryable<Movie> query = _context.tblMovie;
if(!String.IsNullOrEmpty(filter.directorId))
query.Where(m => m.directoryId == filter.directorId);
if(!String.IsNullOrEmpty(filter.categoryId))
query.Where(m => m.categoryId == filter.categoryId);
return query.ToList();
}
The boilerplate Web API controller actions are:
IEnumerable<Movie> Get();
Movie Get(int id)
If I wanted to filter my query by directory or category with Web API, how exactly would I do it in a RESTful way? Given the way routing gets resolved, the following would be an ambiguous call:
IEnumerable<Movie> GetByCategory(int categoryId);
I haven't see much guidance on this, can someone provide some for me?
Regards,
Chris
One of the ways is to use OData protocol http://www.odata.org/docs/
There is also a library supporting OData filtering http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api, supporting querying over the IQueryable interface
It could be seen as a bit more complex, but you gain a lot. Parts of the OData standard :
$filter - Filters the results, based on a Boolean condition.
$select - which columns/properties should be selected
$inlinecount - Tells the server to include the total count of matching entities in the response. (Useful for server-side paging.)
$orderby - Sorts the results.
$skip - Skips the first n results.
$top - Returns only the first n the results.
Honestly, we are using the OData ... while not using the IQueryable and MS libraries. We just created own parser, supporting only limited stuff. But there is OData standard in place

i want to pass the array of request to web service at once...it it possible?

I am working with some web services and I want to pass the array of request to the web service at once and the output should be returned once for the whole array of request.
For example, let's say I am requesting the city details by city name. I want to build the array of city names and pass it to the web service and get all the details in one response.
I am using ASP.NET
<AirAvailability_6_2>
<AirAvailMods>
<GenAvail>
<NumSeats>1</NumSeats>
<Class><![CDATA[ ]]></Class>
<StartDt>20091214</StartDt>
<StartPt>LON</StartPt>
<EndPt>AAH</EndPt>
<StartTm>1200</StartTm>
<TmWndInd>D</TmWndInd>
<StartTmWnd>0800</StartTmWnd>
<EndTmWnd>1400</EndTmWnd>
<FltTypeInd></FltTypeInd>
<StartPtInd></StartPtInd>
<EndPtInd></EndPtInd>
<IgnoreTSPref></IgnoreTSPref>
</GenAvail>
</AirAvailMods></AirAvailability_6_2>
<AirAvailability_6_2>
<AirAvailMods>
<GenAvail>
<NumSeats>1</NumSeats>
<Class><![CDATA[ ]]></Class>
<StartDt>20091214</StartDt>
<StartPt>LON</StartPt>
<EndPt>AAH</EndPt>
<StartTm>1200</StartTm>
<TmWndInd>D</TmWndInd>
<StartTmWnd>0800</StartTmWnd>
<EndTmWnd>1400</EndTmWnd>
<FltTypeInd></FltTypeInd>
<StartPtInd></StartPtInd>
<EndPtInd></EndPtInd>
<IgnoreTSPref></IgnoreTSPref>
</GenAvail>
</AirAvailMods></AirAvailability_6_2>
declare the web method to accept an array. Declare the web method to return an array.
[WebMethod]
public CityDetails[] GetCityDetails(string[] names)
{
/// blah blah
}
If you are talking about an existing web service with an API you have no control over - you will have to stick with what this service offers. In other words if the existing API does not provide for batching requests you will have to feed the service one request at a time.
If, on the other hand, you are building the service yourself - noting prevents you from spelling out the API so that it can take an array of requests.
If you have control over both sides of the connection and they're both managed code, then you could create the custom object (serializable) and setup the web method to take in that object as its parameter.
I did this recently using JSON (giving me access from the client side of a web page). You set up the web service to accept a string parameter, and use a JSON Deserializer (DataContractJsonSerializer is one choice) to convert the request to your custom object.
This gives you the ability to pass in the specifics on multiple requests, and pass the results back out the same way (a custom collection object).
Let me know how this works out for you.'
Gabriel

Resources