Peter Penzov
Peter Penzov

Reputation: 1670

Empty result from rest api

I want to create a service in order to populate dropdown from database. I tried this:

Merchant Class:

export class Merchant {
  constructor(
    public id: string,
    public name: string,
    public state_raw: string,
    public users: string,
  ) {}
}

Merchant Service:

 getList(): Observable<Merchant> {
    return this.http.get<Merchant>(environment.api.urls.merchants.base, {});
  }

SQL query:

@Override
    public Iterable<Merchants> findAll() {
        String hql = "select e from " + Merchants.class.getName() + " e";
        TypedQuery<Merchants> query = entityManager.createQuery(hql, Merchants.class);
        List<Merchants> merchants = query.getResultList();
        return merchants;
    }

Working example:

    @GetMapping("/list")
public Iterable<Merchants> getMerchantsList() {
    return merchantRepository
            .findAll();
}

I tried this:

@GetMapping("/list")
public ResponseEntity<?> getMerchantsList() {
    return StreamSupport.stream(merchantRepository.findAll().spliterator(), false)
            .map(mapper::toDTO)
            .map(ResponseEntity::ok)
            .findFirst()
            .orElseGet(() -> notFound().build());
}

I want to use mapper before I send the response. Currently the list in Angular is empty. Probably I should return Iterable<Merchants> not ResponseEntity<MerchantDTO>?

I use Java 10.

Upvotes: 0

Views: 1025

Answers (1)

JB Nizet
JB Nizet

Reputation: 691903

There are several problems, on both sides. Let's start by the server-side. You want to return a list of merchants to populate a dropdown list, so you correctly named your method getMerchantsList(). But instead of returning a list as its name indicates, it returns void. void is nothing, nada, hence the empty response.

So you need to return a List<Merchant>, or, if you really want to (but it's unnecessary here since you don't want to set anything other than the response body), a ResponseEntity<List<Merchant>>. Calling findFirst() is counter-productive. You don't want the first merchant of the list. You want the whole list:

@GetMapping("/list")
public List<MerchantDTO> getMerchantsList() {
    return StreamSupport.stream(merchantRepository.findAll().spliterator(), false)
            .map(mapper::toDTO)
            .collect(Collectors.toList());
}

or

@GetMapping("/list")
public ResponseEntity<List<MerchantDTO>> getMerchantsList() {
    List<MerchantDTO> list = StreamSupport.stream(merchantRepository.findAll().spliterator(), false)
            .map(mapper::toDTO)
            .collect(Collectors.toList());
    return ResponseEntity.ok(list);
}

Note that the code would be simpler if your findAll() method returned a List instead of an Iterable. You could just use findAll().stream() to get a stream.

At the client-side, you're doing the same mistake. You want the response body to be an array of merchants, to populate the dropdown list. But you're using an Observable<Merchant>. You need an Observable<Array<Merchant>>. And passing an empty options object to get() is useless:

getList(): Observable<Array<Merchant>> {
  return this.http.get<Array<Merchant>>(environment.api.urls.merchants.base);
}

Finally, you're lying to yourself by creating a class. HttpClient will never create an instance of your class. It doesn't know about it, and simply parsed the JSON it receives to plain old JavaScript objects. So you should really define an interface, not a class:

export interface Merchant {
  id: string;
  name: string;
  state_raw: string;
  users: string;
}

You should really use Spring-data-jpa, too. It would simplify your repositories a lot.

Upvotes: 2

Related Questions