WebAPI 2 return types that don't break the help documentation website - asp.net-web-api2

Is there a way to use the (apparently preferred) IHttpActionResult return type for my API methods without breaking the super handy help documentation? When I return
List<T>
from my method, I get very descriptive help documentation. When I return IHttpActionResult, I get useless help documentation. Why give us such a cool toy and then suggest that we use something that breaks the toy? Am I missing a great resource for how to use the documentation website together with the MS preferred style?

You should be able to append ResponseTypeAttribute to your action methods which specifies the expected return type when using HttpResponseMessage or IHttpActionResult. This should then be picked up by ApiExplorer when it generates the documentation.
From the website:
Use this to specify the entity type returned by an action when the declared return type is HttpResponseMessage or IHttpActionResult. The ResponseType will be read by ApiExplorer when generating ApiDescription.
If you are using another API to generate the documentation you should check if they support it or include it in the question and maybe someone here knows off hand.

Related

How to organize endpoints when using FeathersJS's seemingly restrictive api methods?

I'm trying to figure out if FeathersJS suits my needs. I have looked at several examples and use cases. FeathersJS uses a set of request methods : find, get, create, update, patch and delete. No other methods let alone custom methods can be implemented and used, as confirmed on this other SO post..
Let's imagine this application where users can save their app settings. Careless of following method conventions, I would create an endpoint describing the action that is performed by the user. In this case, we could have, for instance: /saveSettings. Knowing there won't be any setting-finding, -creation, -updating (only some -patching) or -deleting. I might also need a /getSettings route.
My question is: can every action be reduced down to these request methods? To me, these actions are strongly bound to a specific collection/model. Sometimes, we need to create actions that are not bound to a single collection and could potentially interact with more than one collection/model.
For this example, I'm guessing it would be translated in FeathersJS with a service named Setting which would hold two methods: get() and a patch().
If that is the correct approach, it looks to me as if this solution is more server-oriented than client-oriented in the sense that we have to know, client-side, what underlying collection is going to get changed or affected. It feels like we are losing some level of freedom by not having some kind of routing between endpoints and services (like we have in vanilla ExpressJS).
Here's another example: I have a game character that can skill-up. When the user decides to skill-up a particular skill, a request is sent to the server. This endpoint can look like POST: /skillUp What would it be in FeathersJS? by implementing SkillUpService#create?
I hope you get the issue I'm trying to highlight here. Do you have some ideas to share or recommendations on how to organize the API in this particular framework?
I'm not an expert of featherJs, but if you build your database and models with a good logic,
these methods are all you need :
for the settings example, saveSettings corresponds to setting.patch({options}) so to the route settings/:id?options (method PATCH) since the user already has some default settings (created whith the user). getSetting would correspond to setting.find(query)
To create the user AND the settings, I guess you have a method to call setting.create({defaultOptions}) when the user CREATE route is called. This would be the right way.
for the skillUp route, depends on the conception of your database, but I guess it would be something like a table that gives you the level/skills/character, so you need a service for this specific table and to call skillLevel.patch({character, level})
In addition to the correct answer that #gui3 has already given, it is probably worth pointing out that Feathers is intentionally restricting in order to help you create RESTful APIs which focus on resources (data) and a known set of methods you can execute on them.
Aside from the answer you linked, this is also explained in more detail in the FAQ and an introduction to REST API design and why Feathers does what it does can be found in this article: Design patterns for modern web APIs. These are best practises that helped scale the internet (specifically the HTTP protocol) to what it is today and can work really well for creating APIs. If you still want to use the routes you are suggesting (which a not RESTful) then Feathers is not the right tool for the job.
One strategy you may want to consider is using a request parameter in a POST body such as { "action": "type" } and use a switch statement to conditionally perform the desired action. An example of this strategy is discussed in this tutorial.

Change results URL in Alfresco AIkau faceted search page

I have some difficulties customizing the Aikau faceted search page on Alfresco, which may be more a matter of lack of my knowledge about dojo/AMD.
What I want to do is to replace the document details page URL by a download URL.
I extended the Search Results Widget to include my own custom module :
var searchResultWidget = widgetUtils.findObject(model.jsonModel, "id", "FCTSRCH_SEARCH_RESULT");
if(searchResultWidget) {
searchResultWidget.name = "mynamespace/search/CustomAlfSearchResult";
}
I understand search results URLs are rendered this way :
AlfSearchResult module => uses SearchResultPropertyLink module => mixins _SearchResultLinkMixin renderer => bring the "generateSearchLinkPayload" function => renders URLs depending on the result type
I want to override this "generateSearchLinkPayload" function but I can't figure out what is the best way to do that.
Thanks in advance for the help !
This answer assumes you're able to use the latest version of Aikau (at the time of writing this is 1.0.61). Older versions might require slightly different overriding...
In order to do this you're going to need to override the createDisplayNameRenderer function of AlfSearchResult in your CustomAlfSearchResult widget. This will allow you to create an extension of alfresco/search/SearchResultPropertyLink.
If you want to take advantage of the the download capabilities provided by the alfresco/services/DocumentService for downloading both documents and folders (as a zip) then you're going to want to change both the publishTopic and publishPayload of the SearchResultPropertyLink.
You should extend the getPublishTopic and generateSearchLinkPayload functions. For the getPublishTopic function you'll want to change the return value to be "ALF_SMART_DOWNLOAD" (there are constants available for these strings in the alfresco/core/topics module). This topic can be used to tell the DocumentService to take care of figuring out if the node is a folder or document and will make an XHR request for the full node metadata (in order to get the contentUrl attribute that is not included in the data returned by the Search API.
You should extend the generateSearchLinkPayload function so that for document or folder types the payload contains the attribute nodes that is a single array where the object is the search result object that you wish to download.
I would recommend that you call this.inherited first to get the default payload and only update it for documents and folders.
Hopefully that all makes sense - if not, add a comment and I'll try to provide further assistance!
This is the answer for 1.0.25.2 - unfortunately it's not quite so straightforward...
You still need to extend the alfresco/search/AlfSearchResult widget, however this time you need to extend the postCreate function (remembering to call this.inherited(arguments)). It's not possible to stop the original alfresco/search/SearchResultPropertyLink widget from being created... so it will be necessary to find it and destroy it.
The widget is not assigned to a variable, so it will be necessary to find it using dijit/registry. Use the byNode function from dijit/registry to find the widget assigned to this.nameNode and then call destroy on it (be sure to pass the argument true to preserve the DOM). However, you will then need to empty the DOM node so that you can start again...
Now you need to add in your extension to alfresco/search/SearchResultPropertyLink. Unfortunately, because the smart download capability is not available you'll need to do more work. The difference here is that you'll need to make an XHR request to retrieve the full node metadata in order to obtain the contentURL. It's possible to publish a request to the DocumentService(via the "ALF_RETRIEVE_SINGLE_DOCUMENT_REQUEST" topic). However, you need to be aware that having the XHR step will not allow you to then proceed with the download as is. Instead you'll need to use an iframe download solution, I'd suggest you take a look at the changes in the pull request we recently made to solve this problem and backport them into your own solution.

Do not encode parameters in RestSharp

I am using RestSharp to access a RubyOnRails API.
As you might know, RoR likes when the parameters names are in the form model_name[property]. RestSharp, on the other hand, does not like it.
Fiddler says I send this to the server :
user%5Bemail%5D=user%40email.com&user%5Bpassword%5D=test
It looks like R# encodes both the parameters and values when it sends the data (unlike Curl, which looks like it encodes selectively).
While that's fine most of the time I guess, in this particular case, it makes the API return a 401 because it doesn't understand the parameters.
Is it possible to ask R# to not encode the request's parameters ?
Thank you !
Edit
Ok, in the R# sources, I found the method RestClient.EncodeParameters, so it looks like the parameter's name is always encoded. I guess I will have to fork it :(
Since RestSharp version 106.4.0 you can just use ParameterType.QueryStringWithoutEncode in request.AddParameter() function:
request.AddParameter("user_id", #"45454545%6565%65", ParameterType.QueryStringWithoutEncode);
I know this has already been answered, but I wanted to add this answer since it worked for me. There is an (albeit hacky) solution to this. Build your own uri for parameters that should not be encoded.
var uri = string.Concat("/path/to/your/api", "?paramThatShouldNotBeEncoded=", DateTime.Now.Date.AddDays(1).ToString("O"));
var restRequest = new RestRequest(uri, Method.GET);
In the RestSharp sources I found out that the parameters are always encoded (both the name and the value), so I guess that I will have to fork it if I want to add an additional parameter.
See this PR from the project site:
https://github.com/restsharp/RestSharp/pull/1157
However, as far as I can tell, it's not yet in a release on NuGet.
Update: probably doesn't work in most cases from comments.
I found an interesting solution... Just decode the parameters you want to pass in and restsharp will encode back to what it should be. For example, I have an api key that uses %7 in it and RestSharper further encodes it. I decoded the api key and passed that into RestSharp and it seems to work!
This solution worked for me
request.AddQueryParameter("sendEndDate", "string:data,something-else", false);
This is the function in the metadata of RestSharp.IRestRequest:
IRestRequest AddQueryParameter(string name, string value, bool encode);

Stub for google calendar API when using rspec in ROR3

The following is the method I am trying to use for getting the API to make the calls to Google calendar. I am not sure what the stub should return. Should I capture the normal response and use it as is or is there a reference with minimum set of parameters?
api = client.discovered_api('calendar', 'v3')
result = client.execute!(:api_method => api.calendar_list.list)
I can see that Omniauth provides it's own mock support and I can see that Google provides Python mock libraries, but I'm not aware of any direct Google support for mocking from Ruby.
That said, given your example, you would need test doubles for client and api. It's not clear where client is coming from, but assuming that's established as a double somehow, you'd have at a minimum:
api = double('api')
client.should_receive(:discovered_api).and_return(api)
api.stub_chain(:calendar_list, :list)
client.should_receive(:execute!).and_return(... whatever result you want ...)
If in addition you want to confirm that your code is passing the right parameters to the Google API, then you'd need to augment the above with message expectations and, in the case of the api stub_chain, a return value which would then have to feed into the message expectations for the execute! call.
I'm still not sure that answers your question, but if not, I'll look forward to reading any additional comments.

Entity Framework: AttachAsModified failure / confusion :)

Ok... I tried google and didn't get many hits. I dont want to abuse So but this is one of the best places to ask and EF isn't well documented.
My fails because the GetOriginal() returns null in UpdateCmsProductCategory. I assume that means currentCmsProductCategory is not in the ChangeSet. Ok... how do I put it in the changeset?
Here is the sequence...
I pull a CmsProductCategory down over Wcf.
I make changes.
I call the Wcf update method...
public void UpdateProductCategory(CmsProductCategory category)
{
domainservice.UpdateCmsProductCategory(category);
}
Which calls the Domain servide method...
public virtual void UpdateCmsProductCategory(CmsProductCategory currentCmsProductCategory)
{
this.Context.AttachAsModified(currentCmsProductCategory,
this.ChangeSet.GetOriginal(currentCmsProductCategory));
}
And that should work - but no, it Exceptions on me when GetOriginal() fails. I feel like I am missing a step between when the code modifies it and I pass it to Wcf.
Any hints / pointers to good documentation?
Thanks!
Your problem is probably that you lose the "context".
When you make the call to update the "this.Context" is not the same as the one you read it from.
WCF has a concept of "per call" and "per session". The "per call" is default your are therefore getting a new instance of the domain service. You may be able to solve it using per session.
Have a look at this link: http://msdn.microsoft.com/en-us/magazine/cc163590.aspx
Also try writing a test to check that what you are doing works without transfering the data over wcf.