From f7455019c3764dd4ff1484cafce673e673e5d8f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Bu=C3=9Fmann?= Date: Tue, 12 Jul 2022 17:24:57 +0200 Subject: [PATCH 1/4] [WIP] Reworked the way the spoonaccular api response gets consumed - Added pojos for jackson - Filtering unneeded information from spoonaccular response --- .env.example | 3 + .gitignore | 4 + .../main/spoonaccular/RecipeInformation.java | 40 +++++ .../src/main/spoonaccular/RecipeSearch.java | 57 +++++++ .../ExtendedRecipeByIngredient.java | 59 +++++++ .../MissedIngredient.java | 29 ++++ .../RecipeByIngredient.java | 108 +++++++++++++ .../recipe_by_ingredient/UsedIngredient.java | 29 ++++ .../ExtendedIngredient.java | 42 +++++ .../models/recipe_information/Measures.java | 31 ++++ .../models/recipe_information/Metric.java | 42 +++++ .../models/recipe_information/Recipe.java | 150 ++++++++++++++++++ backend/src/main/whattocook/Application.java | 2 +- .../Controller/SpoonacularController.java | 49 ------ .../controller/SpoonacularController.java | 52 ++++++ .../SpoonacularApiServiceImpl.java | 86 ---------- .../services/SpoonacularApiService.java | 13 -- build.gradle | 4 +- 18 files changed, 650 insertions(+), 150 deletions(-) create mode 100644 .env.example create mode 100644 backend/src/main/spoonaccular/RecipeInformation.java create mode 100644 backend/src/main/spoonaccular/RecipeSearch.java create mode 100644 backend/src/main/spoonaccular/models/recipe_by_ingredient/ExtendedRecipeByIngredient.java create mode 100644 backend/src/main/spoonaccular/models/recipe_by_ingredient/MissedIngredient.java create mode 100644 backend/src/main/spoonaccular/models/recipe_by_ingredient/RecipeByIngredient.java create mode 100644 backend/src/main/spoonaccular/models/recipe_by_ingredient/UsedIngredient.java create mode 100644 backend/src/main/spoonaccular/models/recipe_information/ExtendedIngredient.java create mode 100644 backend/src/main/spoonaccular/models/recipe_information/Measures.java create mode 100644 backend/src/main/spoonaccular/models/recipe_information/Metric.java create mode 100644 backend/src/main/spoonaccular/models/recipe_information/Recipe.java delete mode 100644 backend/src/main/whattocook/Controller/SpoonacularController.java create mode 100644 backend/src/main/whattocook/controller/SpoonacularController.java delete mode 100644 backend/src/main/whattocook/implementation/SpoonacularApiServiceImpl.java delete mode 100644 backend/src/main/whattocook/services/SpoonacularApiService.java diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0c0af2c --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +SPOONACCULAR_API_URL= +SPOONACCULAR_API_KEY= +SPOONACCULAR_API_SEARCH_RANKING= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0e580e5..ef5a5f4 100644 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,7 @@ out !gradle/wrapper/gradle-wrapper.jar frontend/src/index.js + +.env + +.DS_Store diff --git a/backend/src/main/spoonaccular/RecipeInformation.java b/backend/src/main/spoonaccular/RecipeInformation.java new file mode 100644 index 0000000..812e874 --- /dev/null +++ b/backend/src/main/spoonaccular/RecipeInformation.java @@ -0,0 +1,40 @@ +package spoonaccular; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.cdimascio.dotenv.Dotenv; +import org.springframework.stereotype.Component; +import spoonaccular.models.recipe_by_ingredient.ExtendedRecipeByIngredient; +import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient; +import spoonaccular.models.recipe_information.Recipe; + +import java.io.IOException; +import java.net.URL; + +@Component +public class RecipeInformation { + + private final Dotenv dotenv; + + public RecipeInformation(){ + dotenv = Dotenv.load(); + } + + public Recipe getRecipeFromId(int id) throws IOException { + String urlString = dotenv.get("SPOONACCULAR_API_URL") + "/recipes/" + id + "/information?apiKey="+dotenv.get("SPOONACCULAR_API_KEY")+"&includeNutrition=false"; + URL url = new URL(urlString); + return new ObjectMapper().readValue(url, Recipe.class); + } + + public ExtendedRecipeByIngredient getExtendedRecipeFromId(int id) throws IOException { + String urlString = dotenv.get("SPOONACCULAR_API_URL") + "/recipes/" + id + "/information?apiKey="+dotenv.get("SPOONACCULAR_API_KEY")+"&includeNutrition=false"; + URL url = new URL(urlString); + return new ObjectMapper().readValue(url, ExtendedRecipeByIngredient.class); + } + + public ExtendedRecipeByIngredient getRecepieByIngredientsExtended(RecipeByIngredient recipeByIngredient) throws IOException { + ExtendedRecipeByIngredient extendedRecipeByIngredient = getExtendedRecipeFromId(recipeByIngredient.getId()); + extendedRecipeByIngredient.setMissedIngredients(recipeByIngredient.getMissedIngredients()); + return extendedRecipeByIngredient; + } + +} diff --git a/backend/src/main/spoonaccular/RecipeSearch.java b/backend/src/main/spoonaccular/RecipeSearch.java new file mode 100644 index 0000000..970a5e8 --- /dev/null +++ b/backend/src/main/spoonaccular/RecipeSearch.java @@ -0,0 +1,57 @@ +package spoonaccular; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.cdimascio.dotenv.Dotenv; +import org.json.JSONException; +import org.json.JSONObject; +import org.springframework.stereotype.Component; +import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient; +import spoonaccular.models.recipe_information.Recipe; +import whattocook.models.Item; + +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; + +@Component +public class RecipeSearch { + private static final boolean IGNOREPANTRY = true; + + private final Random rnd; + private final Dotenv dotenv; + + public RecipeSearch(){ + rnd = new Random(); + dotenv = Dotenv.load(); + } + + public RecipeByIngredient[] getForIngridients(Iterable items, int number) throws java.io.IOException { + List itemNames = new LinkedList<>(); + items.forEach(item -> itemNames.add(item.getName())); + String ingridients = String.join(",", itemNames); + String urlString = dotenv.get("SPOONACCULAR_API_URL") + "/recipes/findByIngredients?apiKey=" + dotenv.get("SPOONACCULAR_API_KEY") + "&ingredients=" + ingridients + "&ranking=" + dotenv.get("SPOONACCULAR_API_SEARCH_RANKING") + "&ignorePantry=" + IGNOREPANTRY + "&number=" + number; + URL url = new URL(urlString); + return new ObjectMapper().readValue(url, RecipeByIngredient[].class); + } + + public RecipeByIngredient getOneForIngridients(Iterable items, int number) throws IOException { + return getForIngridients(items, number)[rnd.nextInt(number)]; + } + + public Recipe[] getRandom(List tags, int number) throws java.io.IOException, InterruptedException, JSONException { + String tagString = String.join(",", tags); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(dotenv.get("SPOONACCULAR_API_URL") + "/recipes/random?apiKey=" + dotenv.get("SPOONACCULAR_API_KEY") + "&number=" + number + "&tags=" + tagString)) + .method("GET", HttpRequest.BodyPublishers.noBody()) + .build(); + HttpResponse response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); + JSONObject jsonObject = new JSONObject(response.body()); + return new ObjectMapper().readValue(jsonObject.getJSONArray("recipes").toString(), Recipe[].class); + } +} diff --git a/backend/src/main/spoonaccular/models/recipe_by_ingredient/ExtendedRecipeByIngredient.java b/backend/src/main/spoonaccular/models/recipe_by_ingredient/ExtendedRecipeByIngredient.java new file mode 100644 index 0000000..d423728 --- /dev/null +++ b/backend/src/main/spoonaccular/models/recipe_by_ingredient/ExtendedRecipeByIngredient.java @@ -0,0 +1,59 @@ +package spoonaccular.models.recipe_by_ingredient; + +import com.fasterxml.jackson.annotation.JsonProperty; +import spoonaccular.models.recipe_information.Recipe; + +import java.util.List; + +public class ExtendedRecipeByIngredient extends Recipe { + + @JsonProperty("usedIngredientCount") + private Integer usedIngredientCount; + @JsonProperty("missedIngredientCount") + private Integer missedIngredientCount; + @JsonProperty("missedIngredients") + private List missedIngredients = null; + @JsonProperty("usedIngredients") + private List usedIngredients = null; + + @JsonProperty("usedIngredientCount") + public Integer getUsedIngredientCount() { + return usedIngredientCount; + } + + @JsonProperty("usedIngredientCount") + public void setUsedIngredientCount(Integer usedIngredientCount) { + this.usedIngredientCount = usedIngredientCount; + } + + @JsonProperty("missedIngredientCount") + public Integer getMissedIngredientCount() { + return missedIngredientCount; + } + + @JsonProperty("missedIngredientCount") + public void setMissedIngredientCount(Integer missedIngredientCount) { + this.missedIngredientCount = missedIngredientCount; + } + + @JsonProperty("missedIngredients") + public List getMissedIngredients() { + return missedIngredients; + } + + @JsonProperty("missedIngredients") + public void setMissedIngredients(List missedIngredients) { + this.missedIngredients = missedIngredients; + } + + @JsonProperty("usedIngredients") + public List getUsedIngredients() { + return usedIngredients; + } + + @JsonProperty("usedIngredients") + public void setUsedIngredients(List usedIngredients) { + this.usedIngredients = usedIngredients; + } + +} diff --git a/backend/src/main/spoonaccular/models/recipe_by_ingredient/MissedIngredient.java b/backend/src/main/spoonaccular/models/recipe_by_ingredient/MissedIngredient.java new file mode 100644 index 0000000..cbb953b --- /dev/null +++ b/backend/src/main/spoonaccular/models/recipe_by_ingredient/MissedIngredient.java @@ -0,0 +1,29 @@ + +package spoonaccular.models.recipe_by_ingredient; + +import com.fasterxml.jackson.annotation.*; + +import javax.annotation.Generated; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ + "name" +}) +@Generated("jsonschema2pojo") +public class MissedIngredient { + + @JsonProperty("name") + private String name; + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + +} diff --git a/backend/src/main/spoonaccular/models/recipe_by_ingredient/RecipeByIngredient.java b/backend/src/main/spoonaccular/models/recipe_by_ingredient/RecipeByIngredient.java new file mode 100644 index 0000000..1249f5c --- /dev/null +++ b/backend/src/main/spoonaccular/models/recipe_by_ingredient/RecipeByIngredient.java @@ -0,0 +1,108 @@ + +package spoonaccular.models.recipe_by_ingredient; + +import com.fasterxml.jackson.annotation.*; + +import javax.annotation.Generated; +import java.util.List; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ + "id", + "title", + "image", + "usedIngredientCount", + "missedIngredientCount", + "missedIngredients", + "usedIngredients", +}) +@Generated("jsonschema2pojo") +public class RecipeByIngredient { + + @JsonProperty("id") + private Integer id; + @JsonProperty("title") + private String title; + @JsonProperty("image") + private String image; + @JsonProperty("usedIngredientCount") + private Integer usedIngredientCount; + @JsonProperty("missedIngredientCount") + private Integer missedIngredientCount; + @JsonProperty("missedIngredients") + private List missedIngredients = null; + @JsonProperty("usedIngredients") + private List usedIngredients = null; + + @JsonProperty("id") + public Integer getId() { + return id; + } + + @JsonProperty("id") + public void setId(Integer id) { + this.id = id; + } + + @JsonProperty("title") + public String getTitle() { + return title; + } + + @JsonProperty("title") + public void setTitle(String title) { + this.title = title; + } + + @JsonProperty("image") + public String getImage() { + return image; + } + + @JsonProperty("image") + public void setImage(String image) { + this.image = image; + } + + @JsonProperty("usedIngredientCount") + public Integer getUsedIngredientCount() { + return usedIngredientCount; + } + + @JsonProperty("usedIngredientCount") + public void setUsedIngredientCount(Integer usedIngredientCount) { + this.usedIngredientCount = usedIngredientCount; + } + + @JsonProperty("missedIngredientCount") + public Integer getMissedIngredientCount() { + return missedIngredientCount; + } + + @JsonProperty("missedIngredientCount") + public void setMissedIngredientCount(Integer missedIngredientCount) { + this.missedIngredientCount = missedIngredientCount; + } + + @JsonProperty("missedIngredients") + public List getMissedIngredients() { + return missedIngredients; + } + + @JsonProperty("missedIngredients") + public void setMissedIngredients(List missedIngredients) { + this.missedIngredients = missedIngredients; + } + + @JsonProperty("usedIngredients") + public List getUsedIngredients() { + return usedIngredients; + } + + @JsonProperty("usedIngredients") + public void setUsedIngredients(List usedIngredients) { + this.usedIngredients = usedIngredients; + } + +} diff --git a/backend/src/main/spoonaccular/models/recipe_by_ingredient/UsedIngredient.java b/backend/src/main/spoonaccular/models/recipe_by_ingredient/UsedIngredient.java new file mode 100644 index 0000000..c3f20d5 --- /dev/null +++ b/backend/src/main/spoonaccular/models/recipe_by_ingredient/UsedIngredient.java @@ -0,0 +1,29 @@ + +package spoonaccular.models.recipe_by_ingredient; + +import com.fasterxml.jackson.annotation.*; + +import javax.annotation.Generated; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ + "name" +}) +@Generated("jsonschema2pojo") +public class UsedIngredient { + + @JsonProperty("name") + private String name; + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + +} diff --git a/backend/src/main/spoonaccular/models/recipe_information/ExtendedIngredient.java b/backend/src/main/spoonaccular/models/recipe_information/ExtendedIngredient.java new file mode 100644 index 0000000..6b2aa58 --- /dev/null +++ b/backend/src/main/spoonaccular/models/recipe_information/ExtendedIngredient.java @@ -0,0 +1,42 @@ + +package spoonaccular.models.recipe_information; + +import javax.annotation.Generated; + +import com.fasterxml.jackson.annotation.*; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ + "name", + "measures" +}) +@Generated("jsonschema2pojo") +public class ExtendedIngredient { + + @JsonProperty("name") + private String name; + @JsonProperty("measures") + private Measures measures; + + @JsonProperty("name") + public String getName() { + return name; + } + + @JsonProperty("name") + public void setName(String name) { + this.name = name; + } + + @JsonProperty("measures") + public Measures getMeasures() { + return measures; + } + + @JsonProperty("measures") + public void setMeasures(Measures measures) { + this.measures = measures; + } + +} diff --git a/backend/src/main/spoonaccular/models/recipe_information/Measures.java b/backend/src/main/spoonaccular/models/recipe_information/Measures.java new file mode 100644 index 0000000..960f417 --- /dev/null +++ b/backend/src/main/spoonaccular/models/recipe_information/Measures.java @@ -0,0 +1,31 @@ + +package spoonaccular.models.recipe_information; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; + +import com.fasterxml.jackson.annotation.*; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ + "metric" +}) +@Generated("jsonschema2pojo") +public class Measures { + + @JsonProperty("metric") + private Metric metric; + + @JsonProperty("metric") + public Metric getMetric() { + return metric; + } + + @JsonProperty("metric") + public void setMetric(Metric metric) { + this.metric = metric; + } + +} diff --git a/backend/src/main/spoonaccular/models/recipe_information/Metric.java b/backend/src/main/spoonaccular/models/recipe_information/Metric.java new file mode 100644 index 0000000..8443e22 --- /dev/null +++ b/backend/src/main/spoonaccular/models/recipe_information/Metric.java @@ -0,0 +1,42 @@ + +package spoonaccular.models.recipe_information; + +import javax.annotation.Generated; + +import com.fasterxml.jackson.annotation.*; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ + "amount", + "unitShort" +}) +@Generated("jsonschema2pojo") +public class Metric { + + @JsonProperty("amount") + private Double amount; + @JsonProperty("unitShort") + private String unitShort; + + @JsonProperty("amount") + public Double getAmount() { + return amount; + } + + @JsonProperty("amount") + public void setAmount(Double amount) { + this.amount = amount; + } + + @JsonProperty("unitShort") + public String getUnitShort() { + return unitShort; + } + + @JsonProperty("unitShort") + public void setUnitShort(String unitShort) { + this.unitShort = unitShort; + } + +} diff --git a/backend/src/main/spoonaccular/models/recipe_information/Recipe.java b/backend/src/main/spoonaccular/models/recipe_information/Recipe.java new file mode 100644 index 0000000..130a869 --- /dev/null +++ b/backend/src/main/spoonaccular/models/recipe_information/Recipe.java @@ -0,0 +1,150 @@ + +package spoonaccular.models.recipe_information; + +import java.util.List; +import javax.annotation.Generated; + +import com.fasterxml.jackson.annotation.*; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonPropertyOrder({ + "vegetarian", + "vegan", + "glutenFree", + "dairyFree", + "extendedIngredients", + "id", + "title", + "readyInMinutes", + "servings", + "image", + "spoonacularSourceUrl" +}) +@Generated("jsonschema2pojo") +public class Recipe { + + @JsonProperty("vegetarian") + private Boolean vegetarian; + @JsonProperty("vegan") + private Boolean vegan; + @JsonProperty("glutenFree") + private Boolean glutenFree; + @JsonProperty("dairyFree") + private Boolean diaryFree; + @JsonProperty("extendedIngredients") + private List extendedIngredients = null; + @JsonProperty("id") + private Integer id; + @JsonProperty("title") + private String title; + @JsonProperty("readyInMinutes") + private Integer readyInMinutes; + @JsonProperty("servings") + private Integer servings; + @JsonProperty("image") + private String image; + @JsonProperty("spoonacularSourceUrl") + private String spoonacularSourceUrl; + + @JsonProperty("vegetarian") + public Boolean getVegetarian() { + return vegetarian; + } + + @JsonProperty("vegetarian") + public void setVegetarian(Boolean vegetarian) { + this.vegetarian = vegetarian; + } + + @JsonProperty("vegan") + public Boolean getVegan() { + return vegan; + } + + @JsonProperty("vegan") + public void setVegan(Boolean vegan) { + this.vegan = vegan; + } + + @JsonProperty("glutenFree") + public Boolean getGlutenFree() { + return glutenFree; + } + + @JsonProperty("glutenFree") + public void setGlutenFree(Boolean glutenFree) { + this.glutenFree = glutenFree; + } + + @JsonProperty("extendedIngredients") + public List getExtendedIngredients() { + return extendedIngredients; + } + + @JsonProperty("extendedIngredients") + public void setExtendedIngredients(List extendedIngredients) { + this.extendedIngredients = extendedIngredients; + } + + @JsonProperty("id") + public Integer getId() { + return id; + } + + @JsonProperty("id") + public void setId(Integer id) { + this.id = id; + } + + @JsonProperty("title") + public String getTitle() { + return title; + } + + @JsonProperty("title") + public void setTitle(String title) { + this.title = title; + } + + @JsonProperty("readyInMinutes") + public Integer getReadyInMinutes() { + return readyInMinutes; + } + + @JsonProperty("readyInMinutes") + public void setReadyInMinutes(Integer readyInMinutes) { + this.readyInMinutes = readyInMinutes; + } + + @JsonProperty("servings") + public Integer getServings() { + return servings; + } + + @JsonProperty("servings") + public void setServings(Integer servings) { + this.servings = servings; + } + + @JsonProperty("image") + public String getImage() { + return image; + } + + @JsonProperty("image") + public void setImage(String image) { + this.image = image; + } + + @JsonProperty("spoonacularSourceUrl") + public String getSpoonacularSourceUrl() { + return spoonacularSourceUrl; + } + + @JsonProperty("spoonacularSourceUrl") + public void setSpoonacularSourceUrl(String spoonacularSourceUrl) { + this.spoonacularSourceUrl = spoonacularSourceUrl; + } + +} diff --git a/backend/src/main/whattocook/Application.java b/backend/src/main/whattocook/Application.java index e6c2f04..51ce46f 100644 --- a/backend/src/main/whattocook/Application.java +++ b/backend/src/main/whattocook/Application.java @@ -11,7 +11,7 @@ import org.springframework.web.filter.CorsFilter; import java.util.Collections; -@SpringBootApplication +@SpringBootApplication(scanBasePackages = {"spoonaccular", "whattocook"}) public class Application { public static void main(String[] args) { diff --git a/backend/src/main/whattocook/Controller/SpoonacularController.java b/backend/src/main/whattocook/Controller/SpoonacularController.java deleted file mode 100644 index bfbf3f7..0000000 --- a/backend/src/main/whattocook/Controller/SpoonacularController.java +++ /dev/null @@ -1,49 +0,0 @@ -package whattocook.Controller; - - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpEntity; - -import org.springframework.web.bind.annotation.GetMapping; - -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import whattocook.services.SpoonacularApiService; -import whattocook.repositories.ItemRepository; - -import java.io.IOException; -import java.util.LinkedList; - -@RestController -@RequestMapping("/recipes") -public class SpoonacularController { - private int nextRecepies=10; - private int nextRecepiesForOneRandom=20; - @Autowired - private ItemRepository itemRepository; - @Autowired - private SpoonacularApiService service; - - @GetMapping("/forFridge") - public HttpEntity getForFridge() throws IOException, InterruptedException, JSONException { - return new HttpEntity(service.getForIngridients(itemRepository.findAll(), nextRecepies)); - } - - @GetMapping("/random") - public HttpEntity getRandom() throws IOException, InterruptedException, JSONException { - return new HttpEntity(service.getRandom(new LinkedList<>(), nextRecepies)); - //when user has food preferences apply instead of linked list. - } - - @GetMapping("/oneFridge") - public HttpEntity getOneFridge() throws IOException, InterruptedException, JSONException { - return new HttpEntity(service.getOneForIngridients(itemRepository.findAll(), nextRecepiesForOneRandom)); - } - - public void setNextRecepies(int nextRecepies) { - this.nextRecepies = nextRecepies; - } -} diff --git a/backend/src/main/whattocook/controller/SpoonacularController.java b/backend/src/main/whattocook/controller/SpoonacularController.java new file mode 100644 index 0000000..b517559 --- /dev/null +++ b/backend/src/main/whattocook/controller/SpoonacularController.java @@ -0,0 +1,52 @@ +package whattocook.controller; + +import org.json.JSONException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import spoonaccular.RecipeInformation; +import spoonaccular.RecipeSearch; +import spoonaccular.models.recipe_by_ingredient.ExtendedRecipeByIngredient; +import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient; +import spoonaccular.models.recipe_information.Recipe; +import whattocook.repositories.ItemRepository; + +import java.io.IOException; +import java.util.LinkedList; + +@RestController() +@RequestMapping(path = "recipe") +public class SpoonacularController { + private int nextRecepies=10; + private int nextRecepiesForOneRandom=20; + @Autowired + private ItemRepository itemRepository; + @Autowired + private RecipeInformation recipeInformation; + @Autowired + private RecipeSearch recipeSearch; + + @GetMapping("/forFridge") + public RecipeByIngredient[] getForFridge() throws IOException { + return recipeSearch.getForIngridients(itemRepository.findAll(), nextRecepies); + } + + @GetMapping("/random") + public Recipe[] getRandom() throws IOException, InterruptedException, JSONException { + return recipeSearch.getRandom(new LinkedList<>(), nextRecepies); + //when user has food preferences apply instead of linked list. + } + + @GetMapping("/oneFridge") + public ExtendedRecipeByIngredient getOneFridge() throws IOException { + RecipeByIngredient recipe = recipeSearch.getOneForIngridients(itemRepository.findAll(), nextRecepiesForOneRandom); + return recipeInformation.getRecepieByIngredientsExtended(recipe); + } + + @GetMapping("/info/{id}") + public Recipe getInfo(@PathVariable int id) throws IOException { + return recipeInformation.getRecipeFromId(id); + } +} diff --git a/backend/src/main/whattocook/implementation/SpoonacularApiServiceImpl.java b/backend/src/main/whattocook/implementation/SpoonacularApiServiceImpl.java deleted file mode 100644 index 557f2cc..0000000 --- a/backend/src/main/whattocook/implementation/SpoonacularApiServiceImpl.java +++ /dev/null @@ -1,86 +0,0 @@ -package whattocook.implementation; - - -import org.springframework.stereotype.Service; -import whattocook.models.Item; -import whattocook.services.SpoonacularApiService; -import org.json.*; - -import java.io.IOException; -import java.net.http.HttpResponse; -import java.net.http.HttpRequest; -import java.net.http.HttpClient; -import java.net.URI; -import java.util.Iterator; -import java.util.Random; - -@Service -public class SpoonacularApiServiceImpl implements SpoonacularApiService { - private final String KEY = "85cc006d508b447a88e659cd748899db"; - private final String RANKING = "2"; - private final boolean IGNOREPANTRY = true; - Random rnd=new Random(); - - public JSONArray getForIngridients(Iterable items, int number) throws java.io.IOException, InterruptedException, JSONException { - Iterator itemIterator = items.iterator(); - if (!itemIterator.hasNext()) { - return getRandom(new java.util.LinkedList(), number); - } else { - String ingridients = itemIterator.next().getName(); - for (Iterator it = itemIterator; it.hasNext(); ) { - Item curryItem = it.next(); - - - ingridients += "," + curryItem.getName(); - } - java.net.http.HttpRequest request = java.net.http.HttpRequest.newBuilder() - .uri(java.net.URI.create("https://api.spoonacular.com/recipes/findByIngredients?apiKey=" + KEY + "&ingredients=" + ingridients + "&ranking=" + RANKING + "&ignorePantry=" + IGNOREPANTRY + "&number=" + number)) - .method("GET", java.net.http.HttpRequest.BodyPublishers.noBody()) - .build(); - java.net.http.HttpResponse response = java.net.http.HttpClient.newHttpClient().send(request, java.net.http.HttpResponse.BodyHandlers.ofString()); - - JSONArray array=new JSONArray(response.body()); - return array; - - - } - } - - @Override - public JSONObject getOneForIngridients(Iterable items, int number) throws IOException, InterruptedException, JSONException { - JSONArray array= getForIngridients(items, number); - - - return array.getJSONObject(rnd.nextInt(20)); - } - - public JSONArray getRandom(java.util.List tags, int number) throws java.io.IOException, InterruptedException, JSONException { - if (tags.isEmpty()) { - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("https://api.spoonacular.com/recipes/random?apiKey=" + KEY + "&number=" + number)) - .method("GET", HttpRequest.BodyPublishers.noBody()) - .build(); - HttpResponse response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); - - JSONArray array=new JSONArray(response.body()); - return array; - - } else { - String tagString = tags.get(0); - for (int i = 1; i < tags.size(); i++) { - tagString += "," + tags.get(i); - } - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create("https://api.spoonacular.com/recipes/random?apiKey=" + KEY + "&number=" + number + "&tags=" + tagString)) - .method("GET", HttpRequest.BodyPublishers.noBody()) - .build(); - HttpResponse response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); - JSONArray array=new JSONArray(response.body()); - return array; - } - } - - - - -} diff --git a/backend/src/main/whattocook/services/SpoonacularApiService.java b/backend/src/main/whattocook/services/SpoonacularApiService.java deleted file mode 100644 index 8e18814..0000000 --- a/backend/src/main/whattocook/services/SpoonacularApiService.java +++ /dev/null @@ -1,13 +0,0 @@ -package whattocook.services; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import whattocook.models.Item; - -public interface SpoonacularApiService { - JSONArray getForIngridients(Iterable items, int number) throws java.io.IOException, InterruptedException, JSONException; - JSONObject getOneForIngridients(Iterable items, int number) throws java.io.IOException, InterruptedException, JSONException; - - JSONArray getRandom(java.util.List tags, int number) throws java.io.IOException, InterruptedException, JSONException; -} diff --git a/build.gradle b/build.gradle index 26ce9e8..244c645 100644 --- a/build.gradle +++ b/build.gradle @@ -29,10 +29,12 @@ dependencies { // https://mvnrepository.com/artifact/com.h2database/h2 implementation group: 'com.h2database', name: 'h2', version: '1.3.148' - //lombok + // lombok compileOnly 'org.projectlombok:lombok:1.18.24' annotationProcessor 'org.projectlombok:lombok:1.18.24' + implementation 'io.github.cdimascio:dotenv-java:2.2.4' + testCompileOnly 'org.projectlombok:lombok:1.18.24' testAnnotationProcessor 'org.projectlombok:lombok:1.18.24' From c5014c4a11c2020e4b127472208be26ba65ac98c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Bu=C3=9Fmann?= Date: Wed, 13 Jul 2022 04:25:40 +0200 Subject: [PATCH 2/4] Finished restructuring and changed way of querying the API --- .../main/spoonaccular/APIAuthentication.java | 20 ++++++ .../main/spoonaccular/RecipeInformation.java | 47 ++++++++++---- .../src/main/spoonaccular/RecipeSearch.java | 61 ++++++++++++------- .../ExtendedRecipeByIngredient.java | 6 ++ .../controller/SpoonacularController.java | 15 ++--- build.gradle | 3 + 6 files changed, 106 insertions(+), 46 deletions(-) create mode 100644 backend/src/main/spoonaccular/APIAuthentication.java diff --git a/backend/src/main/spoonaccular/APIAuthentication.java b/backend/src/main/spoonaccular/APIAuthentication.java new file mode 100644 index 0000000..fd48826 --- /dev/null +++ b/backend/src/main/spoonaccular/APIAuthentication.java @@ -0,0 +1,20 @@ +package spoonaccular; + +import io.github.cdimascio.dotenv.Dotenv; +import okhttp3.Request; + +public class APIAuthentication { + + private static Dotenv dotenv = Dotenv.load(); + + private APIAuthentication(){ + } + + public static Request.Builder addAuthHeaders(Request.Builder builder){ + return builder + .get() + .addHeader("X-RapidAPI-Key", dotenv.get("X-RapidAPI-Key")) + .addHeader("X-RapidAPI-Host", dotenv.get("X-RapidAPI-Host")); + } + +} diff --git a/backend/src/main/spoonaccular/RecipeInformation.java b/backend/src/main/spoonaccular/RecipeInformation.java index 812e874..613dde5 100644 --- a/backend/src/main/spoonaccular/RecipeInformation.java +++ b/backend/src/main/spoonaccular/RecipeInformation.java @@ -1,40 +1,61 @@ package spoonaccular; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import io.github.cdimascio.dotenv.Dotenv; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; import org.springframework.stereotype.Component; import spoonaccular.models.recipe_by_ingredient.ExtendedRecipeByIngredient; import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient; import spoonaccular.models.recipe_information.Recipe; import java.io.IOException; -import java.net.URL; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; @Component public class RecipeInformation { private final Dotenv dotenv; + private final OkHttpClient client; public RecipeInformation(){ dotenv = Dotenv.load(); + client = new OkHttpClient(); } - public Recipe getRecipeFromId(int id) throws IOException { - String urlString = dotenv.get("SPOONACCULAR_API_URL") + "/recipes/" + id + "/information?apiKey="+dotenv.get("SPOONACCULAR_API_KEY")+"&includeNutrition=false"; - URL url = new URL(urlString); - return new ObjectMapper().readValue(url, Recipe.class); + public List getRecipeFromIds(List ids) throws IOException { + String idsString = ids.stream().map(String::valueOf) + .collect(Collectors.joining(",")); + return new ObjectMapper().readValue(queryInformationBulk(idsString).body().string(), new TypeReference<>(){}); } - public ExtendedRecipeByIngredient getExtendedRecipeFromId(int id) throws IOException { - String urlString = dotenv.get("SPOONACCULAR_API_URL") + "/recipes/" + id + "/information?apiKey="+dotenv.get("SPOONACCULAR_API_KEY")+"&includeNutrition=false"; - URL url = new URL(urlString); - return new ObjectMapper().readValue(url, ExtendedRecipeByIngredient.class); + public List getExtendedRecipeFromIds(List ids) throws IOException { + String idsString = ids.stream().map(String::valueOf) + .collect(Collectors.joining(",")); + return new ObjectMapper().readValue(queryInformationBulk(idsString).body().string(), new TypeReference<>() {}); } - public ExtendedRecipeByIngredient getRecepieByIngredientsExtended(RecipeByIngredient recipeByIngredient) throws IOException { - ExtendedRecipeByIngredient extendedRecipeByIngredient = getExtendedRecipeFromId(recipeByIngredient.getId()); - extendedRecipeByIngredient.setMissedIngredients(recipeByIngredient.getMissedIngredients()); - return extendedRecipeByIngredient; + private Response queryInformationBulk(String idsString) throws IOException { + Request request = APIAuthentication.addAuthHeaders(new Request.Builder() + .url("https://" + dotenv.get("X-RapidAPI-Host") + + "/recipes/informationBulk?ids=" + idsString)) + .build(); + return client.newCall(request).execute(); + } + + public List getRecepieByIngredientsExtended(List recipeByIngredients) throws IOException { + List ids = recipeByIngredients.stream().map(RecipeByIngredient::getId).toList(); + List extendedRecipeByIngredients = getExtendedRecipeFromIds(ids); + Iterator recipeByIngredientIterator = recipeByIngredients.iterator(); + Iterator extendedRecipeByIngredientIterator = extendedRecipeByIngredients.iterator(); + while(recipeByIngredientIterator.hasNext() && extendedRecipeByIngredientIterator.hasNext()){ + extendedRecipeByIngredientIterator.next().addMissingInfo(recipeByIngredientIterator.next()); + } + return extendedRecipeByIngredients; } } diff --git a/backend/src/main/spoonaccular/RecipeSearch.java b/backend/src/main/spoonaccular/RecipeSearch.java index 970a5e8..c0ce223 100644 --- a/backend/src/main/spoonaccular/RecipeSearch.java +++ b/backend/src/main/spoonaccular/RecipeSearch.java @@ -1,20 +1,20 @@ package spoonaccular; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import io.github.cdimascio.dotenv.Dotenv; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; import org.json.JSONException; import org.json.JSONObject; import org.springframework.stereotype.Component; +import spoonaccular.models.recipe_by_ingredient.ExtendedRecipeByIngredient; import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient; import spoonaccular.models.recipe_information.Recipe; import whattocook.models.Item; import java.io.IOException; -import java.net.URI; -import java.net.URL; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; import java.util.LinkedList; import java.util.List; import java.util.Random; @@ -25,33 +25,50 @@ public class RecipeSearch { private final Random rnd; private final Dotenv dotenv; + private final RecipeInformation recipeInformation; + + private final OkHttpClient client; public RecipeSearch(){ rnd = new Random(); dotenv = Dotenv.load(); + recipeInformation = new RecipeInformation(); + client = new OkHttpClient(); } - public RecipeByIngredient[] getForIngridients(Iterable items, int number) throws java.io.IOException { + public List getForIngridients(Iterable items, int number) throws java.io.IOException { List itemNames = new LinkedList<>(); items.forEach(item -> itemNames.add(item.getName())); String ingridients = String.join(",", itemNames); - String urlString = dotenv.get("SPOONACCULAR_API_URL") + "/recipes/findByIngredients?apiKey=" + dotenv.get("SPOONACCULAR_API_KEY") + "&ingredients=" + ingridients + "&ranking=" + dotenv.get("SPOONACCULAR_API_SEARCH_RANKING") + "&ignorePantry=" + IGNOREPANTRY + "&number=" + number; - URL url = new URL(urlString); - return new ObjectMapper().readValue(url, RecipeByIngredient[].class); - } - public RecipeByIngredient getOneForIngridients(Iterable items, int number) throws IOException { - return getForIngridients(items, number)[rnd.nextInt(number)]; - } - - public Recipe[] getRandom(List tags, int number) throws java.io.IOException, InterruptedException, JSONException { - String tagString = String.join(",", tags); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(dotenv.get("SPOONACCULAR_API_URL") + "/recipes/random?apiKey=" + dotenv.get("SPOONACCULAR_API_KEY") + "&number=" + number + "&tags=" + tagString)) - .method("GET", HttpRequest.BodyPublishers.noBody()) + Request request = + APIAuthentication.addAuthHeaders(new Request.Builder() + .url("https://" + dotenv.get("X-RapidAPI-Host") + + "/recipes/findByIngredients?ingredients=" + + ingridients + "&number=" + number + "&ignorePantry=" + + IGNOREPANTRY + "&ranking=" + dotenv.get("X-RapidAPI-SearchRanking"))) .build(); - HttpResponse response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); - JSONObject jsonObject = new JSONObject(response.body()); - return new ObjectMapper().readValue(jsonObject.getJSONArray("recipes").toString(), Recipe[].class); + + Response response = client.newCall(request).execute(); + String responseString = response.body().string(); + + List recipeByIngredients = new ObjectMapper().readValue(responseString, new TypeReference<>(){}); + return recipeInformation.getRecepieByIngredientsExtended(recipeByIngredients); + } + + public ExtendedRecipeByIngredient getOneForIngridients(Iterable items, int number) throws IOException { + return this.getForIngridients(items, number).get(rnd.nextInt(number)); + } + + public List getRandom(List tags, int number) throws java.io.IOException, JSONException { + String tagString = String.join(",", tags); + Request request = APIAuthentication.addAuthHeaders(new Request.Builder() + .url("https://" + dotenv.get("X-RapidAPI-Host") + + "/recipes/random?number=" + number + "&tags=" + tagString)) + .build(); + + Response response = client.newCall(request).execute(); + JSONObject jsonObject = new JSONObject(response.body().string()); + return new ObjectMapper().readValue(jsonObject.getJSONArray("recipes").toString(), new TypeReference<>(){}); } } diff --git a/backend/src/main/spoonaccular/models/recipe_by_ingredient/ExtendedRecipeByIngredient.java b/backend/src/main/spoonaccular/models/recipe_by_ingredient/ExtendedRecipeByIngredient.java index d423728..5377a5d 100644 --- a/backend/src/main/spoonaccular/models/recipe_by_ingredient/ExtendedRecipeByIngredient.java +++ b/backend/src/main/spoonaccular/models/recipe_by_ingredient/ExtendedRecipeByIngredient.java @@ -56,4 +56,10 @@ public class ExtendedRecipeByIngredient extends Recipe { this.usedIngredients = usedIngredients; } + public void addMissingInfo(RecipeByIngredient recipeByIngredient){ + this.setMissedIngredientCount(recipeByIngredient.getMissedIngredientCount()); + this.setUsedIngredientCount(recipeByIngredient.getUsedIngredientCount()); + this.setMissedIngredients(recipeByIngredient.getMissedIngredients()); + this.setUsedIngredients(recipeByIngredient.getUsedIngredients()); + } } diff --git a/backend/src/main/whattocook/controller/SpoonacularController.java b/backend/src/main/whattocook/controller/SpoonacularController.java index b517559..ea63e9d 100644 --- a/backend/src/main/whattocook/controller/SpoonacularController.java +++ b/backend/src/main/whattocook/controller/SpoonacularController.java @@ -3,18 +3,17 @@ package whattocook.controller; import org.json.JSONException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import spoonaccular.RecipeInformation; import spoonaccular.RecipeSearch; import spoonaccular.models.recipe_by_ingredient.ExtendedRecipeByIngredient; -import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient; import spoonaccular.models.recipe_information.Recipe; import whattocook.repositories.ItemRepository; import java.io.IOException; import java.util.LinkedList; +import java.util.List; @RestController() @RequestMapping(path = "recipe") @@ -29,24 +28,18 @@ public class SpoonacularController { private RecipeSearch recipeSearch; @GetMapping("/forFridge") - public RecipeByIngredient[] getForFridge() throws IOException { + public List getForFridge() throws IOException { return recipeSearch.getForIngridients(itemRepository.findAll(), nextRecepies); } @GetMapping("/random") - public Recipe[] getRandom() throws IOException, InterruptedException, JSONException { + public List getRandom() throws IOException, InterruptedException, JSONException { return recipeSearch.getRandom(new LinkedList<>(), nextRecepies); //when user has food preferences apply instead of linked list. } @GetMapping("/oneFridge") public ExtendedRecipeByIngredient getOneFridge() throws IOException { - RecipeByIngredient recipe = recipeSearch.getOneForIngridients(itemRepository.findAll(), nextRecepiesForOneRandom); - return recipeInformation.getRecepieByIngredientsExtended(recipe); - } - - @GetMapping("/info/{id}") - public Recipe getInfo(@PathVariable int id) throws IOException { - return recipeInformation.getRecipeFromId(id); + return recipeSearch.getOneForIngridients(itemRepository.findAll(), nextRecepiesForOneRandom); } } diff --git a/build.gradle b/build.gradle index 244c645..6a8174c 100644 --- a/build.gradle +++ b/build.gradle @@ -29,6 +29,9 @@ dependencies { // https://mvnrepository.com/artifact/com.h2database/h2 implementation group: 'com.h2database', name: 'h2', version: '1.3.148' + // okhttp + implementation("com.squareup.okhttp3:okhttp:4.10.0") + // lombok compileOnly 'org.projectlombok:lombok:1.18.24' annotationProcessor 'org.projectlombok:lombok:1.18.24' From 5c0de10446084fa5827375dc5cca2b3b4f9ad831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Bu=C3=9Fmann?= Date: Wed, 13 Jul 2022 05:58:48 +0200 Subject: [PATCH 3/4] updated paths of SpoonacularController to match the rest --- .../whattocook/controller/SpoonacularController.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/src/main/whattocook/controller/SpoonacularController.java b/backend/src/main/whattocook/controller/SpoonacularController.java index ea63e9d..8fe7fb6 100644 --- a/backend/src/main/whattocook/controller/SpoonacularController.java +++ b/backend/src/main/whattocook/controller/SpoonacularController.java @@ -2,8 +2,8 @@ package whattocook.controller; import org.json.JSONException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.rest.webmvc.BasePathAwareController; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import spoonaccular.RecipeInformation; import spoonaccular.RecipeSearch; @@ -16,7 +16,7 @@ import java.util.LinkedList; import java.util.List; @RestController() -@RequestMapping(path = "recipe") +@BasePathAwareController() public class SpoonacularController { private int nextRecepies=10; private int nextRecepiesForOneRandom=20; @@ -27,18 +27,18 @@ public class SpoonacularController { @Autowired private RecipeSearch recipeSearch; - @GetMapping("/forFridge") + @GetMapping("/recipe/forFridge") public List getForFridge() throws IOException { return recipeSearch.getForIngridients(itemRepository.findAll(), nextRecepies); } - @GetMapping("/random") + @GetMapping("/recipe/random") public List getRandom() throws IOException, InterruptedException, JSONException { return recipeSearch.getRandom(new LinkedList<>(), nextRecepies); //when user has food preferences apply instead of linked list. } - @GetMapping("/oneFridge") + @GetMapping("/recipe/oneFridge") public ExtendedRecipeByIngredient getOneFridge() throws IOException { return recipeSearch.getOneForIngridients(itemRepository.findAll(), nextRecepiesForOneRandom); } From 33fe0e0d792186ac46f42b46d9340d10be92bfad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Bu=C3=9Fmann?= Date: Wed, 13 Jul 2022 15:42:20 +0200 Subject: [PATCH 4/4] Program no longer terminates if .env file is not present (need for testing) --- backend/src/main/spoonaccular/APIAuthentication.java | 2 +- backend/src/main/spoonaccular/RecipeInformation.java | 2 +- backend/src/main/spoonaccular/RecipeSearch.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/main/spoonaccular/APIAuthentication.java b/backend/src/main/spoonaccular/APIAuthentication.java index fd48826..29991a5 100644 --- a/backend/src/main/spoonaccular/APIAuthentication.java +++ b/backend/src/main/spoonaccular/APIAuthentication.java @@ -5,7 +5,7 @@ import okhttp3.Request; public class APIAuthentication { - private static Dotenv dotenv = Dotenv.load(); + private static final Dotenv dotenv = Dotenv.configure().ignoreIfMissing().ignoreIfMalformed().load(); private APIAuthentication(){ } diff --git a/backend/src/main/spoonaccular/RecipeInformation.java b/backend/src/main/spoonaccular/RecipeInformation.java index 613dde5..7fc7a4f 100644 --- a/backend/src/main/spoonaccular/RecipeInformation.java +++ b/backend/src/main/spoonaccular/RecipeInformation.java @@ -23,7 +23,7 @@ public class RecipeInformation { private final OkHttpClient client; public RecipeInformation(){ - dotenv = Dotenv.load(); + dotenv = Dotenv.configure().ignoreIfMissing().ignoreIfMalformed().load(); client = new OkHttpClient(); } diff --git a/backend/src/main/spoonaccular/RecipeSearch.java b/backend/src/main/spoonaccular/RecipeSearch.java index c0ce223..a501623 100644 --- a/backend/src/main/spoonaccular/RecipeSearch.java +++ b/backend/src/main/spoonaccular/RecipeSearch.java @@ -31,7 +31,7 @@ public class RecipeSearch { public RecipeSearch(){ rnd = new Random(); - dotenv = Dotenv.load(); + dotenv = Dotenv.configure().ignoreIfMissing().ignoreIfMalformed().load(); recipeInformation = new RecipeInformation(); client = new OkHttpClient(); }