Can't call method with PUT or POST - web-services

I can request an API method via http://requestmaker.com/ using GET, but when I use POST or PUT it returns...
HTTP/1.1 403 Forbidden
Here is the method...
[HttpPost]
[Route("api/sales")]
public object Put([FromBody] Sale sale)
{
sale.DateTime = DateTime.Now;
paymentRepository.Insert(sale);
paymentRepository.Save();
return Ok(new { id = sale.SaleId });
}
Any ideas?
Request headers are...
POST /admin/api/sales HTTP/1.1 Host: hello.com Accept: /
Content-Type: text/html Content-Length: 17
Request data...
TourId=3&UserId=1

It has to do with how your Controller is routing the requests. You seem to have defined something like this
Defaults To GET:
public async Task<IHttpActionResult> MethodName(){
return this.Ok()
}
or
[HttpGet]
public async Task<IHttpActionResult> MethodName(){
return this.Ok()
}
There should be some attributes that you can define above the function:
For POST:
[HttpPost]
public async Task<IHttpActionResult> MethodNamePost(){
return this.Ok()
}
For PUT:
[HttpPut]
public async Task<IHttpActionResult> MethodNamePut(){
return this.Ok()
}
Like Win said:
[HttpPut]
[Route("api/sales")]
public object Put([FromBody] Sale sale)
{
sale.DateTime = DateTime.Now;
paymentRepository.Insert(sale);
paymentRepository.Save();
return new { id = sale.SaleId };
}
I would change the return to this.Ok(new {id = sale.SaleId}); though.

Your Request headers are wrong it should be like
{
"UserId":"1",
"TourID":"3",
}
REASON:application/json

Oh silly me, it was looking for an anti-forgery token. I thought I'd commented the filter out, but I'd done it for MVC and not Web Api. Oops.
I also needed to set the content type to application/json and set the data as { "TourId":"3", "UserId":"1" } in order for model binding to work.

Related

Passing a pdf from Django backend to Angular frontend

I haven't been able to make any of the solutions to similar problems work for my case.
I would like to load a pdf from filesystem with django and return it via an API call to Angular so that it can be displayed. My Django code is pretty much:
class LoadPdfViewSet(views.APIView):
def get(self, request):
# some code here here
response = FileResponse(open(path_to_pdf, 'rb').read())
response.headers = {
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment;filename="report.pdf"',
}
response.as_attachment = True
return response
while on the Angular side I have a service that does this:
export class LoadPdfService {
constructor(
private http: HttpClient
) {}
getPdf(): Observable<Blob> {
const params = new HttpParams({
fromObject: {
responsetype: 'arraybuffer'
// other stuff here
}
})
return self.http.get<Blob>(loadpdf_api_url, {params}).pipe(catchError(self.myErrorHandler))
}
}
and a component that tries to open the pdf like this:
export class MyComponent {
constructor(
public loadPdfService: LoadPdfService
) {}
download_pdf() {
let call = self.loadPdfService.getPdf();
call.subscribe( (response:Blob) => {
if (window.navigator && window.navigator.msSaveOrOpenBlob) { // for IE
window.navigator.msSaveOrOpenBlob(blob, "report.pdf");
} else {
let pdfUrl = URL.createObjectURL(blob)
window.open(pdfUrl, '_blank')
URL.revokeObjectURL(pdfUrl);
}
}
}
}
but nothing happens. I have also tried using different responses and passthrough renderers on the django side, and Observable<Response> and .then() callbacks like
response.arrayBuffer().then(buffer => new Blob([buffer], {type: 'application/pdf'}))
on the Angular side. Sometimes I have managed to get the new window/tab to open but no pdf could be displayed.
I finally figured it out. In the python part, the read() can be removed with no problem. The issue was with the service response type and mapping of the response:
getPdf(): Observable<Blob> {
const options = {
params: new HttpParams({
fromObject: {
// my own parameters here
}
}),
responseType: 'blob' as 'json'
};
return this.http.get(this.url, options).pipe(
map(response => response as Blob),
catchError(this.myErrorHandler))
}

How to test the redirected routes with zuul routes filters in zuulProxy

I am following this link.
https://stackoverflow.com/a/57611351/7103694
What I am missing is this part on how to mock the filter i had used for my zuul Proxy.
This is my error log.
com.netflix.zuul.exception.ZuulException: Filter threw Exception
...
Caused by: .com.demo.example.exception.AccessTokenMissingException: No access token found in request headers.
I have a custom prefilter to check for Authorization header.
public class PreRouteFilter extends ZuulFilter {
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 1;
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String header = request.getHeader("Authorization");
// Check header if it contain AUTHORIZATION key and value starting with "Bearer "
if (header == null || !header.startsWith("Bearer ")) {
ctx.set("error.status_code", HttpServletResponse.SC_UNAUTHORIZED);
throw new AccessTokenMissingException("No access token found in request headers.");
}
return null;
}
}
I added my filter via this configuration.
#Configuration
public class FilterConfig {
#Bean
public PreRouteFilter routeFilter() {
return new PreRouteFilter();
}
}
in your test, you need to create a request and in that add a header for Bearer token based Authorization.
something like this,
1. create a RequestContext, -
RequestContext context = new RequestContext();
create a MockHttpServletRequest and add the Auth header to it.
MockHttpServletRequest httpRequest = new MockHttpServletRequest();
httpRequest.setMethod("GET");
String authHeader = "Bearer " + "your sample token string";
httpRequest.addHeader("Authorization", authHeader);
httpRequest.setRequestURI("/<whateverURI>");
set the Http request in the context,
context.setRequest(httpRequest);
Set this context as the current test context,
RequestContext.testSetCurrentContext(context);
Now, you can run the filter,
yourFilter.run();

How to get a CompletableFuture from Jetty's HttpClient?

Is it possible to use issue an asynchronous HTTP request using Jetty and get back a CompletableFuture?
I read the docs but could not find any examples of doing so. I found internal usage of CompletableFuture but I couldn't figure out how to access it using the public API.
UPDATE: I need the CompletableFuture to return the response body as well (not just the response code and headers).
I have been using this with jetty client 9.4.x
var completable = new CompletableFuture<ContentResponse>();
client
.newRequest(uri)
.send(new CompletableFutureResponseListener(completable));
where
public class CompletableFutureResponseListener extends BufferingResponseListener {
private final CompletableFuture<ContentResponse> completable;
public CompletableFutureResponseListener(
CompletableFuture<ContentResponse> completable) {
this.completable = completable;
}
#Override
public void onComplete(Result result) {
if (result.isFailed()) {
completable.completeExceptionally(result.getFailure());
} else {
var response =
new HttpContentResponse(
result.getResponse(),
getContent(),
getMediaType(),
getEncoding());
completable.complete(response);
}
}
}
It's trivial to convert a CompleteListener into a CompletableFuture in this way:
CompletableFuture<Result> completable = new Promise.Completable<>();
httpClient.newRequest(...).send(result -> {
if (result.isFailed()) {
completable.completeExceptionally(result.getFailure());
} else {
completable.complete(result);
}
});
However, you are right that this may be done by HttpClient itself. Track this issue.

Retrofit 2.1 Internal Server Error with Post

I am using Retrofit 2.1 and when i am posting an object to my server, it gives me Internal server error with status code = 500, but i try to to post from my backend, it works like a charm, I am sure this is not server's problem.
Undoubtedly, i should use retrofit as a singleton:
//return api if not null
HereApi getApi(){
if (api == null) {
api = getRetrofit().create(HereApi.class);
}
return api;
}
//returns restadapter if not null
Retrofit getRetrofit(){
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl("my endpoint")
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
and this method that i post Here object:
void createHere(Here here){
List<Here> list = new ArrayList<>();
list.add(here);
Call<List<Here>> call = getApi().createHere(list);
call.enqueue(new Callback<List<Here>>() {
#Override
public void onResponse(Call<List<Here>> call, Response<List<Here>> response) {
Log.i(TAG, "onResponse: "+response.message());
}
#Override
public void onFailure(Call<List<Here>> call, Throwable t) {
}
});
}
I tried to post a list with single object inside and to post one object alone, but still status code is 500 ;*(
This is my api service interface:
public interface HereApi{
#GET("/lessons/")
Call<List<Lesson>> getLesson(#QueryMap Map<String,String> map);
#Headers({
"Content-Type: application/json",
"Vary: Accept"
})
#POST("/heres/")
Call<List<Here>> createHere(#Body List<Here> list);
#GET("/heres/")
Call<List<Here>> getHeres(#QueryMap Map<String,String> map);
}
I have written backend in Django + Django-rest-framework:
When I try to post from this, it just works:
I need your help guys, i have only one day to complete this project!!!
Hi I think there is a datetime conversation issue.
Use Jackson formating attonation in order to properly serialize datetime field.

Testing ASP.NET Web API Multipart Form Data File upload

I am trying to use N-UNIT to test my web API application but I am unable to find a proper way to test my file upload method. Which would be the best approach to test the method?
Web API Controller:
[AcceptVerbs("post")]
public async Task<HttpResponseMessage> Validate()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
return Request.CreateErrorResponse(HttpStatusCode.UnsupportedMediaType,"please submit a valid request");
}
var provider = new MultipartMemoryStreamProvider(); // this loads the file into memory for later on processing
try
{
await Request.Content.ReadAsMultipartAsync(provider);
var resp = new HttpResponseMessage(HttpStatusCode.OK);
foreach (var item in provider.Contents)
{
if (item.Headers.ContentDisposition.FileName != null)
{
Stream stream = item.ReadAsStreamAsync().Result;
// do some stuff and return response
resp.Content = new StringContent(result, Encoding.UTF8, "application/xml"); //text/plain "application/xml"
return resp;
}
}
return resp;
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
Based on your above comment, following is an example:
HttpClient client = new HttpClient();
MultipartFormDataContent formDataContent = new MultipartFormDataContent();
formDataContent.Add(new StringContent("Hello World!"),name: "greeting");
StreamContent file1 = new StreamContent(File.OpenRead(#"C:\Images\Image1.jpeg"));
file1.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
file1.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
file1.Headers.ContentDisposition.FileName = "Image1.jpeg";
formDataContent.Add(file1);
StreamContent file2 = new StreamContent(File.OpenRead(#"C:\Images\Image2.jpeg"));
file2.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
file2.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
file2.Headers.ContentDisposition.FileName = "Image1.jpeg";
formDataContent.Add(file2);
HttpResponseMessage response = client.PostAsync("http://loclhost:9095/api/fileuploads", formDataContent).Result;
The request over the wire would like:
POST http://localhost:9095/api/fileuploads HTTP/1.1
Content-Type: multipart/form-data; boundary="34d56c28-919b-42ab-8462-076b400bd03f"
Host: localhost:9095
Content-Length: 486
Expect: 100-continue
Connection: Keep-Alive
--34d56c28-919b-42ab-8462-076b400bd03f
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=greeting
Hello World!
--34d56c28-919b-42ab-8462-076b400bd03f
Content-Type: image/jpeg
Content-Disposition: form-data; filename=Image1.jpeg
----Your Image here-------
--34d56c28-919b-42ab-8462-076b400bd03f
Content-Type: image/jpeg
Content-Disposition: form-data; filename=Image2.jpeg
----Your Image here-------
--34d56c28-919b-42ab-8462-076b400bd03f--
After spending a bit of time looking into WebClient I was able to come up with this:
try
{
var imageFile = Path.Combine("dir", "fileName");
WebClient webClient = new WebClient();
byte[] rawResponse = webClient.UploadFile(string.Format("{0}/api/values/", "http://localhost:12345/"), imageFile);
Console.WriteLine("Sever Response: {0}", System.Text.Encoding.ASCII.GetString(rawResponse)); // for debugging purposes
Console.WriteLine("File Upload was successful");
}
catch (WebException wexc)
{
Console.WriteLine("Failed with an exception of " + wexc.Message);
// anything other than 200 will trigger the WebException
}