add api utils
This commit is contained in:
parent
ee3ac34e4b
commit
bdd90b50d9
6 changed files with 99 additions and 93 deletions
|
|
@ -1,10 +1,11 @@
|
||||||
import type { Recipe } from "../types/recipe"
|
import type { Recipe } from "../types/recipe"
|
||||||
|
import { get, postJson, putJson } from "./utils/requests";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Util for handling the recipe api
|
* Util for handling the recipe api
|
||||||
*/
|
*/
|
||||||
// reate base url from .env file
|
// read base url from .env file
|
||||||
const BASE_URL = import.meta.env.VITE_API_BASE;
|
const BASE_URL = import.meta.env.VITE_API_BASE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -18,10 +19,7 @@ const RECIPE_URL = `${BASE_URL}/recipe`
|
||||||
* @returns A single recipe
|
* @returns A single recipe
|
||||||
*/
|
*/
|
||||||
export async function fetchRecipe(id: string): Promise<Recipe> {
|
export async function fetchRecipe(id: string): Promise<Recipe> {
|
||||||
const res = await fetch(`${RECIPE_URL}/${id}`)
|
const res = await get(`${RECIPE_URL}/${id}`)
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`Failed to fetch recipe with id ${id}`)
|
|
||||||
}
|
|
||||||
return res.json()
|
return res.json()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,12 +34,8 @@ export async function fetchRecipeList(searchString : string): Promise<Recipe[]>
|
||||||
if(searchString && searchString !== ""){
|
if(searchString && searchString !== ""){
|
||||||
url +="?search=" + searchString;
|
url +="?search=" + searchString;
|
||||||
}
|
}
|
||||||
console.log("calling url", url)
|
const res = await get(url);
|
||||||
const res = await fetch(url)
|
return res.json();
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`Failed to fetch recipe list`)
|
|
||||||
}
|
|
||||||
return res.json()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -50,15 +44,8 @@ export async function fetchRecipeList(searchString : string): Promise<Recipe[]>
|
||||||
* @returns Saved recipe
|
* @returns Saved recipe
|
||||||
*/
|
*/
|
||||||
export async function createRecipe(recipe: Recipe): Promise<Recipe> {
|
export async function createRecipe(recipe: Recipe): Promise<Recipe> {
|
||||||
const res = await fetch(RECIPE_URL, {
|
const res = await postJson(RECIPE_URL, JSON.stringify(recipe));
|
||||||
method: "POST",
|
return res.json();
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify(recipe),
|
|
||||||
})
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error("Failed to create recipe")
|
|
||||||
}
|
|
||||||
return res.json()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -67,13 +54,6 @@ export async function createRecipe(recipe: Recipe): Promise<Recipe> {
|
||||||
* @returns Saved recipe
|
* @returns Saved recipe
|
||||||
*/
|
*/
|
||||||
export async function updateRecipe(recipe: Recipe): Promise<Recipe> {
|
export async function updateRecipe(recipe: Recipe): Promise<Recipe> {
|
||||||
const res = await fetch(`${RECIPE_URL}/${recipe.id}`, {
|
const res = await putJson(`${RECIPE_URL}/${recipe.id}`, JSON.stringify(recipe));
|
||||||
method: "PUT",
|
return res.json();
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify(recipe),
|
|
||||||
})
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`Failed to update recipe with id ${recipe.id}`)
|
|
||||||
}
|
|
||||||
return res.json()
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
frontend/src/api/utils/headers.ts
Normal file
19
frontend/src/api/utils/headers.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
export function setContentTypeHeaderJson(headers: Headers){
|
||||||
|
return headers.set("Content-Type", "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setAuthHeader(headers: Headers){
|
||||||
|
// retrieve session data from browser storage
|
||||||
|
const sessionStr = localStorage.getItem("session");
|
||||||
|
let loginResponse = null;
|
||||||
|
if(sessionStr){
|
||||||
|
loginResponse = JSON.parse(sessionStr);
|
||||||
|
}
|
||||||
|
// add token if possible
|
||||||
|
if(loginResponse && loginResponse.token){
|
||||||
|
headers.set("Authorization", "Bearer " + loginResponse.token)
|
||||||
|
} else {
|
||||||
|
console.log("No access token!")
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
42
frontend/src/api/utils/requests.ts
Normal file
42
frontend/src/api/utils/requests.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { setAuthHeader, setContentTypeHeaderJson } from "./headers";
|
||||||
|
|
||||||
|
export async function get(url: string) : Promise<Response>{
|
||||||
|
const requestHeaders = new Headers();
|
||||||
|
setAuthHeader(requestHeaders);
|
||||||
|
console.log("GET to " + url);
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "GET",
|
||||||
|
headers: requestHeaders
|
||||||
|
})
|
||||||
|
if(!response.ok){
|
||||||
|
throw new Error("GET to " + url + "failed!")
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function postJson(url: string, requestBody: string, logBody = true) : Promise<Response>{
|
||||||
|
console.log("POST to " + url + (logBody) ? "with body " + requestBody : "");
|
||||||
|
return persistJson(url, requestBody, "POST");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function putJson(url: string, requestBody: string, logBody = true) : Promise<Response>{
|
||||||
|
console.log("PUT to " + url + (logBody) ? "with body " + requestBody : "");
|
||||||
|
return persistJson(url, requestBody, "PUT");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function persistJson(url: string, requestBody: string, requestMethod: string) : Promise<Response>{
|
||||||
|
const requestHeaders = new Headers();
|
||||||
|
setContentTypeHeaderJson(requestHeaders);
|
||||||
|
setAuthHeader(requestHeaders);
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: requestMethod,
|
||||||
|
headers: requestHeaders,
|
||||||
|
body: requestBody,
|
||||||
|
});
|
||||||
|
if(!response.ok){
|
||||||
|
throw new Error(requestMethod + " to " + url + "failed!")
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { Link, type LinkProps } from "react-router-dom"
|
||||||
|
import { ButtonType } from "./Button"
|
||||||
|
|
||||||
|
type ButtonLinkProps = LinkProps & {
|
||||||
|
text: string
|
||||||
|
buttonType?: ButtonType
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link component having the same stile as the button
|
||||||
|
*/
|
||||||
|
export default function ButtonLink({
|
||||||
|
to,
|
||||||
|
text,
|
||||||
|
buttonType = ButtonType.DefaultButton,
|
||||||
|
className = "",
|
||||||
|
...props
|
||||||
|
}: ButtonLinkProps) {
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
to={to}
|
||||||
|
className={`basic-button ${buttonType.backgroundColor} ${buttonType.textColor} ${className}`}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -135,7 +135,6 @@ export default function RecipeDetailPage() {
|
||||||
text="Zurueck"
|
text="Zurueck"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
import type { Recipe } from "../types/recipe"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mock data set with some sample recipes.
|
|
||||||
* In a real application, this would be fetched from a backend.
|
|
||||||
*/
|
|
||||||
export const recipes: Recipe[] = [
|
|
||||||
{
|
|
||||||
id: "1",
|
|
||||||
title: "Spaghetti Bolognese",
|
|
||||||
servings: { amount: 1, unit: "Person"},
|
|
||||||
ingredientGroupList: [
|
|
||||||
{
|
|
||||||
ingredientList: [
|
|
||||||
{ name: "Spaghetti", amount: 200, unit: "g" },
|
|
||||||
{ name: "Ground Beef", amount: 300, unit: "g" },
|
|
||||||
{ name: "Tomato Sauce", amount: 400, unit: "ml" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
instructions: "Cook pasta. Prepare sauce. Mix together. Serve hot.",
|
|
||||||
//imageUrl: "https://source.unsplash.com/400x300/?spaghetti"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "2",
|
|
||||||
title: "Spaghetti Carbonara",
|
|
||||||
servings: { amount: 4, unit: "Persons"},
|
|
||||||
ingredientGroupList: [
|
|
||||||
{
|
|
||||||
ingredientList:[
|
|
||||||
{ name: "Spaghetti", amount: 500, unit: "g" },
|
|
||||||
{ name: "Bacon", amount: 150, unit: "g" },
|
|
||||||
{ name: "Cream", amount: 200, unit: "ml" },
|
|
||||||
{ name: "Onion", amount: 1},
|
|
||||||
{ name: "Parmesan cheese", amount: 200, unit: "g"},
|
|
||||||
{ name: "Olives", amount: 100, unit: "g"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
instructions: "Cook pasta. Prepare sauce. Mix together. Serve hot.",
|
|
||||||
//imageUrl: "https://source.unsplash.com/400x300/?spaghetti"
|
|
||||||
},
|
|
||||||
{ id: "3",
|
|
||||||
title: "Apfelkuchen Edeltrud",
|
|
||||||
servings: { amount: 1, unit: "Kuchen"},
|
|
||||||
ingredientGroupList:[
|
|
||||||
{
|
|
||||||
title: "Fuer den Teig",
|
|
||||||
ingredientList: [
|
|
||||||
{ name: "Mehl", amount: 400, unit: "g" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Fuer die Fuellung",
|
|
||||||
ingredientList:[
|
|
||||||
{name: "Aepfel", amount: 4},
|
|
||||||
{name: "Rosinen", amount: 1, unit: "Hand voll"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
instructions: "Einen Muerbteig von 400 g Mehl zubereiten"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue