0

I'm trying to write a PATCH api method which removes one specific element from a list of items. Note that the list of items is part of the Menu class. There aren't a lot of dropwizard resources out there, so I'm kinda stuck.

Here's all the important pieces of code – https://pastebin.com/Y9mAVZJk

Any help would mean a lot. I am a beginner when it comes to restul apis, but i've grasped the concept of Angular easily. I'm having issues with the backend, especially because it is dropwizard. It has to be dropwizard as it is an assignment, I can't change it to anything else. The databse might come later, but it is as it is right now.

public class Item {

    private String person;
    private String name;
    private Integer quantity;
    private Integer price;


     public Item(String name, int price) {

        this.person = "";
        this.quantity = 0;
        this.name = name;
        this.price = price;
      }

    public Item(String person, String name, int quantity, int price) {

        this.name = name;
        this.person = person;
        this.quantity = quantity;
        this.price = price;
    }

    @JsonProperty
    public String getPerson() {
        return this.person;
    }


    @JsonProperty
    public String getName(){
        return this.name;
    }

    @JsonProperty
    public Integer getQuantity(){
        return this.quantity;
    }

    @JsonProperty
    public Integer getPrice(){
        return this.price;
    }

}
____________________________
public class Menu {

    private Integer id;
    private String name;
    private List<Item> items;

    public Menu() { }

    public Menu(int id, String name, List<Item> items) {
        this.id = id;
        this.name = name;
        this.items = items;
    }


    @JsonProperty
    public List<Item> getItems() {
        return this.items;
    }

    @JsonProperty
    public void setItems(List<Item> items){
        this.items = items;
    }

    @JsonProperty
    public Integer getId() {

        return this.id;
    }

    @JsonProperty
    public String getName() {
        return this.name;
    }

    @JsonProperty
    public void setId(final int id) {
        this.id = id;
    }

    @JsonProperty
    public void setName(final String name) {
        this.name = name;
    }
}
_____________________________

public MenuRepository() {
        this.menus = new HashMap<>();
        for (int i=1; i<9; i++) {
            Item item = new Item("Item " + i, i+200);
            this.items.add(item);
        }

        addNewMenu(new Menu(1, "First Menu", this.items));
        addNewMenu(new Menu(2, "Second Menu", this.items));
        addNewMenu(new Menu(3, "Third Menu", this.items));
        addNewMenu(new Menu(4, "Fourth Menu", this.items));
        addNewMenu(new Menu(5, "Fifth Menu", this.items));
        addNewMenu(new Menu(6, "Sixth Menu", this.items));
        addNewMenu(new Menu(7, "Seventh Menu", this.items));

    }

    private int getNewId() {
        return counter++;
    }
 public Collection<Menu> getAllMenus() {
        return this.menus.values();
    }

    public Menu get(final int id) {
        return this.menus.get(id);
    }

    public Collection<Menu> addNewMenu(final Menu menu) {

        menu.setId(this.getNewId());
        this.menus.put(menu.getId(), menu);
        return this.menus.values();

    } 

    public Collection<Menu> removeMenu(final int id) {
        this.menus.remove(id);
        return this.menus.values();
    }

@Path("/menu")
@Produces(MediaType.APPLICATION_JSON)

public class MenuResource {

    private MenuRepository menuRepository;

    public MenuResource(final MenuRepository menuRepository) {
        this.menuRepository = menuRepository;
    }

    @GET
    @Timed
    public Collection<Menu> getAll() {
        return this.menuRepository.getAllMenus();
    }

    @GET
    @Path("/{id}")
    @Timed
    public Menu get(@PathParam("id") final int id) {


        return this.menuRepository.get(id);
    }

    @POST
    @Timed
    public Collection<Menu> post(final Menu menu) {
        return this.menuRepository.addNewMenu(menu);
    }

    @DELETE
    @Path("/{id}")
    @Timed
    public Collection<Menu> delete(@PathParam("id") final int id) {
        return this.menuRepository.removeMenu(id);
    }

EDIT: Is it possible to get the PATCH method to both add and remove items from the list?

soulzap
  • 69
  • 1
  • 1
  • 7
  • You posted a lot of code, this makes it very hard to find the import parts.Can i recommend you read https://stackoverflow.com/help/mcve and remove the unneeded parts. You will be more likely to get a helpful answer. – ktzr Feb 13 '19 at 20:42
  • Thanks for the suggestion. I've split the pieces of code. It's essentially two classes, one repository and one resource file. I'll take care of that in the future though. – soulzap Feb 13 '19 at 20:55
  • @soulzap see if my answer is what you really want. – LppEdd Feb 13 '19 at 20:58
  • `Is it possible to get PATCH method to both add and remove items from the list`: Patch is a method where you send the server instructions on how to modify the resource so it looks like the client intends. You can basically look at [json-patch](http://jsonpatch.com/) for a syntax and semantical description of the respective elements – Roman Vottner Feb 13 '19 at 21:18
  • Thanks for the response Roman! I've read everything there is out there about the PATCH method. I should have asked my question differently. I know it is possible, as that's what I need to do, but I'm just having trouble doing it with dropwizard. I'd manage it somehow with Spring, as there are a lot more learning resources, references and examples. – soulzap Feb 13 '19 at 21:23

1 Answers1

0

I'm trying to understand your code while writing this answer.

I'd say, first of all, try formatting it a little bit better, as formatted code is easier to read not only for us, but for you.

If I remember correctly, Dropwizard bundles Jersey, which is a JAX-RS implementation. In your resource class, just use the @PATCH annotation to identify the item removal method.

You can get a hold of the List<Item> and remove the element via ListIterator<Item>.

@Path("/menu")
@Produces(MediaType.APPLICATION_JSON)
public class MenuResource {
   ...

   @PATCH
   @Path("/remove/{menuId}/{itemName}")
   public void removeMenuItem(
            @PathParam("menuId") final int menuId,
            @PathParam("itemName") final String itemName) {
      final List<Item> items = this.menuRepository.get(menuId).getItems();

      for (final ListIterator<Item> iterator = items.listIterator(); iterator.hasNext();) {
         final Item item = iterator.next();

         if (itemName.equals(item.getName())) {
            iterator.remove();
            break;
         }
      }
   }

   @PATCH
   @Path("/add/{menuId}")
   public void removeMenuItem(
            @PathParam("menuId") final int menuId,
            final Item item) {  // Item represents the Request Body
      final List<Item> items = this.menuRepository.get(menuId).getItems();
      items.add(item);
   }

Remember to add the @XmlRootElement annotation on the Item class

@XmlRootElement
public class Item { ... }

For the insertion/removal point, I'd say use two different methods.

You can prefix the insertion path with add, e.g. /add/{menuId} and pass the Item via request body. You can then prefix the removal path with remove e.g. /remove/{menuId}/{itemId}

LppEdd
  • 20,274
  • 11
  • 84
  • 139
  • Thanks for the input buddy! Is it possible to make the PATCH method both add new items and remove items from the list? Is there something I need to or create a certain function in the repository file? – soulzap Feb 13 '19 at 21:03
  • here's the thing - I don't have the path/menuId/itemName url. The items are displayed once the url/menuId is loaded. I need to be able to both add new items to the list and remove the existing ones using the PATCH method. It is a food ordering rest api - i've got orders and menus, but i'll implement the PATCH easily for orders once I figure out how to do so in menus. – soulzap Feb 13 '19 at 21:07
  • @soulzap see my edit. Is it sufficient? Rule of thumb, keep things separated, seperation of concerns is important to maintain the code clean. – LppEdd Feb 13 '19 at 21:08
  • Thanks a lot man. The only problem is that I'm not that experienced with Java (not at all, i've worked with c# for a bit in the past but that's it). I'm kinda forced to use dropwizard, and whilst I'm completely done on the front-end, I'm having a lot of trouble in the back. Is there any way you could help me a little bit more with the code? I'm going through what you already posted word by word and it makes sense slowly, but having a reference point for future would mean a world to me. Your answer is getting the check mark and the upvote regardless! People like you keep me going. Thanks a lot. – soulzap Feb 13 '19 at 21:12
  • @soulzap If you have other questions feel free to edit your original question and add them, point by point. Or even post a new question if the subject is not the same. I'll always try to answer. – LppEdd Feb 13 '19 at 21:13
  • I'll try the code out when I get to my machine at the company tomorrow. Could you possibly edit so that I'm able to both add and remove items with patch requests from my front-end? And is this all? I don't have to come up with any additional functions? I've struggled a lot with this, got the get/post/delete part somehow, but this is killing me. – soulzap Feb 13 '19 at 21:19
  • @soulzap see edit. Should be sufficient. Obviously add whatever check you need to ensure the Item object is passed correctly. – LppEdd Feb 13 '19 at 21:23
  • 1
    Trying it out as soon as I get to my PC. Can't thank you enough man. If I run into some troubles I cannot solve myself, I'll comment or post again, but hey - I'm extremely grateful! Cheers! – soulzap Feb 13 '19 at 21:26
  • @soulzap If you can't find the PATCH annotation, let me know, it means you're using a version less then 2.1 of the JAX-RS spec. – LppEdd Feb 13 '19 at 21:29
  • The type DurationRange.List is not generic; it cannot be parameterized with arguments Java(16777740) io.dropwizard.validation.DurationRange.List Defines several @DurationRange annotations on the same element – soulzap Feb 14 '19 at 06:35
  • @soulzap you need java.util.List – LppEdd Feb 14 '19 at 06:39
  • I'll figure that out somehow. For some reason, I can't use the (at)XmlRootElement, even after importing everything needed such as import javax.xml.bind.*; – soulzap Feb 14 '19 at 07:22
  • @soulzap you can try without it! In recent versions of Jersey, if I remember correctly, they made it optional. But it's strange. The packege is javax.xml.bind.annotation. Are you sure you're importing it and using it correctly? – LppEdd Feb 14 '19 at 08:11
  • hey buddy, would you mind taking look at this new issue i've stumbled upon? https://stackoverflow.com/questions/54738121/elements-passed-through-a-form-not-received-by-the-server-nor-displayed-on-the-f – soulzap Feb 17 '19 at 22:18