2
votes

I am trying to do a post request with body and header. Below are some of the variations I have gone through, but for the most part I am getting error on the server saying that the parameter, 'key', was not passed in.

I tried this api in the postman and it's working there. This is how I have defined the method header in Java/Spring Boot:

@RequestMapping(value = "/getIssue", method = RequestMethod.POST)
public IssuePojo getIssue(@RequestParam("key") String key, HttpServletRequest request) {

Below are my angular's variations:

public getJiraIssue(key: string): Observable<any> {

    let headers = new HttpHeaders({
      'Content-Type': 'application/json',
      'Authorization': this.idToken });
    let options = { headers: headers };

    const paramsA = new URLSearchParams();
    paramsA.set('key', key);
    let params = new HttpParams().append('key', key);
    // return this.http.post(this.urlEnvironment.jiraGetIssue(), params, this.getHeaders());
    console.log("headers: ", this.getHeaders());
    // let obj = {
    //   key: key
    // }

    var headersA = new Headers();
    headers.append('Authorization', this.idToken);

    let body = new HttpParams()
    .set('key', key);

    return this.http.post(this.urlEnvironment.jiraGetIssue(), body, {headers: headers});
    // return this.http.post(this.urlEnvironment.jiraGetIssue(), null, {headers: this.getHeaders(), params: params});
  }

It seems that the body is being sent:

enter image description here

But this is the error I got:

timestamp: "2019-01-30T04:30:40.721+0000", status: 400, error: "Bad Request",…}
error: "Bad Request"
message: "Required String parameter 'key' is not present"
path: "/jira/getIssue"
status: 400
timestamp: "2019-01-30T04:30:40.721+0000"
trace: "org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'key' is not present
4
OK: so you're successfully able to query Jira from Postman, so you know a) what the HTTP headers should be ('Content-Type': 'application/json', and 'Authorization':XYZ), and you know what the body should be (JSON like this: developer.atlassian.com/server/jira/platform/…). So far, so good. Q: Who is querying Jira: your JS/Angular front-end, or your Java/Spring boot backend? Q: Have you looked at the HTTP being sent (Fiddler or Wireshark)? - paulsm4
I was saying that I have verified my Java API is working through Postman. Java is querying Jira - Noman
Q: Are you successfully able to query Jira anywhere? Java? Postman? Curl? Q: Have you confirmed how the HTTP body should look? I suspect maybe it should be JSON (like here), and NOT a string like "key=WJC-7". SUGGESTION: Verify the message format. - paulsm4
Yes, API is working fine. I tested my method in different ways, from Java and postman. If I take out my Servlet from the method, then it's working. - Noman

4 Answers

2
votes

HttpParams() are used to add query sting parameter to the request URL if you need that then first check if this is getting added in the Developer tools request that is made if that is there then there is something wrong at the api side

1
votes

OK, my understanding is that you have an JS/Angular 7 front-end. It's talking to a Java/Spring Boot back end, which in turn queries Jira:

    Angular       SpringBoot         Jira
   --------- (1)  ----------- (2) ----------
   (service) --> (controller) --> (Jira API)
             <--              <--
             (4)              (3)

Correct so far?

It's it sounds like you can successfully query Jira with Postman (request 2, response 3), correct?

The problem is that your get HTTP 400: "Required String parameter 'key' is not present" when Angular queries Spring Boot (request 1), correct?

That's what I was trying to ask in my comments above. The problem is clearly that your message payload, "key=WJC-7", isn't valid JSON. So the request fails.

Based on what you've shared, I'm making a lot of "assumptions" here. Nevertheless:

SUGGESTION:

  1. Have Angular create the object: let obj = { key: key };, just like you were doing in the first place.

  2. Make sure it's complete (I imagine the Jira API needs more than just a "key").

  3. Make sure the Angular object you're sending matches - field-for-field - the Java object the Spring Boot controller is expecting. Spring Boot should automatically serialize/deserialize in JSON.

  4. Have Angular send the object (as "data"). Your "message payload" != "msg headers".

  5. Be SURE to examine the payloads being sent and received each step of the way (1, 2, 3 and 4 above). You can do this with Fiddler, with Wireshark, or with trace logging.

'Hope that helps!

PS: Here's a hypothetical example of a Java Spring Boot controller that an Angular client might invoke:

...
@RestController
@CrossOrigin(origins = "http://localhost:4200")
public class TodoResource {

    @Autowired
    private TodoHardcodedService todoService;

    // GET All todos
    @GetMapping("/users/{username}/todos")
    public List<Todo> getAllTodos(@PathVariable String username) {
        return todoService.findAll();
    }
...

And here is the corresponding example Java "Todo" object:

public class Todo {
    private long id;
    private String username;
    private String description;
    private Date targetDate;
    private boolean isDone;
    ...
0
votes

enter image description hereUse this HHTP service class to send parameters in body and you can send in headers too

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable, empty } from 'rxjs';
import { catchError, timeout } from 'rxjs/operators';


@Injectable({
  providedIn: 'root'
})
export class HttpService {
  constructor(private http: HttpClient) {
  }

  private getHeaders(headersConfig?: object): HttpHeaders {
    return new HttpHeaders({
      'Content-Type': 'application/json',
      ...headersConfig,
    });
  }

  get(url: string, params: HttpParams = new HttpParams(), headers: Object): Observable<any> {
    let finalHeaders = this.getHeaders();
    if (headers) {
      for (let key in headers) {
        finalHeaders = finalHeaders.append(key, headers[key]);
      }
    }
    return this.http.get(
      url,
      { headers: finalHeaders, params }
    ).pipe(timeout(10000)).pipe(catchError(this.handleError('Get request')));
  }

  put(url: string, body: Object = {}, headers: Object): Observable<any> {
    let finalHeaders = this.getHeaders();
    if (headers) {
      for (let key in headers) {
        finalHeaders = finalHeaders.append(key, headers[key]);
      }
    }
    return this.http.put(
      url,
      body,
      { headers: finalHeaders }
    ).pipe(timeout(10000)).pipe(catchError(this.handleError<any>('put request')));
  }

  post(url: string, body: Object = {}, headers: Object): Observable<any> {
    let finalHeaders = this.getHeaders();
    if (headers) {
      for (let key in headers) {
        finalHeaders = finalHeaders.append(key, headers[key]);
      }
    }
    return this.http.post(
      url,
      body,
      { headers: finalHeaders }
    ).pipe(timeout(10000)).pipe(catchError(this.handleError<any>('post request')));
  }

  /**
 * Handle Http operation that failed.
 * Let the app continue.
 * @param operation - name of the operation that failed
 * @param result - optional value to return as the observable result
 */
  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      return empty();//of(result as T);
    };
  }
}
0
votes

So the key is 'Content-Type': 'application/json', Since I'm sending json, then on the server side its expecting to map it to an Object. I managed to get it to work with string as well, but then I have to parse the string myself on the server which is not what I'm looking to do.

So 'Content-Type': 'text/plain', => maps to => @RequestBody String key

And 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', => maps to => @RequestParam String key, @RequestParam String test,

And so the post call from Angular will look like this:

const httpBody = new HttpParams()
      .set('key', 'key')
      .set('test', 'test');
    return this.http.post(endPoint, httpBody, this.getArgHeaders());

  private getArgHeaders(): any {
      const httpOptions = {
        headers: new HttpHeaders({
          'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
        })
      };
      return httpOptions;
  }