// GET: api/Books/5 /// <summary> /// Information for one book /// </summary> /// <param name="id">Book identifier (int)</param> /// <returns>Book object</returns> public IHttpActionResult Get(int? id) { // Fetch the object var fetchedObject = w.Books.GetById(id.GetValueOrDefault()); // Continue? if (fetchedObject == null) { return NotFound(); } BookLinked result = new BookLinked (Mapper.Map<BookWithLink>(fetchedObject)); // Get the request URI path string self = Request.RequestUri.AbsolutePath; // Add a link relation to indicate a command that can be performed result.Links.Add(new Link() { Rel = "edit", Href = self + "/setphoto", ContentType = "image/*", Method = "PUT" }); return Ok(result); }
// POST: api/Books /// <summary> /// Add a new book /// </summary> /// <param name="newItem">New book object (the template has the object schema)</param> /// <returns>New book object</returns> public IHttpActionResult Post([FromBody]BookAdd newItem) { // Ensure that the URI is clean (and does not have an id parameter) if (Request.GetRouteData().Values["id"] != null) { return BadRequest("Invalid request URI"); } // Ensure that a "newItem" is in the entity body if (newItem == null) { return BadRequest("Must send an entity body with the request"); } // Ensure that we can use the incoming data if (!ModelState.IsValid) { return BadRequest(ModelState); } // Attempt to add the new object var addedItem = w.Books.Add(newItem); // Continue? if (addedItem == null) { return BadRequest("Cannot add the object"); } // HTTP 201 with the new object in the entity body // Notice how to create the URI for the Location header var uri = Url.Link("DefaultApi", new { id = addedItem.Id }); // Use the factory constructor for the "add new" use case BookLinked result = new BookLinked (Mapper.Map<BookWithLink>(addedItem), addedItem.Id); return Created(uri, result); }
// PUT: api/Books/5 public IHttpActionResult Put(int id, [FromBody] BookEdit editedItem) { // Ensure that an "editedItem" is in the entity body if (editedItem == null) { return(BadRequest("Must send an entity body with the request")); } // Ensure that the id value in the URI matches the id value in the entity body if (id != editedItem.Id) { return(BadRequest("Invalid data in the entity body")); } // Ensure that we can use the incoming data if (ModelState.IsValid) { // Attempt to update the item var changedItem = m.Books.EditExisting(editedItem); // Notice the ApiController convenience methods if (changedItem == null) { // HTTP 400 return(BadRequest("Cannot edit the object")); } else { // From RFC 7231... // http://tools.ietf.org/html/rfc7231#section-4.3.4 // "the origin server MUST send either a 200 (OK) // or a 204 (No Content) response to indicate // successful completion of the request" // So, we have a choice... // To send HTTP 204... // return StatusCode(HttpStatusCode.NoContent); // To send HTTP 200... // Include the changed item in the entity body, as seen below // Create an object to be returned BookLinked book = new BookLinked(); // Set its item property book.Item = Mapper.Map <BookWithLink>(changedItem); // Get the request URI path Uri uri = new Uri(Url.Link("DefaultApi", new { id = book.Item.Id })); // Add a link relation for 'self' book.Links.Add(new Link() { Rel = "self", Href = uri.AbsolutePath }); // Add a link relation for the parent 'collection' List <string> u = Request.RequestUri.Segments.ToList(); book.Links.Add(new Link() { Rel = "collection", Href = u[0] + u[1] + u[2] }); // Add a link relation for 'self' in the item book.Item.Link = new Link() { Rel = "self", Href = uri.AbsolutePath }; // Return the response return(Ok <BookLinked>(book)); } } else { return(BadRequest(ModelState)); } }
// GET: api/Books/5 public HttpResponseMessage Get(int id) { var fetchedObject = m.Books.GetById(id); if (fetchedObject == null) { return(Request.CreateResponse(HttpStatusCode.NotFound)); } else { // Create an object to be returned BookLinked book = new BookLinked(); // Set its item property book.Item = Mapper.Map <BookWithLink>(fetchedObject); // Get the request URI path string self = Request.RequestUri.AbsolutePath; // Add a link relation for 'self' book.Links.Add(new Link() { Rel = "self", Href = self }); // Add a link relation for the parent 'collection' List <string> u = Request.RequestUri.Segments.ToList(); book.Links.Add(new Link() { Rel = "collection", Href = u[0] + u[1] + u[2] }); // ############################################################ // New on Wed Oct 8 2014... // Add a link relation to indicate that an alternate representation is available book.Links.Add(new Link() { Rel = "self", Href = self, ContentType = "image/*", Title = "Book cover photo" }); // Add a link relation to indicate a command that can be performed book.Links.Add(new Link() { Rel = "edit", Href = self + "/setphoto", ContentType = "image/*", Method = "PUT" }); // ############################################################ // Add a link relation for 'self' in the item book.Item.Link = new Link() { Rel = "self", Href = self }; // Build a response object var response = Request.CreateResponse(HttpStatusCode.OK, book); // The repository method has returned a BookLinked object // We need to know if the request asked for an image to be returned. // If so, we need to configure the Content-Type header BEFORE the object // is passed on to the 'image' media formatter. // Unfortunately, the current design of the media formatter does not // allow us to dynamically set the response's Content-Type header. // See this post - http://stackoverflow.com/a/12565530 // Step 1 - look for an Accept header that starts with 'image' var imageHeader = Request.Headers.Accept .SingleOrDefault(a => a.MediaType.ToLower().StartsWith("image/")); // Step 2 - if found, set the Content-Type header value if (imageHeader != null) { if (string.IsNullOrEmpty(book.Item.ContentType)) { response.StatusCode = HttpStatusCode.NoContent; } else { response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(book.Item.ContentType); } } // Return the result return(response); } }
// POST: api/Books public HttpResponseMessage Post([FromBody] BookAdd newItem) { // Ensure that the URI is clean (and does not have an id parameter) if (Request.GetRouteData().Values["id"] != null) { return(Request.CreateErrorResponse (HttpStatusCode.BadRequest, "Invalid request URI")); } // Ensure that a "newItem" is in the entity body if (newItem == null) { return(Request.CreateErrorResponse (HttpStatusCode.BadRequest, "Must send an entity body with the request")); } // Ensure that we can use the incoming data if (ModelState.IsValid) { // Attempt to add the new object var addedItem = m.Books.AddNew(newItem); if (addedItem == null) { // HTTP 400 return(Request.CreateErrorResponse (HttpStatusCode.BadRequest, "Cannot add the object")); } else { // HTTP 201 with the new object in the entity body // Notice how to create the URI for the Location header // Create an object to be returned BookLinked book = new BookLinked(); // Set its item property book.Item = Mapper.Map <BookWithLink>(addedItem); // Get the request URI path Uri uri = new Uri(Url.Link("DefaultApi", new { id = book.Item.Id })); // Add a link relation for 'self' book.Links.Add(new Link() { Rel = "self", Href = uri.AbsolutePath }); // Add a link relation for the parent 'collection' List <string> u = Request.RequestUri.Segments.ToList(); book.Links.Add(new Link() { Rel = "collection", Href = u[0] + u[1] + u[2] }); // Add a link relation for 'self' in the item book.Item.Link = new Link() { Rel = "self", Href = uri.AbsolutePath }; // Build the response object var response = Request.CreateResponse <BookLinked>(HttpStatusCode.Created, book); // Set the Location header response.Headers.Location = uri; // Return the response return(response); } } else { // HTTP 400 return(Request.CreateErrorResponse (HttpStatusCode.BadRequest, ModelState)); } }
// GET: api/Books/5 public HttpResponseMessage Get(int id) { var fetchedObject = m.Books.GetById(id); if (fetchedObject == null) { return Request.CreateResponse(HttpStatusCode.NotFound); } else { // Create an object to be returned BookLinked book = new BookLinked(); // Set its item property book.Item = Mapper.Map<BookWithLink>(fetchedObject); // Get the request URI path string self = Request.RequestUri.AbsolutePath; // Add a link relation for 'self' book.Links.Add(new Link() { Rel = "self", Href = self }); // Add a link relation for the parent 'collection' List<string> u = Request.RequestUri.Segments.ToList(); book.Links.Add(new Link() { Rel = "collection", Href = u[0] + u[1] + u[2] }); // ############################################################ // New on Wed Oct 8 2014... // Add a link relation to indicate that an alternate representation is available book.Links.Add(new Link() { Rel = "self", Href = self, ContentType = "image/*", Title = "Book cover photo" }); // Add a link relation to indicate a command that can be performed book.Links.Add(new Link() { Rel = "edit", Href = self + "/setphoto", ContentType = "image/*", Method = "PUT" }); // ############################################################ // Add a link relation for 'self' in the item book.Item.Link = new Link() { Rel = "self", Href = self }; // Build a response object var response = Request.CreateResponse(HttpStatusCode.OK, book); // The repository method has returned a BookLinked object // We need to know if the request asked for an image to be returned. // If so, we need to configure the Content-Type header BEFORE the object // is passed on to the 'image' media formatter. // Unfortunately, the current design of the media formatter does not // allow us to dynamically set the response's Content-Type header. // See this post - http://stackoverflow.com/a/12565530 // Step 1 - look for an Accept header that starts with 'image' var imageHeader = Request.Headers.Accept .SingleOrDefault(a => a.MediaType.ToLower().StartsWith("image/")); // Step 2 - if found, set the Content-Type header value if (imageHeader != null) { if (string.IsNullOrEmpty(book.Item.ContentType)) { response.StatusCode = HttpStatusCode.NoContent; } else { response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(book.Item.ContentType); } } // Return the result return response; } }
// PUT: api/Books/5 public IHttpActionResult Put(int id, [FromBody]BookEdit editedItem) { // Ensure that an "editedItem" is in the entity body if (editedItem == null) { return BadRequest("Must send an entity body with the request"); } // Ensure that the id value in the URI matches the id value in the entity body if (id != editedItem.Id) { return BadRequest("Invalid data in the entity body"); } // Ensure that we can use the incoming data if (ModelState.IsValid) { // Attempt to update the item var changedItem = m.Books.EditExisting(editedItem); // Notice the ApiController convenience methods if (changedItem == null) { // HTTP 400 return BadRequest("Cannot edit the object"); } else { // From RFC 7231... // http://tools.ietf.org/html/rfc7231#section-4.3.4 // "the origin server MUST send either a 200 (OK) // or a 204 (No Content) response to indicate // successful completion of the request" // So, we have a choice... // To send HTTP 204... // return StatusCode(HttpStatusCode.NoContent); // To send HTTP 200... // Include the changed item in the entity body, as seen below // Create an object to be returned BookLinked book = new BookLinked(); // Set its item property book.Item = Mapper.Map<BookWithLink>(changedItem); // Get the request URI path Uri uri = new Uri(Url.Link("DefaultApi", new { id = book.Item.Id })); // Add a link relation for 'self' book.Links.Add(new Link() { Rel = "self", Href = uri.AbsolutePath }); // Add a link relation for the parent 'collection' List<string> u = Request.RequestUri.Segments.ToList(); book.Links.Add(new Link() { Rel = "collection", Href = u[0] + u[1] + u[2] }); // Add a link relation for 'self' in the item book.Item.Link = new Link() { Rel = "self", Href = uri.AbsolutePath }; // Return the response return Ok<BookLinked>(book); } } else { return BadRequest(ModelState); } }
// POST: api/Books public HttpResponseMessage Post([FromBody]BookAdd newItem) { // Ensure that the URI is clean (and does not have an id parameter) if (Request.GetRouteData().Values["id"] != null) { return Request.CreateErrorResponse (HttpStatusCode.BadRequest, "Invalid request URI"); } // Ensure that a "newItem" is in the entity body if (newItem == null) { return Request.CreateErrorResponse (HttpStatusCode.BadRequest, "Must send an entity body with the request"); } // Ensure that we can use the incoming data if (ModelState.IsValid) { // Attempt to add the new object var addedItem = m.Books.AddNew(newItem); if (addedItem == null) { // HTTP 400 return Request.CreateErrorResponse (HttpStatusCode.BadRequest, "Cannot add the object"); } else { // HTTP 201 with the new object in the entity body // Notice how to create the URI for the Location header // Create an object to be returned BookLinked book = new BookLinked(); // Set its item property book.Item = Mapper.Map<BookWithLink>(addedItem); // Get the request URI path Uri uri = new Uri(Url.Link("DefaultApi", new { id = book.Item.Id })); // Add a link relation for 'self' book.Links.Add(new Link() { Rel = "self", Href = uri.AbsolutePath }); // Add a link relation for the parent 'collection' List<string> u = Request.RequestUri.Segments.ToList(); book.Links.Add(new Link() { Rel = "collection", Href = u[0] + u[1] + u[2] }); // Add a link relation for 'self' in the item book.Item.Link = new Link() { Rel = "self", Href = uri.AbsolutePath }; // Build the response object var response = Request.CreateResponse<BookLinked>(HttpStatusCode.Created, book); // Set the Location header response.Headers.Location = uri; // Return the response return response; } } else { // HTTP 400 return Request.CreateErrorResponse (HttpStatusCode.BadRequest, ModelState); } }
// GET: api/Books/5 /// <summary> /// Information for one book /// </summary> /// <param name="id">Book identifier (int)</param> /// <returns>Book object</returns> public IHttpActionResult Get(int? id) { // Attention - This method DOES use content negotiation (aka conneg) // Fetch the object var fetchedObject = w.Books.GetById(id.GetValueOrDefault()); // Continue? if (fetchedObject == null) { return NotFound(); } // Attention - Here is the content negotiation code // Look for an Accept header that starts with 'image' var imageHeader = Request.Headers.Accept .SingleOrDefault(a => a.MediaType.ToLower().StartsWith("image/")); if (imageHeader == null) { // Normal processing for a JSON result BookLinked result = new BookLinked(Mapper.Map<BookWithLink>(fetchedObject)); // Get the request URI path string self = Request.RequestUri.AbsolutePath; // Add a link relation to indicate a command that can be performed result.Links.Add(new Link() { Rel = "edit", Href = self + "/setphoto", ContentType = "image/*", Method = "PUT" }); // If a media item exists, add some custom links... if (result.Item.PhotoLength > 0) { // Add a link relation to indicate that an alternate representation is available result.Links.Add(new Link() { Rel = "self", Href = self, ContentType = "image/*", Title = "Book cover photo", Method = "GET" }); // Add a link relation to indicate that an alternate representation is available result.Links.Add(new Link() { Rel = "self", Href = self + "/photo", ContentType = "image/*", Title = "Book cover photo", Method = "GET" }); } // Return the result, using the built-in media formatters (JSON, XML) return Ok(result); } else { // Special processing for an image result // Confirm that a media item exists if (fetchedObject.PhotoLength > 0) { // Return the result, using the custom media formatter return Ok(fetchedObject.Photo); } else { // Otherwise, return "not found" // Yes, this is correct. Read the RFC: https://tools.ietf.org/html/rfc7231#section-6.5.4 return NotFound(); } } }