How do you decide how much data to push to the user in Single Page Applications? - asp.net-mvc

Say you have a Recipe Manager application that you're building with a Web Api project. Do you send the list of recipes along with their ingredient names in JSON? Or do you send the recipes, ingredient names, and ingredient details? What's the process in determining how big the initial payload should be for a SPA?

These are the determining factors in how much to send to the client in an initial page:
Data that will be displayed for that first page
Lookup list data for any drop downs on that page
Data that is required for and presentation rules (might not be displayed but is used)
On a recipe page that would show a list of recipes, I would get the recipes and some key factors to display (like recipe name, the dish, and other key info) that can be displayed in a list. Enough for the user to make a determination on what to pick. Then when the user dives into a recipe, then go get that 1 recipe's details.
The general rule is get what you user will almost certainly need up front. Then get other data as they request it.

The process by which you determine how much data to send solely depends on the experience you want to provide your users - however it's as simple as this. If my experience demands that I readily display all of the recipes with a brief description and then allow them to drill into the recipe to get more information, then I'm only going to send enough information to produce the display and navigate further into the entity.
If then after navigating into the recipe it requires that you display the ingredient names and measures then send down that and enough information to navigate further into any single ingredient.
And as you can see it just goes on and on.

It depends if your application is just a simple HTTP API backing your web page, or your goal is something more akin to Platform As A Service. One driver for the adoption of SPA is that it makes the browser another client, just like an iOS or Android app,or a 3rd party.
If you want to support multiple clients, then it's likely that you want to design your APIs around the resources that you are trying to expose, such that you can use the uniform interface of GET/POST/PUT etc. against that resource. This will means it is much more likely that you are not coding in an client specific style and your API will be usable by a wide range of clients.
A resource is anything you would want to have its own URN.
I would suggest that is likely that in this case you would want a Recipe Book resource which has links to individual Recipe resources, which probably contain all the information necessary for that Recipe. Ingredients would only be a separate resource if you had more depth on what an Ingredient contained and they had their own resource.
At Huddle we use a Documentation Driven Design approach. That is we write the documentation for our API up front so that we can understand how usable our API would be. You can measure API quality in WTFs. http://code.google.com/p/huddle-apis/
Now this logical division might not be optimal in terms of performance. Your dealing with a classic tradeoff (ultimately architecture is all about balancing design tradeoffs) here between usability of your API and the performance of your API. Usually, don't favour performance until you know that it is an issue, because you will pay a penalty in usability or maintainability for early optimization.

Another possibility is to implement the OData query support for WebAPI. http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api
That way, your clients can perform their own queries to return only the data they need.

Related

D2L Get enrollments

I'm working on a D2L add-on right now and trying to retrieve all the courses the current user is enrolled in. The only way I found so far is using the
GET /d2l/api/lp/(version)/enrollments/myenrollments/ call. This works perfectly for a small amount of courses and is extremely slow for more than approximately 50 courses. Is there any better way to retrieve all the enrollments?
Thanks in advance
For end-users, this call is indeed the one intended to address this need. Since a portion of the performance drop may come from having to process a series of data pages (requiring several calls), you can try several techniques to add a bit of performance here:
You can pre-filter the call based on org unit type: this likely requires you as the app developer to know the org unit type IDs for the org units of interest to your end users. For example, if your main use case here is "student wants to see all the course offerings she's enrolled in", then you can provide the appropriate org unit type ID for course offering org units to your API call. This becomes more difficult if your app must address several different back-end services, or you don't know the org unit type ID used by the back-end service for the relevant org unit types.
You can try using an HTTP library that can pool connections, and batch together the calls that fetch all the data pages you need to get the complete list of enrollments needed. This will provide you with some benefit to overhead on each call, but the performance benefit will likely only be marginal.
Currently, this API route does not allow the caller to request a particular data page size, and allowing that would improve the overall latency involved in this use case: for example, requesting a page size of 500 records could conceivably fetch back all the enrollments in a single call. I would judge page-size requesting to be a completely reasonable feature enhancement to request, and I would encourage you to request it on D2L's Product Idea Exchange; in fact, I'd be rather surprised if someone hasn't already done so.

Custom replacement strings from third party app

Is there any ability to populate a learning module's content using data passed from a third party application. For example:
Third party data:
userid = 12, username = Sally, user_q1_answer = Jim, user_q2_answer
= 101
Module Content setup:
[[username]], since you are in room [[user_q1_answer]], you should
contact [[user_q2_answer]] in the event of the fire alarm going off.
Module Content Delivered:
Sally, since you are in room 101, you should contact Jim in the event of the fire alarm going off.
Thanks for any help
Currently, no facility in the LMS exists to do this kind of dynamic substitution at render time. A number of other questions here have covered this ground. As of Spring 2013, this kind of functionality is on the development roadmap but there is not yet a committed release vehicle for it.
It might be possible to use a client-side browser extension to detect specially formatted strings in page content and make Valence Learning Framework API calls to find values it can replace those strings with. However, this technique would probably only practically be able to replace values that are known about the current user and their relationship to the LMS. Through URL and page content examination, it might also be possible to gather knowledge about the user's current browsing context (i.e. what course or course section they're looking at), but we never recommend screen-scraping because you can't depend on meaningful tokens or data appearing reliably going forward (where as you can depend on the Learning Framework APIs to be able to get you information about the current operating user).

How should a REST URL schema look like for a tree hierarchy?

Let's assume that I have stores, shelves in a store, and products on a shelf. So in order to get a list of products on a shelf in a store, I'd use the following request:
GET http://server/stores/123/shelves/456/products
From here, how would I get an individual product? Should I use:
GET http://server/products/789
Or:
GET http://server/stores/123/shelves/456/products/789
The first method is more concise, since once you get a list of products, you don't really care which store it belongs to if you just want to view the details for a particular product. However, the second method is more logical, since you're viewing the products for a specific shelf in a specific store.
Likewise, what about a PUT/DELETE operation?
DELETE http://server/stores/123/shelves/456/products/789
Or:
DELETE http://server/products/789
What would be the correct way of designing a schema for a tree hierarchy like this?
P.S. If I'm misunderstanding something about the REST architecture, please provide examples on how I can make this better. There's way too many people who love to say "REST is not CRUD" and "REST is not RPC", then provide absolutely no clarifications or examples of good RESTful design.
I've noted 2 approaches to RESTful URI design: hierarchical & filtered
I feel hierarchical is overly verbose, has the potential for redundant endpoints (not DRY) and disguises in what resource's state you're really interested (after all, REST = representational state transfer).
I favor Simple URIs
Simple is elegant. I'd choose a URI structure like
GET http://server/products/789
because I am interested in the state of the product resource.
If I wanted all products that belonged to a specific shelf at a specific store, then I would do
GET http://server/products?store=123&shelf=456
If I wanted to create a product at a specific store on a specific shelf then I'd post
{
product: {
store: 123,
shelf: 456,
name: "test product"
}
}
via
POST http://server/products
Ultimately, it's tomayto, tomahto
REST doesn't require one over the other. However, in my own experience, it is more efficient to consume a RESTful API that maps single entities to single endpoints (eg: RestKit object mappings on iOS) instead of having an entity map to many different endpoints based on what parameters are passed.
About REST
As far as REST, it is not a protocol and has no RFC. It is tightly related to the HTTP/1.1 RFC as a way to implement its CRUD actions, but many software engineers will posit that REST does not depend on HTTP. I disagree and consider such as conjecture, because the original dissertation by UCI's Roy Fielding (http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm) explains the deep rooted connection of REST and HTTP/1.1. You may also enjoy Roy's opinion on the topic: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven.
The principles defined by REST can be applied to other protocols, but REST was built for the internet and HTTP is the protocol for the world wide web.
REST vs RPC
RPC is all about making calls to remote functions and is verb-centric.
REST is all about using the CRUD convention to act on data depending on how the CRUD operation applies to a given data type and is noun-centric.
You can accomplish the same things with REST or RPC, but REST follows DRY principles because for every URI you can perform 4 actions whereas RPC requires an endpoint for each action.
PS
Much of this is my opinion and based on my experiences, but I hope it sheds some light on how you could most efficiently design a RESTful URI schema. As always, your specific goals and needs will affect your choices, but simplicity is always a good target for which to aim.
Creating a product should just be a POST to
http://server/product
Updating a product should just be a PUT to
http://server/product/$id
Getting a product should just be a GET to
http://server/product/$id
Deleting a product should just be a DELETE to
http://server/product/$id
You should use the http methods that are there for you to get more functionality out of a simpler uri structure. If creating a product requires a passing in a store and shelf as a requirement, then those should get passed in the body of your POST (or PUT if you're changing shelves).
When someone does a GET to http://server/product/$id, they will get back some kind of xml/json response, right? What does that look like? The incoming data for a create or update should be POSTed or PUT the same way in the body of the request. That is how you pass in the store and shelf, not via the uri. The uri should be as simple as possible and just point to the resource (product), using the http verbs to differentiate functionality.
If you want to be able to get the contents of shelf 23, you do a GET to
http://server/shelf/23
When you do, you get back a json / xml / custom media type document that has the shelf data and a collection of product elements with links back to their product uri.
If you want to be able to move product 23 from one shelf to another, you do a PUT to
http://server/product/23
In the body of the PUT you have the product in the representation of your choice, but with the updated shelf.
It's a weird mode of thinking at first, because you're not dealing with functionality across the entire system, but instead focusing on the resources (product, shelf, store) and using the http verbs to expose them to the universe.
Don't design a REST api based on an URL structure. Here is how I think you should go about designing a REST api.
Trying to define a REST interface without discussing what links will be contained in what resources is like discussing an RPC interface and ignoring parameters and return values.
Since products may be in several stores or several shelves (categories?), I'd have each product have a unique number regardless of its position in the hierarchy. Then use the flat product number. That makes the API more stable when some products are for instance moved in your store.
In short, don't add unneeded redundancy to your API. To get a shelve list a store ID is enough, for a product list a shelve ID is enough... etc.
it seems like you are trying to build many different use cases, but everything is getting built into one super service. It would be better to break it out.
http://server/product_info/123123 or http://server/product_info?product=123123
http://server/product_inventory?store=123&shelf=345
then you can also support:
http://server/product_inventory?store=123
then PUT and DELETE makes sense for changing inventory or adding a new product.

RESTful route for a list of members that are not in a collection

I'm trying to figure out what the best way to show a list of members (users) that aren't a collection (group).
/users
is my route for listing all of the users in the account
/group/:id/members
is my route for listing all of the users in the group
/users?not_in_group=:id
is my current option for showing a list of users NOT in the group. Is there a more RESTFul way of displaying this?
/group/:id/non_members
seems sort of odd…
Either query parameters or paths can be used to get at the representation you want. But I'd follow Pete's advice and make sure your API is hypertext-driven. Not doing so introduces coupling between client and server that REST was intended to prevent.
The best answer to your question might depend on your application. For example, if your system is small enough, it may suffice to only support a representation consisting of a list of users and their respective groups (the resource found at /users). Then let the client sort out what they want to do with the information. If your system has lots of groups and lots of users, each of which belongs to only a couple of groups, your available_users representation for any group is likely to be only slightly smaller than the entire list of users anyway.
Creative design of media types can go a long way to solving problems like this.
Spoke with my partner. He suggested:
/group/:id/available_members
Seems much more positive.
The main precept of REST is "hypertext as the engine of application state". The form of the URI is irrelevant, what matters is that it is navigable from the representation returned at the application's entry point.

Why would Google Search use client-side URL parameters?

Yesterday morning I noticed Google Search was using hash parameters:
http://www.google.com/#q=Client-side+URL+parameters
which seems to be the same as the more usual search (with search?q=Client-side+URL+parameters). (It seems they are no longer using it by default when doing a search using their form.)
Why would they do that?
More generally, I see hash parameters cropping up on a lot of web sites. Is it a good thing? Is it a hack? Is it a departure from REST principles? I'm wondering if I should use this technique in web applications, and when.
There's a discussion by the W3C of different use cases, but I don't see which one would apply to the example above. They also seem undecided about recommendations.
Google has many live experimental features that are turned on/off based on your preferences, location and other factors (probably random selection as well.) I'm pretty sure the one you mention is one of those as well.
What happens in the background when a hash is used instead of a query string parameter is that it queries the "real" URL (http://www.google.com/search?q=hello) using JavaScript, then it modifies the existing page with the content. This will appear much more responsive to the user since the page does not have to reload entirely. The reason for the hash is so that browser history and state is maintained. If you go to http://www.google.com/#q=hello you'll find that you actually get the search results for "hello" (even if your browser is really only requesting http://www.google.com/) With JavaScript turned off, it wouldn't work however, and you'd just get the Google front page.
Hashes are appearing more and more as dynamic web sites are becoming the norm. Hashes are maintained entirely on the client and therefore do not incur a server request when changed. This makes them excellent candidates for maintaining unique addresses to different states of the web application, while still being on the exact same page.
I have been using them myself more and more lately, and you can find one example here: http://blixt.org/js -- If you have a look at the "Hash" library on that page, you'll see my implementation of supporting hashes across browsers.
Here's a little guide for using hashes for storing state:
How?
Maintaining state in hashes implies that your application (I'll call it application since you generally only use hashes for state in more advanced web solutions) relies on JavaScript. Without JavaScript, the only function of hashes would be to tell the browser to find content somewhere on the page.
Once you have implemented some JavaScript to detect changes to the hash, the next step would be to parse the hash into meaningful data (just as you would with query string parameters.)
Why?
Once you've got the state in the hash, it can be modified by your code (or your user) to represent the current state in your application. There are many reasons for why you would want to do this.
One common case is when only a small part of a page changes based on a variable, and it would be inefficient to reload the entire page to reflect that change (Example: You've got a box with tabs. The active tab can be identified in the hash.)
Other cases are when you load content dynamically in JavaScript, and you want to tell the client what content to load (Example: http://beta.multifarce.com/#?state=7001, will take you to a specific point in the text adventure.)
When?
If you had a look at my "JavaScript realm" you'll see a border-line overkill case. I did it simply because I wanted to cram as much JavaScript dynamics into that page as possible. In a normal project I would be conservative about when to do this, and only do it when you will see positive changes in one or more of the following areas:
User interactivity
Usually the user won't see much difference, but the URLs can be confusing
Remember loading indicators! Loading content dynamically can be frustrating to the user if it takes time.
Responsiveness (time from one state to another)
Performance (bandwidth, server CPU)
No JavaScript?
Here comes a big deterrent. While you can safely rely on 99% of your users to have a browser capable of using your page with hashes for state, there are still many cases where you simply can't rely on this. Search engine crawlers, for example. While Google is constantly working to make their crawler work with the latest web technologies (did you know that they index Flash applications?), it still isn't a person and can't make sense of some things.
Basically, you're on a crossroads between compatability and user experience.
But you can always build a road inbetween, which of course requires more work. In less metaphorical terms: Implement both solutions so that there is a server-side URL for every client-side URL that outputs relevant content. For compatible clients it would redirect them to the hash URL. This way, Google can index "hard" URLs and when users click them, they get the dynamic state stuff!
Recently google also stopped serving direct links in search results offering instead redirects.
I believe both have to do with gathering usage statistics, what searches were performed by the same user, in what sequence, what of the search results the user has followed etc.
P.S. Now, that's interesting, direct links are back. I absolutely remember seeing there only redirects in the last couple of weeks. They are definitely experimenting with something.

Resources