I am trying to learn Web API and created my first project as below. I am testing it using postman. The post method works fine and I get response message – but the input received at the controller for the post action is null. What need to be done to get the post value in the controller?
using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http;
using WebApplication1.Models;
namespace WebApplication1.Controllers
{
public class ValuesController : ApiController
{
List<Comment> comments;
// GET api/values
public IEnumerable<Comment> Get()
{
return comments;
}
// GET api/values/5
public Comment Get(int id)
{
Comment c = comments[id-1];
if (string.IsNullOrEmpty(c.Description))
{
throw new HttpResponseException(System.Net.HttpStatusCode.NotFound);
}
return c;
}
// POST api/values
public HttpResponseMessage Post(Comment inputComment)
{
Comment c = new Comment();
if (inputComment != null)
{
c.Description = inputComment.Description;
c.ID = inputComment.ID;
}
//var response = new HttpResponseMessage(HttpStatusCode.Created);
//return response;
var response = Request.CreateResponse<Comment>(System.Net.HttpStatusCode.Created, c);
response.Headers.Location=new System.Uri(Request.RequestUri,"/api/values/"+c.ID.ToString());
return response;
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
public ValuesController()
{
comments = new List<Comment>();
Comment comment1 = new Comment();
comment1.ID = 1;
comment1.Description = "Test1";
Comment comment2 = new Comment();
comment2.ID = 2;
comment2.Description = "";
comments.Add(comment1);
comments.Add(comment2);
}
}
}
POSTMAN Request/Response
POSTMAN Request Header
UPDATE
After using 'raw' in the request body, it worked fine. In POSTMAN, when I clicked "Generate Code", it is now displaying correct headers.
Use Raw as body type instead of Form-data and input you JSON.
Related
I have question about web api and Repository may be its a duplicate question.
but i tried to search on it and i did not get any satisfactory answer.
In my Repository i am getting data with the help of httpclient.
My question is that i can get an error inside my response or i can get required json data which i can map to my product class.I am returning IEnumerable.
1) If i get an error how can i bubble it up to controller and display an error to user.
2) Return the MessageResponse instead of IEnumerable and handle it inside the controller.
What is the best way.
enter code here
public interface IProduct{
Task<IEnumerable<Product>> All();
}
public class Product:IProduct
{
public async Task<IEnumerable<Product>> All(){
var ResponseMessage=//some response.
}
}
You could customize a ApiException which is used to get the error message of the response, and call the UseExceptionHandler in your startup.cs ,refer to the following :
ProductRep
public class ProductRep : IProduct
{
private readonly HttpClient _client;
public ProductRep(HttpClient client)
{
_client = client;
}
public async Task<IEnumerable<Product>> All()
{
List<Product> productlist = new List<Product>();
var response = await _client.GetAsync("https://localhost:44357/api/values/GetProducts");
string apiResponse = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode == false)
{
JObject message = JObject.Parse(apiResponse);
var value = message.GetValue("error").ToString();
throw new ApiException(value);
}
productlist = JsonConvert.DeserializeObject<List<Product>>(apiResponse);
return productlist;
}
public class ApiException : Exception
{
public ApiException(string message): base(message)
{ }
}
}
Startup.cs
app.UseExceptionHandler(a => a.Run(async context =>
{
var feature = context.Features.Get<IExceptionHandlerPathFeature>();
var exception = feature.Error;
var result = JsonConvert.SerializeObject(new { error = exception.Message });
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(result);
}));
I am calling sample google book URL from the lightning component, For that i have written APEX controller to make http request . But it is throwing 404 error for the Google Book API. Here is my APEX controller please check ,
public class WebservicesController {
public static String responseFormat='application/json';
public static String bodyContentType='application/json';
#AuraEnabled
public static Response makeRequest(String url, String method, String bodyContent) {
System.debug('Making request httpResponse ' );
HttpRequest request = buildRequest(url, method,bodyContent);
HttpResponse httpRes = sendRequest(request);
Response restRes = buildResponse(httpRes);
return restRes;
}
private static HttpRequest buildRequest(String url, String method, String bodyContent) {
HttpRequest request = new HttpRequest();
System.debug('Making request httpResponse '+ url );
request.setEndpoint(url);
request.setMethod(method);
request.setHeader('Content-Security-Policy', '*');
if (bodyContent != null) {
request.setBody(bodyContent);
request.setHeader('Content-Type', bodyContentType);
}
request.setHeader('ACCEPT', responseFormat);
return request;
}
private static HttpResponse sendRequest(HttpRequest request) {
return new Http().send(request);
}
private static Response buildResponse(HttpResponse httpRes) {
Response restRes = new Response();
restRes.status = httpRes.getStatus();
restRes.statusCode = httpRes.getStatusCode();
restRes.body = httpRes.getBody();
System.debug(' Status code is ' + restRes.statusCode );
System.debug(' httpResponse ' + httpRes.getBody() );
return restRes;
}
public class Response {
#AuraEnabled
public String status { get; set; }
#AuraEnabled
public Integer statusCode { get; set; }
#AuraEnabled
public String body { get; set; }
}
}
and also my helper js controller where i am calling this apex controller is method is below ..
createCustomer: function(component, customer) {
var action = component.get("c.makeRequest");
action.setParams({
url: "https://www.googleapis.com/books/v1/volumes/NFPqCQAAQBAJ",
method: "GET",
bodyContent: "",
});
action.setCallback(this, function(a) {
action.setCallback(this, function(response){
var state = response.getState();
if (state === "SUCCESS") {
var customers = component.get("v.data");
customers.push(response.getReturnValue());
component.set("v.data", customers);
}
var action = component.get("c.saveCustomer");
action.setParams({
"customer": customer
});
});
$A.enqueueAction(action);
});
$A.enqueueAction(action);
},
And i also given this google api url in Remote settings and also added as CSP trusted site in my domain.
Add #AuraEnabled in front of following method:
buildRequest
sendRequest
buildResponse
I have an app in facebook and I am trying to obtain long term token,
for that I call the following link:
https://graph.facebook.com/oauth/authorize?client_id=xxxxxx&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Faccesstokforfacebook%2Ffbaccess&scope=read_stream,read_insights,user_religion_politics,user_relationship_details,user_hometown,user_location,user_likes,user_activities,user_interests,user_education_history,user_work_history,user_website,user_groups,user_events,user_photos,user_videos,user_about_me,user_status,user_games_activity,user_tagged_places,user_actions.books,user_actions.video,user_actions.news
and the return url is a servlet with following codes:
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String accessCode = request.getParameter("code");
System.out.println("dddd "+accessCode);
//print SUCCESS if code is found
/*if (accessCode!=null){*/
out.print("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\"http://www.w3.org/TR/html4/strict.dtd\"><html><head><title>Facebook Access Granted</title></head><body>");
out.print("<p>SUCCESS!</p><p>"+accessCode+"</p></body></html>");
and this servlet receives the very long code like this:
AQCY244eMOhxEVu3e6UEIl-qK974wTh-p0Il1ZdG9VEAYl5GdrjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxQcJeUmeXFU56cbWbmXJdLQvEyIT7JWCxxu6tChkr9oCL1DVYxxv4v-j4Y_vaWGD7dYcxxxxxxxxxxxxxxxxxxTvZPHLU-tU5ySHrQrVgpo_i8minM73cyWxxxxxxxxxxxxxxdZvnrIhQXQ-B_3LAFzDcWe2NbCW7WSgmQ-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxMkJ55M0wHHbLmL4D-g_wLIwhpz4W_8Hz0h7v_ZL
Now when I use this token to get the all info for a page I get an error:
this is a link that I use:
https://graph.facebook.com/v2.0/khalatbari.hooman/feed?access_token=THE ABOVE CODE
and the error is:
Now I think the code that I get is not access token but I have no idea how to use this code to get access token!!!
can anyone help
Finally found solution for Facebook SDK 4.6.0 to getting limited comment's list for feed :
1> Calling commentInfo() firstly Inside Activity's oncreate()
:
private boolean isLoadMoreCalled;
commentInfo("", "true");
2> Putting load more method also there like:
listViewCommentList.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
Log.d("scrollState", ""+scrollState);
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int last_visible_in_screen = firstVisibleItem + visibleItemCount;
if(last_visible_in_screen == totalItemCount && isLoadMoreCalled) {
Toast.makeText(getApplicationContext(), "Loading more Items 10", Toast.LENGTH_SHORT).show();
commentInfo(nextFeedUrl, "false");
isLoadMoreCalled = false;
}
}
});
3> create commentInfo() of outside onCreate() :
public void commentInfo (String fields, final String isFirst) {
/** Festival Feed Comments Details #Facebook */
Bundle params = new Bundle();
params.putString("fields", "message,created_time,from");
params.putString("limit", "10");
if(isFirst.equals("false")) {
params.putString("after", fields);
}
showProgressBar();
/* make the API call */
//refreshCurrentAccessTokenAsync();
System.out.println("Acees Token Comment>>>"+ AccessToken.getCurrentAccessToken());
new GraphRequest(AccessToken.getCurrentAccessToken(), "/"+ feedId +"/comments", params, HttpMethod.GET,
new GraphRequest.Callback() {
public void onCompleted(GraphResponse response) {
/* handle the result */
System.out.println("Festival feed Comments response::" + String.valueOf(response.getJSONObject()));
try {
JSONObject jObjResponse = new JSONObject(String.valueOf(response.getJSONObject()));
JSONObject jObjPaging = jObjResponse.getJSONObject("paging");
JSONObject jObjCursor = jObjPaging.getJSONObject("cursors");
nextFeedUrl = "";
nextFeedUrl = jObjCursor.getString("after");
System.out.println("nextFeedUrl>>"+ nextFeedUrl);
JSONArray jArrayData = jObjResponse.getJSONArray("data");
for(int i = 0; i< jArrayData.length(); i++) {
Getting comments info & store into Data-Structure(Array-List)
}
if(isFirst.equals("true")) {
fbFeedCommentAdapter = new FbFeedCommentAdapter();
listViewCommentList.setAdapter(fbFeedCommentAdapter);
}
else {
fbFeedCommentAdapter.notifyDataSetChanged();
}
if(!jObjPaging.has("next")) {
isLoadMoreCalled = false;
}
else {
isLoadMoreCalled = true;
}
dismissProgressBar();
}
catch (Exception e) {
e.printStackTrace();
dismissProgressBar();
}
}
}
).executeAsync();
}
Here,
fbFeedCommentAdapter -> BaseAdapter
listViewCommentList -> Listview
Also refer How to use the Facebook Graph Api Cursor-based Pagination
I need to populate my pojo class based on the request param 'type'.
so I have code like
#ModelAttribute
public void getModelObject(HttpServletRequest request, ModelMap modelMap) {
String typeCombo = request.getParameter("type");
System.out.println("typeCombo: " + typeCombo);
if (typeCombo != null) {
if (condition) {
modelMap.addAttribute("modelObj", new ClassB()); //ClassB extends ClassA
} else if (another condition) {
modelMap.addAttribute("modelObj", new ClassC()); //ClassC extends ClassA
} else {
System.out.println("no type found");
}
} else {
System.out.println("typecombo null");
}
}
I use above method to get create correct subclasses which will be used to add / update. The above one works fine in case of "POST" - for creating a record. But for "PUT" request.getParameter("type") always returns null. So for editing, I'm not able to get correct subclasses.
Below are my post and put request mapping:
#RequestMapping(value = "", method = RequestMethod.POST, headers = "Accept=*/*")
#ResponseBody
public String addCredentials(#ModelAttribute("modelObj") Credential credential,
ModelMap modelMap) {
//code
}
#RequestMapping(value = "/edit/{id}", method = RequestMethod.PUT, headers = "Accept=*/*")
#ResponseBody
public Credential editCredential(#ModelAttribute ("modelObj") Credential credential, #PathVariable long id, ModelMap model) {
//code
}
Any help is much appreciated.
Register the filter HttpPutFormContentFilter like this:
<beans:bean id="httpPutFormContentFilter"
class="org.springframework.web.filter.HttpPutFormContentFilter" />
I am currently working on a website and I had a good separation of concerns following a repository pattern with repositories and managers. Now, I am attempting to implement a Web API as I would greatly benefit from it in the future being able to use it from various clients. Since I am fairly new to REST services, I am having trouble with the correct procedure to consume my web API from a Service in my MVC4 application to then use that service in my MVC controllers. I do not want to have to use knockout for every call to the API.
My Web APIs look something like this(simplified):
public class UserController : ApiController
{
private readonly IUserManager _manager;
public UserController(IUserManager manager)
{
this._manager = manager;
}
// GET api/user
public IEnumerable<User> Get()
{
return _manager.GetAll();
}
// GET api/user/5
public User Get(int id)
{
return _manager.GetById(id);
}
// POST api/user
public void Post(User user)
{
_manager.Add(user);
}
// PUT api/user/5
public void Put(User user)
{
_manager.Update(user);
}
// DELETE api/user/5
public void Delete(User user)
{
_manager.Delete(user);
}
}
I essentially would like to create a service to consume my web API as such:
public class UserService : IUserService
{
....Implement something to get,post,put,and delete using the api.
}
so then I can use it in my mvc controller:
public class UserController: Controller
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
this._userService = userService;
}
//And then I will be able to communicate with my WebAPI from my MVC controller
}
I know this is possible because I have seen it done at some workplaces but it is very difficult to find articles about this, I have only found articles explaining how to consume web API through knockout. Any help or tips would be greatly appreciated.
Have a look at the implementation over here: https://github.com/NBusy/NBusy.SDK/blob/master/src/NBusy.Client/Resources/Messages.cs
It basically makes use of HttpClient class to consume Web API. One caveat though, all responses are wrapped in a custom HttpResponse class in that sample. You don't need to do that and can simply use the retrieved DTO object as the return type or a raw HttpResponseMessage class.
You might want to create a static class, I created a separate Class Library to use across solutions that might want to use the API.
NOTE: I use RestSharp for POST and PUT operation since I haven't been able to get them to work using the regular HttpClient over SSL. As you can see documented in this question.
internal static class Container
{
private static bool isInitialized;
internal static HttpClient Client { get; set; }
internal static RestClient RestClient { get; set; }
/// <summary>
/// Verifies the initialized.
/// </summary>
/// <param name="throwException">if set to <c>true</c> [throw exception].</param>
/// <returns>
/// <c>true</c> if it has been initialized; otherwise, <c>false</c>.
/// </returns>
/// <exception cref="System.InvalidOperationException">Service must be initialized first.</exception>
internal static bool VerifyInitialized(bool throwException = true)
{
if (!isInitialized)
{
if (throwException)
{
throw new InvalidOperationException("Service must be initialized first.");
}
}
return true;
}
/// <summary>
/// Initializes the Service communication, all methods throw a System.InvalidOperationException if it hasn't been initialized.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="connectionUserName">Name of the connection user.</param>
/// <param name="connectionPassword">The connection password.</param>
internal static void Initialize(string url, string connectionUserName, string connectionPassword)
{
RestClient = new RestClient(url);
if (connectionUserName != null && connectionPassword != null)
{
HttpClientHandler handler = new HttpClientHandler
{
Credentials = new NetworkCredential(connectionUserName, connectionPassword)
};
Client = new HttpClient(handler);
RestClient.Authenticator = new HttpBasicAuthenticator(connectionUserName, connectionPassword);
}
else
{
Client = new HttpClient();
}
Client.BaseAddress = new Uri(url);
isInitialized = true;
}
}
public static class UserService
{
public static void Initialize(string url = "https://serverUrl/", string connectionUserName = null, string connectionPassword = null)
{
Container.Initialize(url, connectionUserName, connectionPassword);
}
public static async Task<IEnumerable<User>> GetServiceSites()
{
// RestSharp example
Container.VerifyInitialized();
var request = new RestRequest("api/Users", Method.GET);
request.RequestFormat = DataFormat.Json;
var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute<List<User>>(request); }).ConfigureAwait(false);
return response.Data;
// HttpClient example
var response = await Container.Client.GetAsync("api/Users/").ConfigureAwait(false);
return await response.Content.ReadAsAsync<IEnumerable<User>>().ConfigureAwait(false);
}
public static async Task<User> Get(int id)
{
Container.VerifyInitialized();
var request = new RestRequest("api/Users/" + id, Method.GET);
var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute<User>(request); }).ConfigureAwait(false);
return response.Data;
}
public static async Task Put(int id, User user)
{
Container.VerifyInitialized();
var request = new RestRequest("api/Users/" + id, Method.PATCH);
request.RequestFormat = DataFormat.Json;
request.AddBody(user);
var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute(request); }).ConfigureAwait(false);
}
public static async Task Post(User user)
{
Container.VerifyInitialized();
var request = new RestRequest("api/Users", Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddBody(user);
var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute(request); }).ConfigureAwait(false);
}
public static async Task Delete(int id)
{
Container.VerifyInitialized();
var request = new RestRequest("api/Users/" + id, Method.DELETE);
var response = await Task.Factory.StartNew(() => { return Container.RestClient.Execute(request); }).ConfigureAwait(false);
}
}