What is the best way to name REST resources when returning same resource but using different DTO? - rest

I'm curious what is the best way of returning the same resource but using different DTOs.
For example, I have a user class:
public class User {
private String name;
private String surname;
private String age;
}
The list of users is available under url:
/users
Some other view needs list of users but without age, so, I would like to return list of UserDTO.
public class UserDTO {
private String name;
private String surname;
}
What is the proper way of defining url?
/userDtos - this is bad, because I can have more than one DTOs for representing users,
/users/dto - this is also bad
/users?name=true,surname=true - this one is also bad, it indicates that we are filtering the result, but we are not; we're just filtering fields.
For sure someone already had this problem before, but I couldn't find anything on the Internet.

A similar concept is called partial response which provide an option to let client to specify which fields to include in the response using the query parameters like:
:
/user?fields=name,surename
Basically you define a syntax for you own query language to represent a selection of fields. Here and Google Cloud API are some examples.
By taking this concept to a more coarse-grained level , you can use query parameter "view" to define different predefined combination of fields such as:
/users //default view if no "view" query parameter is specified
/users?view=admin //maybe this view will not show age field
/users?view=hr //maybe this view only show the fields that are accessible to HR

Related

Best practice for filtering results from a RESTful API call?

I'm defining a RESTful API for a TV broadcaster, specifically what the path should look like when asking for a subset of data. For example if I wanted to get the whole content for a particular channel, language on that channel between a specific date, how would I filter by date? The path below seems too long:
endpoint.com/content/channels/{channel_name}/language/french/from/20160701/to/20160801
An alternative I saw is to 'treat the search as a resource' and POST the date range filters to it in the request body, as mentioned here on SO: (How to design RESTful search/filtering?)
Any thoughts?
I will suggest you use #QueryParam annotation to filter your resources by getting it from URI.
To filter the resource you can use an URI like
/channel_name?language=french&from=20160701&to=20160801
Using JAX-RS you then can access the these values:
#GET
#Path("/channel_name")
List<Content> getContent(#QueryParam("language")String lang,
#QueryParam("from")Long from,
#QueryParam("to")Long to) {
// your logic
}
Of course you need to take care of exceptions and the repsonse including status codes in this case.
I also work for a TV Broadcaster and the approach we have taken is to post the search criteria through a resource. Much easier to handle and doesn't create an endless path.
Interface :
#POST
#Path("/lookup")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
List<Content> getContent(CriteriaSearch cr);
Implementation :
#Override
#Public
public List<ContentInfo> getContent(CriteriaSearch searchCriteria) {
List<ContentInfo> contentInfos = contentManager.lookupContent(searchCriteria);
...

Reference for Constants.ClaimTypes

I've got IdentityServer3 running as a standalone identity server.
I have a separate MVC client that uses Cookies and OpenIdConnect for authentication. I'm trying to set up claims transformations amongst other things, and would like to reference the different claims types like so:
var givenName = id.FindFirst(Constants.ClaimTypes.GivenName);
var familyName = id.FindFirst(Constants.ClaimTypes.FamilyName);
var sub = id.FindFirst(Constants.ClaimTypes.Subject);
var roles = id.FindAll(Constants.ClaimTypes.Role);
On the IdentityServer3, I reference these using Thinktecture.IdentityServer.Core.Constants however on my MVC client I don't think I should need to reference Thinktecture.IdentityServer3 just for these string constants? Is there a client library that is recommended to be used in this case? I've tried Thinktecture.IdentityModel and some .NET references but none seem to replicate the ClaimTypes in Thinktecture.IdentityServer.Core.Constants. The best I've found is System.Security.Claims.ClaimTypes but that seems to have several missing e.g. FamilyName.
The first placed I looked was Thinktecture.IdentityModel but was surprised these aren't there.
So what's the magic reference? Or is it appropriate to load Thinktecture.IdentityServer3 just for these strings?
Thanks
EDIT: So I've found Thinktecture.IdentityModel.Client which contains a JwtClaimTypes that seems to mirror ClaimTypes. Why is this named with a Jwt prefix though?
The IdentityServer ClaimType constants are just a map of the OpenID Connect standard claims.
You'd be best off making your own class for these constants, as you said there's no point pulling in the full Identity Server 3 package and I don't think they are available in any other packages...
Do note that the claims come across via JSON in the JWT as snake case. For example FamilyName will be family_name.
You can install the Microsoft.AspNetCore.Authentication.JwtBearer package. It includes the JwtRegisteredClaimNames struct which you can use like:
using static Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames;
⋮
var userId = User.FindFirstValue(Sub);
Agree with Scott Brady, the best way to go about this is to create your constants class. We have created a shared library for this purpose, which contains claim type constants and have used them both in the server and the client projects.
NB: Apart from 'id_token' and 'sub' claim types, you can use your custom claim types in the implementation of 'IUserService'. This gives better clarity to claim type names also as you can use specific names based on your implementation.
Use IdentityModel
I've seen people use bare strings like "sub", but why, when the constants exist?
namespace IdentityModel
{
/// <summary>Commonly used claim types</summary>
public static class JwtClaimTypes
{
/// <summary>Unique Identifier for the End-User at the Issuer.</summary>
public const string Subject = "sub";
/// <summary>End-User's full name in displayable form including all name parts, possibly including titles and suffixes, ordered according to the End-User's locale and preferences.</summary>
public const string Name = "name";
/// <summary>Given name(s) or first name(s) of the End-User. Note that in some cultures, people can have multiple given names; all can be present, with the names being separated by space characters.</summary>
public const string GivenName = "given_name";
/// <summary>Surname(s) or last name(s) of the End-User. Note that in some cultures, people can have multiple family names or no family name; all can be present, with the names being separated by space characters.</summary>
public const string FamilyName = "family_name";

ServiceStack Routing with ravendb ids

I've an entity with an ID of
public string ID {get;set;}
activities/1
(which comes from RavenDB).
I'm registering the following routes in my ServiceStack AppHost
Routes
.Add<Activity>("/activities")
.Add<Activity("/activities/{id}");
I'm using a backbone app to POST and PUT to my REST Service.
What happens out-of-the-box:
id property is serialized into the json as "activities/1"
id property is encoded into route as "activities%2F1"
ServiceStack gives precedence to the URL based id property, so my string gets the encoded value which is no use to RavenDb directly.
The options I'm aware of:
Change backbone to post to "/activities" and let the JSON Serialiser kick in
Change RavenDb ID generation to use hyphens rather than slashes
Make my Id property parse for the encoded %2F on set and convert to a slash
Both have disadvantages in that I either lose RESTfulness in my API, which is undesirable, or I don't follow RavenDb conventions, which are usually sensible out-of-the-fox. Also, I've a personal preference for having slashes.
So I'm wondering if there are any other options in servicestack that I could use to sort this issue that involve less compromise? Either Serialiser customisation or wildcard routing are in my head....
I have the same problem with ASP.Net WebAPI, so I don't think this is so much a ServiceStack issue, but just a general concern with dealing with Raven style id's on a REST URL.
For example, let's say I query GET: /api/users and return a result like:
[{
Id:"users/1",
Name:"John"
},
{
Id:"users/2",
Name:"Mary"
}]
Now I want to get a specific user. If I follow pure REST approach, the Id would be gathered from this document, and then I would pass it in the id part of the url. The problem here is that this ends up looking like GET: /api/users/users/1 which is not just confusing, but the slash gets in the way of how WebAPI (and ServiceStack) route url parameters to action methods.
The compromise I made was to treat the id as an integer from the URL's perspective only. So the client calls GET: /api/users/1, and I define my method as public User Get(int id).
The cool part is that Raven's session.Load(id) has overloads that take either the full string form, or the integer form, so you don't have to translate most of the time.
If you DO find yourself needing to translate the id, you can use this extension method:
public static string GetStringIdFor<T>(this IDocumentSession session, int id)
{
var c = session.Advanced.DocumentStore.Conventions;
return c.FindFullDocumentKeyFromNonStringIdentifier(id, typeof (T), false);
}
Calling it is simple as session.GetStringIdFor<User>(id). I usually only have to translate manually if I'm doing something with the id other than immediately loading a document.
I understand that by translating the ids like this, that I'm breaking some REST purist conventions, but I think this is reasonable given the circumstances. I'd be interested in any alternative approaches anyone comes up with.
I had this problem when trying out Durandal JS with RavenDB.
My workaround was to change the URL very slightly to get it to work. So in your example:
GET /api/users/users/1
Became
GET /api/users/?id=users/1
From jQuery, this becomes:
var vm = {};
vm.users = [];
$.get("/api/users/?" + $.param( { id: "users/1" })
.done(function(data) {
vm.users = data;
});

Why won't my WCF Data Service accept my querystring?

I'm using jqGrid to display some data to the user. One of the features needed is for users to be able to search the grid. I'm using a WCF Data Service to get this data and return it.
When I first started jqGrid development I just needed pagination (no searching required) and was successfully able to use the following method:
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public String GetStuff(int? page, int? rows)
{
// pagination going on in here
}
Then I needed the search so I added a param of type string like so:
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public String GetStuff(int? page, int? rows, string search)
{
// more stuff going on in here
}
and then I get a 400 Bad Request error. I assume its because of the search param, I just don't understand why int works (and even bool worked) but string doesn't. Does it have anything to do with the fact that WCF Data Services are RESTful?
I of course double-checked the query string that jqGrid sends (via ajax) and it matches the param name. There are some extra query string params that jqGrid sends that are not used (ignoring them worked fine with my original pagination code)
String literals in the query URL must be quoted with single quotes. So the above service operation would be called like this:
/GetStuff?page=1&rows=10&search='John'
Does your query string look like that?

Guidance on a better way to retain filtering options when using ASP.NET MVC 2

I have an ASP.NET MVC 2 application which in part allows a user to filter data and view that data in a JQGrid.
Currently this consists of a controller which initialises my filter model and configures how I wish my grid to be displayed. This information is used by a view and a partial view to display the filter and the grid shell. I use an editor template to display my filter. The JQGrid makes use of a JsonResult controller action (GET) to retrieve the results of the filter (with the addition of the paging offered by the grid - only a single page of data is returned by the GET request. The Uri used by the grid to request data contains the filter model as a RouteValue - and currently contains a string representation of the current state of the filter. A custom IModelBinder is used to convert this representation back into an instance of the filter model class.
The user can change the filter and press a submit button to get different results - this is then picked up by an (HttpPost) ViewResult action which takes the filter model - reconstituted by a further model binder and causes the grid shell to be updated.
So I have:
FilterModel
Represents the user's desired filtering characteristics
FilterModelEditorTemplateSubmissionBinder : DefaultModelBinder - used to convert the request information supplied from a user changing their filtering characteristics into the appropriate FilterModel instance.
FilterModelStringRepresentationBinder : IModelBinder - used to convert the encoded filter from the JQGrid GET request for data so the correct request is made of the service which is ultimately performing the query and returning the relevant data.
ViewResult Index() - constructs a default filter, configures the grid specification and returns the view to render the filter's editor template, and the grid shell.
[HttpPost]ViewResult Filter(FilterModel filter) - takes the new filter characteristics and returns the same view as Index(). Uses FilterModelEditorTemplateSubmissionBinder to bind the filter model.
JsonResult GetData(FilterModel filter, string sidx, string sord, int page, int rows) - called from the JQGrid in order to retrieve the data. Uses FilterModelStringRepresentationBinder to bind the filter model.
As a complication, my filter model contains a option to select a single value from a collection of items. This collection is retrieved from a service request and I don't want to keep querying for this data everytime I show the filter, currently I get it if the property is null, and then include the options hidden in the editor template and encoding in the string representation. These options are then reconstituted by the relevant model binder.
Although this approach works I can't help but feel that I am having to basically reinvent viewstate in order to maintain my filter and the included options. As I am new to ASP.NET MVC but am very happy with classic ASP and ASP.NET Web Forms I thought I'd throw this out there for comment and guidance as to find a way which more closely fits with the MVC pattern.
It seems to me that the best way in to divide some actions which provide pure data for the jqGrid from other controller action. Such jqGrid-oriented actions can have prototype like:
JsonResult GetData(string filter, string sidx, string sord, int page, int rows)
I personally prefer to implement this part as WCF service and to have this WCF service as a part of the same ASP.NET site. In general it's much more the matter of taste and depends on your other project requirements.
This part of you ASP.NET site could implement users authentication which you need and can be tested with unit tests exactly like other actions of your controllers.
The views of the ASP.NET MVC site can have empty data for jqGrids, and have only correct URLs and probably generate the HTML code depends on the users permission in the site. Every page will fill the data of jqGrids with respect of the corresponds requests to the server (request to the corresponding GetData action).
You can use HTTP GET for the data for the best data caching. The caching of data is the subject of a separate discussion. If you do this, you should use prmNames: { nd:null } in the definition of jqGrid to remove unique nd parameter with the timestamp added per default to every GET request. To have full control of the data caching on the server side you can for example add in HTTP headers of the server responses both "Cache-Control" set to "max-age=0" and "ETag" header with the value calculated based of the data returned in the response. You should test whether the request from the client has "If-None-Match" HTTP header with the value of "ETag" coresponds the data cached on the client. Then you should verify whether the current data on the server (in the database) are changed and, if there are not changed, generate a response with an empty body (set SuppressEntityBody to true) and return "304 Not Modified" status code (HttpStatusCode.NotModified) instead of default "200 OK". A more detail explanation is much more longer.
If you don't want optimize you site for caching of HTTP GET data for jqGrids you can either use HTTP POST or don't use prmNames: { nd:null } parameter.
The code inside of JsonResult GetData(string filter, string sidx, string sord, int page, int rows) is not very short of cause. You should deserialise JSON data from the filter string and then construct the request to the data model depends on the method of the data access which you use (LINQ to SQL, Entity Model or SqlCommand with SqlDataReader). Because you have this part already implemented it has no sense to discuss this part.
Probably the main part of my suggestion is the usage of clear separation of controller actions which provide the data for all your jqGrids and the usage of MVC views with empty data (having only <table id="list"></table><div id="pager"></div>). You should also has no doubt with having a relative long code for analyzing of filters which come from the Advance Searching feature of the jqGrid and generating or the corresponding requests to your data model. Just implement it one time. In my implementation the code in also relatively complex, but it is already written one time, it works and it can be used for all new jqGrids.
I made this once, very simple.
pseudo code:
Controller
[HttpGet]
public ActionResult getList(int? id){
return PartialView("Index", new ListViewModel(id??0))
}
ViewModel
public class ListViewModel{
//ObjectAmountPerPage is the amount of object you want per page, you can modify this as //parameter so the user
//can choose the amount
public int ObjectAmountPerPage = 20 //you can make this into a variable of any sort, db/configfile/parameter
public List<YourObjectName> ObjectList;
public int CurrentPage;
public ListViewModel(id){
Currentpage = id;
using (MyDataContext db = new MyDataContext()){
ObjectList = db.YourObjectName.OrderBy(object=>object.somefield).getListFromStartIndexToEndIndex(id*ObjectAmountPerPage ,(id*ObjectAmountPerPage) +20).toList();
}
}
}
Now Create A RenderPartial:
PartialView
<#page inherit="IEnumerable<ListViewMode>">
<%foreach(YourObjectName object in Model.ObjectList){%>
Create a table with your fields
<%}%>
And create a view that implements your Jquery, other components+your partialView
View
<javascript>
$(function(){
$("#nextpage").click(function(){
(/controller/getlist/$("#nextpage").val(),function(data){$("#yourlist").html = data});
});
});
</javascript>
<div id="yourlist">
<%=Html.RenderPartial("YourPartialView", new ListViewModel())%>
</div>
<something id="nextpage" value"<%=Model.CurentPage+1%>">next page</something>
I hope this helps, this is according to the MVC- mv-mv-c principle ;)
Model-View -(modelview) - control