Finished restructuring and changed way of querying the API

This commit is contained in:
2022-07-13 04:25:40 +02:00
parent f7455019c3
commit c5014c4a11
6 changed files with 106 additions and 46 deletions

View File

@@ -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"));
}
}

View File

@@ -1,40 +1,61 @@
package spoonaccular; package spoonaccular;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.cdimascio.dotenv.Dotenv; import io.github.cdimascio.dotenv.Dotenv;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import spoonaccular.models.recipe_by_ingredient.ExtendedRecipeByIngredient; import spoonaccular.models.recipe_by_ingredient.ExtendedRecipeByIngredient;
import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient; import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient;
import spoonaccular.models.recipe_information.Recipe; import spoonaccular.models.recipe_information.Recipe;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
@Component @Component
public class RecipeInformation { public class RecipeInformation {
private final Dotenv dotenv; private final Dotenv dotenv;
private final OkHttpClient client;
public RecipeInformation(){ public RecipeInformation(){
dotenv = Dotenv.load(); dotenv = Dotenv.load();
client = new OkHttpClient();
} }
public Recipe getRecipeFromId(int id) throws IOException { public List<Recipe> getRecipeFromIds(List<Integer> ids) throws IOException {
String urlString = dotenv.get("SPOONACCULAR_API_URL") + "/recipes/" + id + "/information?apiKey="+dotenv.get("SPOONACCULAR_API_KEY")+"&includeNutrition=false"; String idsString = ids.stream().map(String::valueOf)
URL url = new URL(urlString); .collect(Collectors.joining(","));
return new ObjectMapper().readValue(url, Recipe.class); return new ObjectMapper().readValue(queryInformationBulk(idsString).body().string(), new TypeReference<>(){});
} }
public ExtendedRecipeByIngredient getExtendedRecipeFromId(int id) throws IOException { public List<ExtendedRecipeByIngredient> getExtendedRecipeFromIds(List<Integer> ids) throws IOException {
String urlString = dotenv.get("SPOONACCULAR_API_URL") + "/recipes/" + id + "/information?apiKey="+dotenv.get("SPOONACCULAR_API_KEY")+"&includeNutrition=false"; String idsString = ids.stream().map(String::valueOf)
URL url = new URL(urlString); .collect(Collectors.joining(","));
return new ObjectMapper().readValue(url, ExtendedRecipeByIngredient.class); return new ObjectMapper().readValue(queryInformationBulk(idsString).body().string(), new TypeReference<>() {});
} }
public ExtendedRecipeByIngredient getRecepieByIngredientsExtended(RecipeByIngredient recipeByIngredient) throws IOException { private Response queryInformationBulk(String idsString) throws IOException {
ExtendedRecipeByIngredient extendedRecipeByIngredient = getExtendedRecipeFromId(recipeByIngredient.getId()); Request request = APIAuthentication.addAuthHeaders(new Request.Builder()
extendedRecipeByIngredient.setMissedIngredients(recipeByIngredient.getMissedIngredients()); .url("https://" + dotenv.get("X-RapidAPI-Host") +
return extendedRecipeByIngredient; "/recipes/informationBulk?ids=" + idsString))
.build();
return client.newCall(request).execute();
}
public List<ExtendedRecipeByIngredient> getRecepieByIngredientsExtended(List<RecipeByIngredient> recipeByIngredients) throws IOException {
List<Integer> ids = recipeByIngredients.stream().map(RecipeByIngredient::getId).toList();
List<ExtendedRecipeByIngredient> extendedRecipeByIngredients = getExtendedRecipeFromIds(ids);
Iterator<RecipeByIngredient> recipeByIngredientIterator = recipeByIngredients.iterator();
Iterator<ExtendedRecipeByIngredient> extendedRecipeByIngredientIterator = extendedRecipeByIngredients.iterator();
while(recipeByIngredientIterator.hasNext() && extendedRecipeByIngredientIterator.hasNext()){
extendedRecipeByIngredientIterator.next().addMissingInfo(recipeByIngredientIterator.next());
}
return extendedRecipeByIngredients;
} }
} }

View File

@@ -1,20 +1,20 @@
package spoonaccular; package spoonaccular;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.cdimascio.dotenv.Dotenv; import io.github.cdimascio.dotenv.Dotenv;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import spoonaccular.models.recipe_by_ingredient.ExtendedRecipeByIngredient;
import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient; import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient;
import spoonaccular.models.recipe_information.Recipe; import spoonaccular.models.recipe_information.Recipe;
import whattocook.models.Item; import whattocook.models.Item;
import java.io.IOException; 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.LinkedList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
@@ -25,33 +25,50 @@ public class RecipeSearch {
private final Random rnd; private final Random rnd;
private final Dotenv dotenv; private final Dotenv dotenv;
private final RecipeInformation recipeInformation;
private final OkHttpClient client;
public RecipeSearch(){ public RecipeSearch(){
rnd = new Random(); rnd = new Random();
dotenv = Dotenv.load(); dotenv = Dotenv.load();
recipeInformation = new RecipeInformation();
client = new OkHttpClient();
} }
public RecipeByIngredient[] getForIngridients(Iterable<Item> items, int number) throws java.io.IOException { public List<ExtendedRecipeByIngredient> getForIngridients(Iterable<Item> items, int number) throws java.io.IOException {
List<String> itemNames = new LinkedList<>(); List<String> itemNames = new LinkedList<>();
items.forEach(item -> itemNames.add(item.getName())); items.forEach(item -> itemNames.add(item.getName()));
String ingridients = String.join(",", itemNames); 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<Item> items, int number) throws IOException { Request request =
return getForIngridients(items, number)[rnd.nextInt(number)]; APIAuthentication.addAuthHeaders(new Request.Builder()
} .url("https://" + dotenv.get("X-RapidAPI-Host") +
"/recipes/findByIngredients?ingredients="
public Recipe[] getRandom(List<String> tags, int number) throws java.io.IOException, InterruptedException, JSONException { + ingridients + "&number=" + number + "&ignorePantry="
String tagString = String.join(",", tags); + IGNOREPANTRY + "&ranking=" + dotenv.get("X-RapidAPI-SearchRanking")))
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(); .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
JSONObject jsonObject = new JSONObject(response.body()); Response response = client.newCall(request).execute();
return new ObjectMapper().readValue(jsonObject.getJSONArray("recipes").toString(), Recipe[].class); String responseString = response.body().string();
List<RecipeByIngredient> recipeByIngredients = new ObjectMapper().readValue(responseString, new TypeReference<>(){});
return recipeInformation.getRecepieByIngredientsExtended(recipeByIngredients);
}
public ExtendedRecipeByIngredient getOneForIngridients(Iterable<Item> items, int number) throws IOException {
return this.getForIngridients(items, number).get(rnd.nextInt(number));
}
public List<Recipe> getRandom(List<String> 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<>(){});
} }
} }

View File

@@ -56,4 +56,10 @@ public class ExtendedRecipeByIngredient extends Recipe {
this.usedIngredients = usedIngredients; this.usedIngredients = usedIngredients;
} }
public void addMissingInfo(RecipeByIngredient recipeByIngredient){
this.setMissedIngredientCount(recipeByIngredient.getMissedIngredientCount());
this.setUsedIngredientCount(recipeByIngredient.getUsedIngredientCount());
this.setMissedIngredients(recipeByIngredient.getMissedIngredients());
this.setUsedIngredients(recipeByIngredient.getUsedIngredients());
}
} }

View File

@@ -3,18 +3,17 @@ package whattocook.controller;
import org.json.JSONException; import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; 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.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import spoonaccular.RecipeInformation; import spoonaccular.RecipeInformation;
import spoonaccular.RecipeSearch; import spoonaccular.RecipeSearch;
import spoonaccular.models.recipe_by_ingredient.ExtendedRecipeByIngredient; import spoonaccular.models.recipe_by_ingredient.ExtendedRecipeByIngredient;
import spoonaccular.models.recipe_by_ingredient.RecipeByIngredient;
import spoonaccular.models.recipe_information.Recipe; import spoonaccular.models.recipe_information.Recipe;
import whattocook.repositories.ItemRepository; import whattocook.repositories.ItemRepository;
import java.io.IOException; import java.io.IOException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
@RestController() @RestController()
@RequestMapping(path = "recipe") @RequestMapping(path = "recipe")
@@ -29,24 +28,18 @@ public class SpoonacularController {
private RecipeSearch recipeSearch; private RecipeSearch recipeSearch;
@GetMapping("/forFridge") @GetMapping("/forFridge")
public RecipeByIngredient[] getForFridge() throws IOException { public List<ExtendedRecipeByIngredient> getForFridge() throws IOException {
return recipeSearch.getForIngridients(itemRepository.findAll(), nextRecepies); return recipeSearch.getForIngridients(itemRepository.findAll(), nextRecepies);
} }
@GetMapping("/random") @GetMapping("/random")
public Recipe[] getRandom() throws IOException, InterruptedException, JSONException { public List<Recipe> getRandom() throws IOException, InterruptedException, JSONException {
return recipeSearch.getRandom(new LinkedList<>(), nextRecepies); return recipeSearch.getRandom(new LinkedList<>(), nextRecepies);
//when user has food preferences apply instead of linked list. //when user has food preferences apply instead of linked list.
} }
@GetMapping("/oneFridge") @GetMapping("/oneFridge")
public ExtendedRecipeByIngredient getOneFridge() throws IOException { public ExtendedRecipeByIngredient getOneFridge() throws IOException {
RecipeByIngredient recipe = recipeSearch.getOneForIngridients(itemRepository.findAll(), nextRecepiesForOneRandom); return recipeSearch.getOneForIngridients(itemRepository.findAll(), nextRecepiesForOneRandom);
return recipeInformation.getRecepieByIngredientsExtended(recipe);
}
@GetMapping("/info/{id}")
public Recipe getInfo(@PathVariable int id) throws IOException {
return recipeInformation.getRecipeFromId(id);
} }
} }

View File

@@ -29,6 +29,9 @@ dependencies {
// https://mvnrepository.com/artifact/com.h2database/h2 // https://mvnrepository.com/artifact/com.h2database/h2
implementation group: 'com.h2database', name: 'h2', version: '1.3.148' implementation group: 'com.h2database', name: 'h2', version: '1.3.148'
// okhttp
implementation("com.squareup.okhttp3:okhttp:4.10.0")
// lombok // lombok
compileOnly 'org.projectlombok:lombok:1.18.24' compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24' annotationProcessor 'org.projectlombok:lombok:1.18.24'