-
-
Save kellabyte/2355599 to your computer and use it in GitHub Desktop.
/* | |
<?xml version='1.0' encoding='UTF-8'?> | |
<feed xmlns="http://www.w3.org/2005/Atom" | |
xmlns:as="http://atomserver.org/namespaces/1.0/" | |
xmlns:os="http://a9.com/-/spec/opensearchrss/1.1/"> | |
<os:totalResults>65801</os:totalResults> | |
<os:startIndex>0</os:startIndex> | |
<os:itemsPerPage>2</os:itemsPerPage> | |
<as:endIndex>153</as:endIndex> | |
<link href="/myserver/v1/widgets/acme?start-index=153&max-results=2" rel="next" /> | |
<link href="/myserver/v1/widgets/acme?start-index=0&max-results=2" rel="self" /> | |
<author> | |
<name>AtomServer APP Service</name> | |
</author> | |
<title type="text">acme entries</title> | |
<updated>2007-10-05T19:17:42.750Z</updated> | |
<id>tag:atomserver.org,2007:v1:acme</id> | |
<entry> | |
<id>/myserver/v1/widgets/acme/205390.en.xml</id> | |
<as:entryId>205390</as:entryId> | |
<title type="text"> Entry: acme 205390.en</title> | |
<author> | |
<name>AtomServer Atom Service</name> | |
</author> | |
<link href="/myserver/v1/widgets/acme/205390.en.xml" rel="self" /> | |
<link href="/myserver/v1/widgets/acme/205390.en.xml/2" rel="edit" /> | |
</entry> | |
</feed> | |
*/ | |
// Option 1 - AtomFormatter understands how to deal with it's own model. Feed, Entry, etc. | |
public class StoryController : ApiController | |
{ | |
public HttpResponseMessage Get(int id) | |
{ | |
Story story = GetMeAStory(id); | |
var response = new HttpResponseMessage(HttpStatusCode.OK); | |
Entry entry = ConvertToEntry(story); // Why do we need this? | |
response.Content = new ObjectContent<SyndicationItem>(entry, atomFormatter); | |
return response; | |
} | |
} | |
// I'm not convinced we need media type specific models and translate twice. Atom example: | |
// Story (our model) -> Entry (atom model) -> Atom Representation | |
// | |
// I think we can do better. | |
// Option 2 | |
var formatter = new AtomFormatter(); | |
formatter.MapModel<Story>() | |
.ToTitle(x => x.Topic) | |
.ToAuthor(x => x.Owner); | |
// Option 2b - Since Atom is specifically XML, why not use it. | |
var formatter = new AtomFormatter(); | |
formatter.MapModel<Story>() | |
.To("/feed/title", x => x.Topic) | |
.To("/feed/author/name", x => x.Owner); | |
// AtomFormatter.MapModel<T>() would return an AtomModelMap, so we still have SRP as the mapping and | |
// formatting are still independent. | |
public class StoryController : ApiController | |
{ | |
public HttpResponseMessage Get(int id) | |
{ | |
Story story = GetMeAStory(id); | |
var response = new HttpResponseMessage(HttpStatusCode.OK); | |
response.Content = this.Request.Represent(story); // The proper formatter is used based on conneg | |
return response; | |
} | |
} | |
// Option 2 and 2b don't require copying data for the purpose of mapping a translation like option 1 does. | |
// We've also eliminated a double translation that occurred in option 1. |
@DarkSmith feel free to fork the gist and create an alternative :)
I didn't like having an intermediate model just for the purpose of translation because that forces us into translating twice. I get to use multiple formatters for a given model and map to them without having to use a model in the middle. I don't believe copying data is required to do this representation.
Please fork the gist and show the alternative. Seeing the code will be easier to understand what you mean :)
Given that the available transitions/links are dependent of the resource state, I'm assuming the Story
object would be responsible to know it's available transitions/links.
The formatter then would have to know how to retrieve the links from the story object in the response message. Is that correct?
Why not simply use the view-model pattern with various view rendering strategies ?