diff --git a/docker-compose.yml b/docker-compose.yml
index 94ae39bd2ed9ab570b27c46c09777b596bd083e7..9c201e1eda89bbc4304341307a558f88543a87b0 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,14 +1,13 @@
 services:
   meal:
     build: ./service/meal
-    ports:
-      - "9111:9111"
   planner:
     build: ./service/planner
     ports:
       - "8000:8000"
     environment:
       - DB_CONNECT=mariadb:3306
+      - MEAL_CONNECT=meal:9111
       - LOG_LEVEL=info
   mariadb:
     image: mariadb:10.5
diff --git a/go.work.sum b/go.work.sum
new file mode 100644
index 0000000000000000000000000000000000000000..52a48b32c1abb3ea1505ece4723f2ff622335969
--- /dev/null
+++ b/go.work.sum
@@ -0,0 +1,14 @@
+cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE=
+cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
+github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q=
+github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
+github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
diff --git a/service/meal/Dockerfile b/service/meal/Dockerfile
index 82b0691576cb4342f7d9e4d5f04f26af72cfdc08..def529fac70828d5fcb8b92587f87e3ee4e46d1b 100644
--- a/service/meal/Dockerfile
+++ b/service/meal/Dockerfile
@@ -3,7 +3,14 @@ FROM golang:1.20-buster
 WORKDIR /go/src/app
 COPY . /go/src/app
 
+RUN apt update
+RUN apt install -y protobuf-compiler
+
+RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
+RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
+
 RUN go mod download
+RUN go generate ./...
 RUN go install
 
 CMD ["meal"]
diff --git a/service/meal/db/mealdb/client.go b/service/meal/db/mealdb/client.go
index 1796d8e379e955696b52dd32fea50f81743b0173..f6f8923f7611a82133899c5cb04678198a6c6ef2 100644
--- a/service/meal/db/mealdb/client.go
+++ b/service/meal/db/mealdb/client.go
@@ -8,7 +8,7 @@ import (
 	"strconv"
 	"time"
 
-	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/model"
+	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/grpc/meal"
 )
 
 const baseUrl = "https://www.themealdb.com/api/json/v1/1/"
@@ -17,7 +17,7 @@ var client = &http.Client{
 	Timeout: time.Minute,
 }
 
-func GetRandomMeal() (*model.Meal, error) {
+func GetRandomMeal() (*meal.MealResponse, error) {
 	path := "random.php"
 	request, err := http.NewRequest(http.MethodGet, baseUrl+path, nil)
 	if err != nil {
@@ -42,7 +42,7 @@ func GetRandomMeal() (*model.Meal, error) {
 	return createMeal(currentMeal)
 }
 
-func GetMeal(id int) (*model.Meal, error) {
+func GetMeal(id int) (*meal.MealResponse, error) {
 	path := fmt.Sprintf("lookup.php?i=%d", id)
 	request, err := http.NewRequest(http.MethodGet, baseUrl+path, nil)
 	if err != nil {
@@ -67,7 +67,7 @@ func GetMeal(id int) (*model.Meal, error) {
 	return createMeal(currentMeal)
 }
 
-func SearchMealByName(name string) ([]*model.Meal, error) {
+func SearchMealByName(name string) (*meal.MealResponses, error) {
 	path := fmt.Sprintf("search.php?s=%s", name)
 	request, err := http.NewRequest(http.MethodGet, baseUrl+path, nil)
 	if err != nil {
@@ -83,19 +83,19 @@ func SearchMealByName(name string) ([]*model.Meal, error) {
 		return nil, err
 	}
 
-	meals := []*model.Meal{}
+	meals := &meal.MealResponses{}
 	for _, v := range mealResponse.Meals {
 		meal, err := createMeal(v)
 		if err != nil {
 			continue
 		}
-		meals = append(meals, meal)
+		meals.Meals = append(meals.Meals, meal)
 	}
 
 	return meals, nil
 }
 
-func SearchMealBy(value string, filter model.Filter) ([]*model.MealOverview, error) {
+func SearchMealBy(value string, filter string) (*meal.MealOverviewResponses, error) {
 	path := fmt.Sprintf("filter.php?%s=%s", filter, value)
 	request, err := http.NewRequest(http.MethodGet, baseUrl+path, nil)
 	if err != nil {
@@ -111,19 +111,19 @@ func SearchMealBy(value string, filter model.Filter) ([]*model.MealOverview, err
 		return nil, err
 	}
 
-	meals := []*model.MealOverview{}
+	meals := &meal.MealOverviewResponses{}
 	for _, v := range mealResponse.Meals {
 		meal, err := createMealOverview(v)
 		if err != nil {
 			continue
 		}
-		meals = append(meals, meal)
+		meals.Meals = append(meals.Meals, meal)
 	}
 
 	return meals, nil
 }
 
-func GetFilter(filter model.Filter) (*model.FilterOverview, error) {
+func GetFilter(filter string) (*meal.FilterOverviewResponse, error) {
 	path := fmt.Sprintf("list.php?%s=list", filter)
 	request, err := http.NewRequest(http.MethodGet, baseUrl+path, nil)
 	if err != nil {
@@ -138,21 +138,21 @@ func GetFilter(filter model.Filter) (*model.FilterOverview, error) {
 	if err != nil {
 		return nil, err
 	}
-	filterOverview := &model.FilterOverview{}
+	filterOverview := &meal.FilterOverviewResponse{}
 	switch filter {
-	case model.CATEGORY:
+	case "c":
 		for _, v := range mealResponse.Meals {
 			if v.StrCategory != nil {
 				filterOverview.ValidValues = append(filterOverview.ValidValues, *v.StrCategory)
 			}
 		}
-	case model.AREA:
+	case "a":
 		for _, v := range mealResponse.Meals {
 			if v.StrArea != nil {
 				filterOverview.ValidValues = append(filterOverview.ValidValues, *v.StrArea)
 			}
 		}
-	case model.INGREDIENT:
+	case "i":
 		for _, v := range mealResponse.Meals {
 			if v.StrIngredient != nil {
 				filterOverview.ValidValues = append(filterOverview.ValidValues, *v.StrIngredient)
@@ -163,282 +163,282 @@ func GetFilter(filter model.Filter) (*model.FilterOverview, error) {
 	return filterOverview, nil
 }
 
-func createMeal(currentMeal *Meal) (*model.Meal, error) {
-	meal := &model.Meal{}
+func createMeal(currentMeal *Meal) (*meal.MealResponse, error) {
+	result := &meal.MealResponse{}
 	if currentMeal.IdMeal != nil {
 		id, err := strconv.Atoi(*currentMeal.IdMeal)
 		if err == nil {
-			meal.ID = id
+			result.Id = int32(id)
 		}
 	}
 	if currentMeal.StrMeal != nil {
-		meal.Name = *currentMeal.StrMeal
+		result.Name = *currentMeal.StrMeal
 	}
 	if currentMeal.StrCategory != nil {
-		meal.Category = *currentMeal.StrCategory
+		result.Category = *currentMeal.StrCategory
 	}
 	if currentMeal.StrInstructions != nil {
-		meal.Instructions = *currentMeal.StrInstructions
+		result.Instructions = *currentMeal.StrInstructions
 	}
 	if currentMeal.StrMealThumb != nil {
-		meal.ImagePath = *currentMeal.StrMealThumb
+		result.ImagePath = *currentMeal.StrMealThumb
 	}
-	ingredients := []*model.Ingredient{}
+	ingredients := []*meal.IngredientResponse{}
 	if currentMeal.StrIngredient1 != nil {
 		if currentMeal.StrMeasure1 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient1,
 				Amount: *currentMeal.StrMeasure1,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient1,
 			})
 		}
 	}
 	if currentMeal.StrIngredient2 != nil {
 		if currentMeal.StrMeasure2 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient2,
 				Amount: *currentMeal.StrMeasure2,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient2,
 			})
 		}
 	}
 	if currentMeal.StrIngredient3 != nil {
 		if currentMeal.StrMeasure3 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient3,
 				Amount: *currentMeal.StrMeasure3,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient3,
 			})
 		}
 	}
 	if currentMeal.StrIngredient4 != nil {
 		if currentMeal.StrMeasure4 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient4,
 				Amount: *currentMeal.StrMeasure4,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient4,
 			})
 		}
 	}
 	if currentMeal.StrIngredient5 != nil {
 		if currentMeal.StrMeasure5 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient5,
 				Amount: *currentMeal.StrMeasure5,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient5,
 			})
 		}
 	}
 	if currentMeal.StrIngredient6 != nil {
 		if currentMeal.StrMeasure6 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient6,
 				Amount: *currentMeal.StrMeasure6,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient6,
 			})
 		}
 	}
 	if currentMeal.StrIngredient7 != nil {
 		if currentMeal.StrMeasure7 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient7,
 				Amount: *currentMeal.StrMeasure7,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient7,
 			})
 		}
 	}
 	if currentMeal.StrIngredient8 != nil {
 		if currentMeal.StrMeasure8 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient8,
 				Amount: *currentMeal.StrMeasure8,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient8,
 			})
 		}
 	}
 	if currentMeal.StrIngredient9 != nil {
 		if currentMeal.StrMeasure9 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient9,
 				Amount: *currentMeal.StrMeasure9,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient9,
 			})
 		}
 	}
 	if currentMeal.StrIngredient10 != nil {
 		if currentMeal.StrMeasure10 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient10,
 				Amount: *currentMeal.StrMeasure10,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient10,
 			})
 		}
 	}
 	if currentMeal.StrIngredient11 != nil {
 		if currentMeal.StrMeasure11 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient11,
 				Amount: *currentMeal.StrMeasure11,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient11,
 			})
 		}
 	}
 	if currentMeal.StrIngredient12 != nil {
 		if currentMeal.StrMeasure12 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient12,
 				Amount: *currentMeal.StrMeasure12,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient12,
 			})
 		}
 	}
 	if currentMeal.StrIngredient13 != nil {
 		if currentMeal.StrMeasure13 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient13,
 				Amount: *currentMeal.StrMeasure13,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient13,
 			})
 		}
 	}
 	if currentMeal.StrIngredient14 != nil {
 		if currentMeal.StrMeasure14 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient14,
 				Amount: *currentMeal.StrMeasure14,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient14,
 			})
 		}
 	}
 	if currentMeal.StrIngredient15 != nil {
 		if currentMeal.StrMeasure15 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient15,
 				Amount: *currentMeal.StrMeasure15,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient15,
 			})
 		}
 	}
 	if currentMeal.StrIngredient16 != nil {
 		if currentMeal.StrMeasure16 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient16,
 				Amount: *currentMeal.StrMeasure16,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient16,
 			})
 		}
 	}
 	if currentMeal.StrIngredient17 != nil {
 		if currentMeal.StrMeasure17 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient17,
 				Amount: *currentMeal.StrMeasure17,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient17,
 			})
 		}
 	}
 	if currentMeal.StrIngredient18 != nil {
 		if currentMeal.StrMeasure18 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient18,
 				Amount: *currentMeal.StrMeasure18,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient18,
 			})
 		}
 	}
 	if currentMeal.StrIngredient19 != nil {
 		if currentMeal.StrMeasure19 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient19,
 				Amount: *currentMeal.StrMeasure19,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient19,
 			})
 		}
 	}
 	if currentMeal.StrIngredient20 != nil {
 		if currentMeal.StrMeasure20 != nil {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name:   *currentMeal.StrIngredient20,
 				Amount: *currentMeal.StrMeasure20,
 			})
 		} else {
-			ingredients = append(ingredients, &model.Ingredient{
+			ingredients = append(ingredients, &meal.IngredientResponse{
 				Name: *currentMeal.StrIngredient20,
 			})
 		}
 	}
 	for _, ingredient := range ingredients {
 		if ingredient.Name != "" {
-			meal.Ingredients = append(meal.Ingredients, ingredient)
+			result.Ingredients = append(result.Ingredients, ingredient)
 		}
 	}
 
-	return meal, nil
+	return result, nil
 }
 
-func createMealOverview(currentMeal *Meal) (*model.MealOverview, error) {
-	meal := &model.MealOverview{}
+func createMealOverview(currentMeal *Meal) (*meal.MealOverviewResponse, error) {
+	meal := &meal.MealOverviewResponse{}
 	if currentMeal.IdMeal != nil {
 		id, err := strconv.Atoi(*currentMeal.IdMeal)
 		if err == nil {
-			meal.ID = id
+			meal.Id = int32(id)
 		}
 	}
 	if currentMeal.StrMeal != nil {
diff --git a/service/meal/go.mod b/service/meal/go.mod
index 4558a1a9a2fd1523310fdce30813339ffe7360c2..71b715572fd9df37787d67905990f8b62d934bf3 100644
--- a/service/meal/go.mod
+++ b/service/meal/go.mod
@@ -2,4 +2,16 @@ module gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal
 
 go 1.20
 
-require github.com/gorilla/mux v1.8.0
+require (
+	github.com/sirupsen/logrus v1.9.3
+	google.golang.org/grpc v1.56.2
+	google.golang.org/protobuf v1.31.0
+)
+
+require (
+	github.com/golang/protobuf v1.5.3 // indirect
+	golang.org/x/net v0.9.0 // indirect
+	golang.org/x/sys v0.7.0 // indirect
+	golang.org/x/text v0.9.0 // indirect
+	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
+)
diff --git a/service/meal/go.sum b/service/meal/go.sum
index 535028803d222b0e4e9174f56529c0ed9fece4e0..99c742abd6866edc35d113e91cfa1c32aabf569c 100644
--- a/service/meal/go.sum
+++ b/service/meal/go.sum
@@ -1,2 +1,34 @@
-github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
-github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
+golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
+golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
+google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
+google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/service/meal/grpc/gen.go b/service/meal/grpc/gen.go
new file mode 100644
index 0000000000000000000000000000000000000000..1edf88fb54442df6e060da722c44e8811b828fe3
--- /dev/null
+++ b/service/meal/grpc/gen.go
@@ -0,0 +1,3 @@
+package grpc
+
+//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative meal/meal.proto
diff --git a/service/meal/grpc/meal/meal.pb.go b/service/meal/grpc/meal/meal.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..e67e14c9a8f41b6bcce07a1ca701bc0bf7ae9395
--- /dev/null
+++ b/service/meal/grpc/meal/meal.pb.go
@@ -0,0 +1,840 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v4.23.3
+// source: meal/meal.proto
+
+package meal
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	emptypb "google.golang.org/protobuf/types/known/emptypb"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type MealRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *MealRequest) Reset() {
+	*x = MealRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealRequest) ProtoMessage() {}
+
+func (x *MealRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealRequest.ProtoReflect.Descriptor instead.
+func (*MealRequest) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *MealRequest) GetId() int32 {
+	if x != nil {
+		return x.Id
+	}
+	return 0
+}
+
+type MealOverviewRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Value  string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
+	Filter string `protobuf:"bytes,2,opt,name=filter,proto3" json:"filter,omitempty"`
+}
+
+func (x *MealOverviewRequest) Reset() {
+	*x = MealOverviewRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealOverviewRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealOverviewRequest) ProtoMessage() {}
+
+func (x *MealOverviewRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealOverviewRequest.ProtoReflect.Descriptor instead.
+func (*MealOverviewRequest) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *MealOverviewRequest) GetValue() string {
+	if x != nil {
+		return x.Value
+	}
+	return ""
+}
+
+func (x *MealOverviewRequest) GetFilter() string {
+	if x != nil {
+		return x.Filter
+	}
+	return ""
+}
+
+type FilterOverviewRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Filter string `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"`
+}
+
+func (x *FilterOverviewRequest) Reset() {
+	*x = FilterOverviewRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FilterOverviewRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FilterOverviewRequest) ProtoMessage() {}
+
+func (x *FilterOverviewRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FilterOverviewRequest.ProtoReflect.Descriptor instead.
+func (*FilterOverviewRequest) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *FilterOverviewRequest) GetFilter() string {
+	if x != nil {
+		return x.Filter
+	}
+	return ""
+}
+
+type SearchRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *SearchRequest) Reset() {
+	*x = SearchRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SearchRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SearchRequest) ProtoMessage() {}
+
+func (x *SearchRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SearchRequest.ProtoReflect.Descriptor instead.
+func (*SearchRequest) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *SearchRequest) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+type IngredientResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name   string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Amount string `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"`
+}
+
+func (x *IngredientResponse) Reset() {
+	*x = IngredientResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *IngredientResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*IngredientResponse) ProtoMessage() {}
+
+func (x *IngredientResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use IngredientResponse.ProtoReflect.Descriptor instead.
+func (*IngredientResponse) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *IngredientResponse) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *IngredientResponse) GetAmount() string {
+	if x != nil {
+		return x.Amount
+	}
+	return ""
+}
+
+type MealResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id           int32                 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+	Name         string                `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+	Category     string                `protobuf:"bytes,3,opt,name=category,proto3" json:"category,omitempty"`
+	Ingredients  []*IngredientResponse `protobuf:"bytes,4,rep,name=ingredients,proto3" json:"ingredients,omitempty"`
+	Instructions string                `protobuf:"bytes,5,opt,name=instructions,proto3" json:"instructions,omitempty"`
+	ImagePath    string                `protobuf:"bytes,6,opt,name=imagePath,proto3" json:"imagePath,omitempty"`
+}
+
+func (x *MealResponse) Reset() {
+	*x = MealResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealResponse) ProtoMessage() {}
+
+func (x *MealResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealResponse.ProtoReflect.Descriptor instead.
+func (*MealResponse) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *MealResponse) GetId() int32 {
+	if x != nil {
+		return x.Id
+	}
+	return 0
+}
+
+func (x *MealResponse) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *MealResponse) GetCategory() string {
+	if x != nil {
+		return x.Category
+	}
+	return ""
+}
+
+func (x *MealResponse) GetIngredients() []*IngredientResponse {
+	if x != nil {
+		return x.Ingredients
+	}
+	return nil
+}
+
+func (x *MealResponse) GetInstructions() string {
+	if x != nil {
+		return x.Instructions
+	}
+	return ""
+}
+
+func (x *MealResponse) GetImagePath() string {
+	if x != nil {
+		return x.ImagePath
+	}
+	return ""
+}
+
+type MealResponses struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Meals []*MealResponse `protobuf:"bytes,1,rep,name=meals,proto3" json:"meals,omitempty"`
+}
+
+func (x *MealResponses) Reset() {
+	*x = MealResponses{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealResponses) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealResponses) ProtoMessage() {}
+
+func (x *MealResponses) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealResponses.ProtoReflect.Descriptor instead.
+func (*MealResponses) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *MealResponses) GetMeals() []*MealResponse {
+	if x != nil {
+		return x.Meals
+	}
+	return nil
+}
+
+type MealOverviewResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id        int32  `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+	Name      string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+	ImagePath string `protobuf:"bytes,3,opt,name=imagePath,proto3" json:"imagePath,omitempty"`
+}
+
+func (x *MealOverviewResponse) Reset() {
+	*x = MealOverviewResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealOverviewResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealOverviewResponse) ProtoMessage() {}
+
+func (x *MealOverviewResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealOverviewResponse.ProtoReflect.Descriptor instead.
+func (*MealOverviewResponse) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *MealOverviewResponse) GetId() int32 {
+	if x != nil {
+		return x.Id
+	}
+	return 0
+}
+
+func (x *MealOverviewResponse) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *MealOverviewResponse) GetImagePath() string {
+	if x != nil {
+		return x.ImagePath
+	}
+	return ""
+}
+
+type MealOverviewResponses struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Meals []*MealOverviewResponse `protobuf:"bytes,1,rep,name=meals,proto3" json:"meals,omitempty"`
+}
+
+func (x *MealOverviewResponses) Reset() {
+	*x = MealOverviewResponses{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealOverviewResponses) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealOverviewResponses) ProtoMessage() {}
+
+func (x *MealOverviewResponses) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealOverviewResponses.ProtoReflect.Descriptor instead.
+func (*MealOverviewResponses) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *MealOverviewResponses) GetMeals() []*MealOverviewResponse {
+	if x != nil {
+		return x.Meals
+	}
+	return nil
+}
+
+type FilterOverviewResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ValidValues []string `protobuf:"bytes,1,rep,name=validValues,proto3" json:"validValues,omitempty"`
+}
+
+func (x *FilterOverviewResponse) Reset() {
+	*x = FilterOverviewResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FilterOverviewResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FilterOverviewResponse) ProtoMessage() {}
+
+func (x *FilterOverviewResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[9]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FilterOverviewResponse.ProtoReflect.Descriptor instead.
+func (*FilterOverviewResponse) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *FilterOverviewResponse) GetValidValues() []string {
+	if x != nil {
+		return x.ValidValues
+	}
+	return nil
+}
+
+var File_meal_meal_proto protoreflect.FileDescriptor
+
+var file_meal_meal_proto_rawDesc = []byte{
+	0x0a, 0x0f, 0x6d, 0x65, 0x61, 0x6c, 0x2f, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x12, 0x04, 0x6d, 0x65, 0x61, 0x6c, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1d, 0x0a, 0x0b, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
+	0x02, 0x69, 0x64, 0x22, 0x43, 0x0a, 0x13, 0x4d, 0x65, 0x61, 0x6c, 0x4f, 0x76, 0x65, 0x72, 0x76,
+	0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x2f, 0x0a, 0x15, 0x46, 0x69, 0x6c, 0x74,
+	0x65, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x23, 0x0a, 0x0d, 0x53, 0x65, 0x61,
+	0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x40,
+	0x0a, 0x12, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75,
+	0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
+	0x22, 0xcc, 0x01, 0x0a, 0x0c, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69,
+	0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72,
+	0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72,
+	0x79, 0x12, 0x3a, 0x0a, 0x0b, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x73,
+	0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x49, 0x6e,
+	0x67, 0x72, 0x65, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x52, 0x0b, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x22, 0x0a,
+	0x0c, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x50, 0x61, 0x74, 0x68, 0x22,
+	0x39, 0x0a, 0x0d, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73,
+	0x12, 0x28, 0x0a, 0x05, 0x6d, 0x65, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x12, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x52, 0x05, 0x6d, 0x65, 0x61, 0x6c, 0x73, 0x22, 0x58, 0x0a, 0x14, 0x4d, 0x65,
+	0x61, 0x6c, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02,
+	0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x50,
+	0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65,
+	0x50, 0x61, 0x74, 0x68, 0x22, 0x49, 0x0a, 0x15, 0x4d, 0x65, 0x61, 0x6c, 0x4f, 0x76, 0x65, 0x72,
+	0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x30, 0x0a,
+	0x05, 0x6d, 0x65, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d,
+	0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x6d, 0x65, 0x61, 0x6c, 0x73, 0x22,
+	0x3a, 0x0a, 0x16, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65,
+	0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x76, 0x61, 0x6c,
+	0x69, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b,
+	0x76, 0x61, 0x6c, 0x69, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x32, 0xcd, 0x02, 0x0a, 0x04,
+	0x4d, 0x65, 0x61, 0x6c, 0x12, 0x3d, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f,
+	0x6d, 0x4d, 0x65, 0x61, 0x6c, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e,
+	0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x61, 0x6c, 0x12, 0x11,
+	0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x12, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x10, 0x53, 0x65, 0x61, 0x72, 0x63,
+	0x68, 0x4d, 0x65, 0x61, 0x6c, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x13, 0x2e, 0x6d, 0x65,
+	0x61, 0x6c, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x1a, 0x13, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63,
+	0x68, 0x4d, 0x65, 0x61, 0x6c, 0x42, 0x79, 0x12, 0x19, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d,
+	0x65, 0x61, 0x6c, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x4f, 0x76,
+	0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22,
+	0x00, 0x12, 0x48, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1b,
+	0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x76, 0x65, 0x72,
+	0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6d, 0x65,
+	0x61, 0x6c, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65,
+	0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x50, 0x5a, 0x4e, 0x67,
+	0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x72, 0x65, 0x75, 0x74, 0x6c, 0x69, 0x6e, 0x67, 0x65, 0x6e,
+	0x2d, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x69, 0x74, 0x79, 0x2e, 0x64, 0x65, 0x2f, 0x79,
+	0x65, 0x73, 0x69, 0x6c, 0x64, 0x61, 0x73, 0x2f, 0x6d, 0x65, 0x61, 0x6c, 0x70, 0x6c, 0x61, 0x6e,
+	0x6e, 0x65, 0x72, 0x32, 0x67, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x6d,
+	0x65, 0x61, 0x6c, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x6d, 0x65, 0x61, 0x6c, 0x62, 0x06, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_meal_meal_proto_rawDescOnce sync.Once
+	file_meal_meal_proto_rawDescData = file_meal_meal_proto_rawDesc
+)
+
+func file_meal_meal_proto_rawDescGZIP() []byte {
+	file_meal_meal_proto_rawDescOnce.Do(func() {
+		file_meal_meal_proto_rawDescData = protoimpl.X.CompressGZIP(file_meal_meal_proto_rawDescData)
+	})
+	return file_meal_meal_proto_rawDescData
+}
+
+var file_meal_meal_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
+var file_meal_meal_proto_goTypes = []interface{}{
+	(*MealRequest)(nil),            // 0: meal.MealRequest
+	(*MealOverviewRequest)(nil),    // 1: meal.MealOverviewRequest
+	(*FilterOverviewRequest)(nil),  // 2: meal.FilterOverviewRequest
+	(*SearchRequest)(nil),          // 3: meal.SearchRequest
+	(*IngredientResponse)(nil),     // 4: meal.IngredientResponse
+	(*MealResponse)(nil),           // 5: meal.MealResponse
+	(*MealResponses)(nil),          // 6: meal.MealResponses
+	(*MealOverviewResponse)(nil),   // 7: meal.MealOverviewResponse
+	(*MealOverviewResponses)(nil),  // 8: meal.MealOverviewResponses
+	(*FilterOverviewResponse)(nil), // 9: meal.FilterOverviewResponse
+	(*emptypb.Empty)(nil),          // 10: google.protobuf.Empty
+}
+var file_meal_meal_proto_depIdxs = []int32{
+	4,  // 0: meal.MealResponse.ingredients:type_name -> meal.IngredientResponse
+	5,  // 1: meal.MealResponses.meals:type_name -> meal.MealResponse
+	7,  // 2: meal.MealOverviewResponses.meals:type_name -> meal.MealOverviewResponse
+	10, // 3: meal.Meal.GetRandomMeal:input_type -> google.protobuf.Empty
+	0,  // 4: meal.Meal.GetMeal:input_type -> meal.MealRequest
+	3,  // 5: meal.Meal.SearchMealByName:input_type -> meal.SearchRequest
+	1,  // 6: meal.Meal.SearchMealBy:input_type -> meal.MealOverviewRequest
+	2,  // 7: meal.Meal.GetFilter:input_type -> meal.FilterOverviewRequest
+	5,  // 8: meal.Meal.GetRandomMeal:output_type -> meal.MealResponse
+	5,  // 9: meal.Meal.GetMeal:output_type -> meal.MealResponse
+	6,  // 10: meal.Meal.SearchMealByName:output_type -> meal.MealResponses
+	8,  // 11: meal.Meal.SearchMealBy:output_type -> meal.MealOverviewResponses
+	9,  // 12: meal.Meal.GetFilter:output_type -> meal.FilterOverviewResponse
+	8,  // [8:13] is the sub-list for method output_type
+	3,  // [3:8] is the sub-list for method input_type
+	3,  // [3:3] is the sub-list for extension type_name
+	3,  // [3:3] is the sub-list for extension extendee
+	0,  // [0:3] is the sub-list for field type_name
+}
+
+func init() { file_meal_meal_proto_init() }
+func file_meal_meal_proto_init() {
+	if File_meal_meal_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_meal_meal_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealOverviewRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FilterOverviewRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SearchRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*IngredientResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealResponses); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealOverviewResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealOverviewResponses); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FilterOverviewResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_meal_meal_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   10,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_meal_meal_proto_goTypes,
+		DependencyIndexes: file_meal_meal_proto_depIdxs,
+		MessageInfos:      file_meal_meal_proto_msgTypes,
+	}.Build()
+	File_meal_meal_proto = out.File
+	file_meal_meal_proto_rawDesc = nil
+	file_meal_meal_proto_goTypes = nil
+	file_meal_meal_proto_depIdxs = nil
+}
diff --git a/service/meal/grpc/meal/meal.proto b/service/meal/grpc/meal/meal.proto
new file mode 100644
index 0000000000000000000000000000000000000000..63d7313fa2877f3de14eeabc388e8b85f32d93d2
--- /dev/null
+++ b/service/meal/grpc/meal/meal.proto
@@ -0,0 +1,64 @@
+syntax = "proto3";
+
+package meal;
+
+import "google/protobuf/empty.proto";
+
+option go_package = "gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/grpc/meal";
+
+service Meal {
+    rpc GetRandomMeal(google.protobuf.Empty) returns (MealResponse) {}
+    rpc GetMeal(MealRequest) returns (MealResponse) {}
+    rpc SearchMealByName(SearchRequest) returns (MealResponses) {}
+    rpc SearchMealBy(MealOverviewRequest) returns (MealOverviewResponses) {}
+    rpc GetFilter(FilterOverviewRequest) returns (FilterOverviewResponse) {}
+}
+
+message MealRequest {
+    int32 id = 1;
+}
+
+message MealOverviewRequest {
+    string value = 1;
+    string filter = 2;
+}
+
+message FilterOverviewRequest {
+    string filter = 1;
+}
+
+message SearchRequest {
+    string name = 1;
+}
+
+message IngredientResponse {
+    string name = 1;
+    string amount = 2;
+}
+
+message MealResponse {
+    int32 id = 1;
+    string name = 2;
+    string category = 3;
+    repeated IngredientResponse ingredients = 4;
+    string instructions = 5;
+    string imagePath = 6;
+}
+
+message MealResponses {
+    repeated MealResponse meals = 1;
+}
+
+message MealOverviewResponse {
+    int32 id = 1;
+    string name = 2;
+    string imagePath = 3;
+}
+
+message MealOverviewResponses {
+    repeated MealOverviewResponse meals = 1;
+}
+
+message FilterOverviewResponse {
+    repeated string validValues = 1;
+}
\ No newline at end of file
diff --git a/service/meal/grpc/meal/meal_grpc.pb.go b/service/meal/grpc/meal/meal_grpc.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..f24057f56162d136e679f23feab7d792f9e004a2
--- /dev/null
+++ b/service/meal/grpc/meal/meal_grpc.pb.go
@@ -0,0 +1,250 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.2.0
+// - protoc             v4.23.3
+// source: meal/meal.proto
+
+package meal
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+	emptypb "google.golang.org/protobuf/types/known/emptypb"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// MealClient is the client API for Meal service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type MealClient interface {
+	GetRandomMeal(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MealResponse, error)
+	GetMeal(ctx context.Context, in *MealRequest, opts ...grpc.CallOption) (*MealResponse, error)
+	SearchMealByName(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*MealResponses, error)
+	SearchMealBy(ctx context.Context, in *MealOverviewRequest, opts ...grpc.CallOption) (*MealOverviewResponses, error)
+	GetFilter(ctx context.Context, in *FilterOverviewRequest, opts ...grpc.CallOption) (*FilterOverviewResponse, error)
+}
+
+type mealClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewMealClient(cc grpc.ClientConnInterface) MealClient {
+	return &mealClient{cc}
+}
+
+func (c *mealClient) GetRandomMeal(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MealResponse, error) {
+	out := new(MealResponse)
+	err := c.cc.Invoke(ctx, "/meal.Meal/GetRandomMeal", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *mealClient) GetMeal(ctx context.Context, in *MealRequest, opts ...grpc.CallOption) (*MealResponse, error) {
+	out := new(MealResponse)
+	err := c.cc.Invoke(ctx, "/meal.Meal/GetMeal", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *mealClient) SearchMealByName(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*MealResponses, error) {
+	out := new(MealResponses)
+	err := c.cc.Invoke(ctx, "/meal.Meal/SearchMealByName", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *mealClient) SearchMealBy(ctx context.Context, in *MealOverviewRequest, opts ...grpc.CallOption) (*MealOverviewResponses, error) {
+	out := new(MealOverviewResponses)
+	err := c.cc.Invoke(ctx, "/meal.Meal/SearchMealBy", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *mealClient) GetFilter(ctx context.Context, in *FilterOverviewRequest, opts ...grpc.CallOption) (*FilterOverviewResponse, error) {
+	out := new(FilterOverviewResponse)
+	err := c.cc.Invoke(ctx, "/meal.Meal/GetFilter", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// MealServer is the server API for Meal service.
+// All implementations must embed UnimplementedMealServer
+// for forward compatibility
+type MealServer interface {
+	GetRandomMeal(context.Context, *emptypb.Empty) (*MealResponse, error)
+	GetMeal(context.Context, *MealRequest) (*MealResponse, error)
+	SearchMealByName(context.Context, *SearchRequest) (*MealResponses, error)
+	SearchMealBy(context.Context, *MealOverviewRequest) (*MealOverviewResponses, error)
+	GetFilter(context.Context, *FilterOverviewRequest) (*FilterOverviewResponse, error)
+	mustEmbedUnimplementedMealServer()
+}
+
+// UnimplementedMealServer must be embedded to have forward compatible implementations.
+type UnimplementedMealServer struct {
+}
+
+func (UnimplementedMealServer) GetRandomMeal(context.Context, *emptypb.Empty) (*MealResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetRandomMeal not implemented")
+}
+func (UnimplementedMealServer) GetMeal(context.Context, *MealRequest) (*MealResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetMeal not implemented")
+}
+func (UnimplementedMealServer) SearchMealByName(context.Context, *SearchRequest) (*MealResponses, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SearchMealByName not implemented")
+}
+func (UnimplementedMealServer) SearchMealBy(context.Context, *MealOverviewRequest) (*MealOverviewResponses, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SearchMealBy not implemented")
+}
+func (UnimplementedMealServer) GetFilter(context.Context, *FilterOverviewRequest) (*FilterOverviewResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetFilter not implemented")
+}
+func (UnimplementedMealServer) mustEmbedUnimplementedMealServer() {}
+
+// UnsafeMealServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to MealServer will
+// result in compilation errors.
+type UnsafeMealServer interface {
+	mustEmbedUnimplementedMealServer()
+}
+
+func RegisterMealServer(s grpc.ServiceRegistrar, srv MealServer) {
+	s.RegisterService(&Meal_ServiceDesc, srv)
+}
+
+func _Meal_GetRandomMeal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(emptypb.Empty)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MealServer).GetRandomMeal(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/meal.Meal/GetRandomMeal",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MealServer).GetRandomMeal(ctx, req.(*emptypb.Empty))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Meal_GetMeal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MealRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MealServer).GetMeal(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/meal.Meal/GetMeal",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MealServer).GetMeal(ctx, req.(*MealRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Meal_SearchMealByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SearchRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MealServer).SearchMealByName(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/meal.Meal/SearchMealByName",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MealServer).SearchMealByName(ctx, req.(*SearchRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Meal_SearchMealBy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MealOverviewRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MealServer).SearchMealBy(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/meal.Meal/SearchMealBy",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MealServer).SearchMealBy(ctx, req.(*MealOverviewRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Meal_GetFilter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(FilterOverviewRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MealServer).GetFilter(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/meal.Meal/GetFilter",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MealServer).GetFilter(ctx, req.(*FilterOverviewRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// Meal_ServiceDesc is the grpc.ServiceDesc for Meal service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Meal_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "meal.Meal",
+	HandlerType: (*MealServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "GetRandomMeal",
+			Handler:    _Meal_GetRandomMeal_Handler,
+		},
+		{
+			MethodName: "GetMeal",
+			Handler:    _Meal_GetMeal_Handler,
+		},
+		{
+			MethodName: "SearchMealByName",
+			Handler:    _Meal_SearchMealByName_Handler,
+		},
+		{
+			MethodName: "SearchMealBy",
+			Handler:    _Meal_SearchMealBy_Handler,
+		},
+		{
+			MethodName: "GetFilter",
+			Handler:    _Meal_GetFilter_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "meal/meal.proto",
+}
diff --git a/service/meal/handler/utils.go b/service/meal/handler/utils.go
deleted file mode 100644
index 7272c8514f0fc4b8989c32129c7b409ba55ae66d..0000000000000000000000000000000000000000
--- a/service/meal/handler/utils.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package handler
-
-import (
-	"encoding/json"
-	"net/http"
-	"strconv"
-
-	"github.com/gorilla/mux"
-)
-
-func sendJson(w http.ResponseWriter, value interface{}) {
-	w.Header().Set("Content-Type", "application/json")
-	if err := json.NewEncoder(w).Encode(value); err != nil {
-		http.Error(w, err.Error(), http.StatusInternalServerError)
-	}
-}
-
-func getId(r *http.Request) (int, error) {
-	vars := mux.Vars(r)
-	id, err := strconv.Atoi(vars["id"])
-	if err != nil {
-		return 0, err
-	}
-	return id, nil
-}
-
-func getValue(r *http.Request) string {
-	vars := mux.Vars(r)
-	return vars["value"]
-}
diff --git a/service/meal/main.go b/service/meal/main.go
index b8c4a44562fd0b41b6913b89a9045ac4a7eebda6..5d2a6f22e6cc985afeb4b78ca7f2fbb8c5e21da4 100644
--- a/service/meal/main.go
+++ b/service/meal/main.go
@@ -2,27 +2,39 @@ package main
 
 import (
 	"fmt"
-	"log"
-	"net/http"
 
-	"github.com/gorilla/mux"
-	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/handler"
+	"net"
+	"os"
+
+	log "github.com/sirupsen/logrus"
+	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/grpc/meal"
+	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/service"
+	"google.golang.org/grpc"
 )
 
+func init() {
+	// init logger
+	log.SetFormatter(&log.TextFormatter{})
+	log.SetReportCaller(true)
+	level, err := log.ParseLevel(os.Getenv("LOG_LEVEL"))
+	if err != nil {
+		log.Info("Log level not specified, set default to: INFO")
+		log.SetLevel(log.InfoLevel)
+		return
+	}
+	log.SetLevel(level)
+}
+
 func main() {
 	port := 9111
-	router := mux.NewRouter()
-	router.HandleFunc("/random", handler.GetRandomMeal).Methods(http.MethodGet)
-	router.HandleFunc("/search/{value}", handler.SearchMealByName).Methods(http.MethodGet)
-	router.HandleFunc("/category/{value}", handler.SearchMealByCategory).Methods(http.MethodGet)
-	router.HandleFunc("/category", handler.GetCategoryOverview).Methods(http.MethodGet)
-	router.HandleFunc("/area/{value}", handler.SearchMealByArea).Methods(http.MethodGet)
-	router.HandleFunc("/area", handler.GetAreaOverview).Methods(http.MethodGet)
-	router.HandleFunc("/ingredient/{value}", handler.SearchMealByIngredient).Methods(http.MethodGet)
-	router.HandleFunc("/ingredient", handler.GetIngredientOverview).Methods(http.MethodGet)
-	router.HandleFunc("/{id}", handler.GetMeal).Methods(http.MethodGet)
-	fmt.Printf("Server is listening on port :%v\n", port)
-	if err := http.ListenAndServe(fmt.Sprintf(":%v", port), router); err != nil {
-		log.Fatal(err)
+	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
+	if err != nil {
+		log.Fatalf("failed to listen on grpc port %d: %v", port, err)
+	}
+	log.Infof("Server is listening on port :%v\n", port)
+	grpcServer := grpc.NewServer()
+	meal.RegisterMealServer(grpcServer, service.NewMealService())
+	if err := grpcServer.Serve(lis); err != nil {
+		log.Fatalf("failed to serve: %v", err)
 	}
 }
diff --git a/service/meal/model/meal.go b/service/meal/model/meal.go
deleted file mode 100644
index d83cf19c7a07b2d20435bf247326d657a4dc1ba3..0000000000000000000000000000000000000000
--- a/service/meal/model/meal.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package model
-
-type Ingredient struct {
-	Name   string `json:"name"`
-	Amount string `json:"amount"`
-}
-
-type Meal struct {
-	ID           int           `json:"id"`
-	Name         string        `json:"name"`
-	Category     string        `json:"category"`
-	Ingredients  []*Ingredient `json:"ingredients"`
-	Instructions string        `json:"instructions"`
-	ImagePath    string        `json:"imagePath"`
-}
-
-type MealOverview struct {
-	ID        int    `json:"id"`
-	Name      string `json:"name"`
-	ImagePath string `json:"imagePath"`
-}
-
-type FilterOverview struct {
-	ValidValues []string `json:"validValues"`
-}
-
-const (
-	CATEGORY   Filter = "c"
-	AREA       Filter = "a"
-	INGREDIENT Filter = "i"
-)
-
-type Filter string
diff --git a/service/meal/service/meal.go b/service/meal/service/meal.go
index b3a17fe01aea5294cfd9bba813a51f1838e3783b..ab6eb2b63532d37660bfe43a27dbbe8a7e6bff78 100644
--- a/service/meal/service/meal.go
+++ b/service/meal/service/meal.go
@@ -1,51 +1,62 @@
 package service
 
 import (
+	"context"
+
 	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/db/mealdb"
-	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/model"
+	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/grpc/meal"
+	"google.golang.org/protobuf/types/known/emptypb"
 )
 
-func GetRandomMeal() (*model.Meal, error) {
-	meal, err := mealdb.GetRandomMeal()
+type MealService struct {
+	meal.MealServer
+}
+
+func NewMealService() *MealService {
+	return &MealService{}
+}
+
+func (ms *MealService) GetRandomMeal(_ context.Context, _ *emptypb.Empty) (*meal.MealResponse, error) {
+	result, err := mealdb.GetRandomMeal()
 	if err != nil {
 		return nil, err
 	}
 
-	return meal, nil
+	return result, nil
 }
 
-func GetMeal(id int) (*model.Meal, error) {
-	meal, err := mealdb.GetMeal(id)
+func (ms *MealService) GetMeal(_ context.Context, mealRequest *meal.MealRequest) (*meal.MealResponse, error) {
+	result, err := mealdb.GetMeal(int(mealRequest.Id))
 	if err != nil {
 		return nil, err
 	}
 
-	return meal, nil
+	return result, nil
 }
 
-func SearchMealByName(name string) ([]*model.Meal, error) {
-	meals, err := mealdb.SearchMealByName(name)
+func (ms *MealService) SearchMealByName(_ context.Context, searchRequest *meal.SearchRequest) (*meal.MealResponses, error) {
+	result, err := mealdb.SearchMealByName(searchRequest.Name)
 	if err != nil {
 		return nil, err
 	}
 
-	return meals, nil
+	return result, nil
 }
 
-func SearchMealBy(value string, filter model.Filter) ([]*model.MealOverview, error) {
-	meals, err := mealdb.SearchMealBy(value, filter)
+func (ms *MealService) SearchMealBy(_ context.Context, mealOverviewRequest *meal.MealOverviewRequest) (*meal.MealOverviewResponses, error) {
+	result, err := mealdb.SearchMealBy(mealOverviewRequest.Value, mealOverviewRequest.Filter)
 	if err != nil {
 		return nil, err
 	}
 
-	return meals, nil
+	return result, nil
 }
 
-func GetFilter(filter model.Filter) (*model.FilterOverview, error) {
-	filterOverview, err := mealdb.GetFilter(filter)
+func (ms *MealService) GetFilter(_ context.Context, filterOverviewRequest *meal.FilterOverviewRequest) (*meal.FilterOverviewResponse, error) {
+	result, err := mealdb.GetFilter(filterOverviewRequest.Filter)
 	if err != nil {
 		return nil, err
 	}
 
-	return filterOverview, nil
+	return result, nil
 }
diff --git a/service/planner/client/gen.go b/service/planner/client/gen.go
new file mode 100644
index 0000000000000000000000000000000000000000..79343436da1a035370ea9b37ca9ceb329a1571f2
--- /dev/null
+++ b/service/planner/client/gen.go
@@ -0,0 +1,3 @@
+package client
+
+//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative meal/meal.proto
diff --git a/service/planner/client/meal.go b/service/planner/client/meal.go
new file mode 100644
index 0000000000000000000000000000000000000000..a702fc543ff65edb4f51ba0d3e19923ad58e1e3d
--- /dev/null
+++ b/service/planner/client/meal.go
@@ -0,0 +1,24 @@
+package client
+
+import (
+	"context"
+	"os"
+
+	log "github.com/sirupsen/logrus"
+	"google.golang.org/grpc"
+)
+
+var (
+	mealTarget = os.Getenv("MEAL_CONNECT")
+)
+
+func GetMealConnection(ctx context.Context) (*grpc.ClientConn, error) {
+	var err error
+	log.Infof("Connecting to meal service via %s\n", mealTarget)
+	conn, err := grpc.DialContext(ctx, mealTarget, grpc.WithInsecure(), grpc.WithBlock())
+	if err != nil {
+		return nil, err
+	}
+
+	return conn, nil
+}
diff --git a/service/planner/client/meal/meal.pb.go b/service/planner/client/meal/meal.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..e67e14c9a8f41b6bcce07a1ca701bc0bf7ae9395
--- /dev/null
+++ b/service/planner/client/meal/meal.pb.go
@@ -0,0 +1,840 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v4.23.3
+// source: meal/meal.proto
+
+package meal
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	emptypb "google.golang.org/protobuf/types/known/emptypb"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type MealRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *MealRequest) Reset() {
+	*x = MealRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealRequest) ProtoMessage() {}
+
+func (x *MealRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealRequest.ProtoReflect.Descriptor instead.
+func (*MealRequest) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *MealRequest) GetId() int32 {
+	if x != nil {
+		return x.Id
+	}
+	return 0
+}
+
+type MealOverviewRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Value  string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
+	Filter string `protobuf:"bytes,2,opt,name=filter,proto3" json:"filter,omitempty"`
+}
+
+func (x *MealOverviewRequest) Reset() {
+	*x = MealOverviewRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealOverviewRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealOverviewRequest) ProtoMessage() {}
+
+func (x *MealOverviewRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealOverviewRequest.ProtoReflect.Descriptor instead.
+func (*MealOverviewRequest) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *MealOverviewRequest) GetValue() string {
+	if x != nil {
+		return x.Value
+	}
+	return ""
+}
+
+func (x *MealOverviewRequest) GetFilter() string {
+	if x != nil {
+		return x.Filter
+	}
+	return ""
+}
+
+type FilterOverviewRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Filter string `protobuf:"bytes,1,opt,name=filter,proto3" json:"filter,omitempty"`
+}
+
+func (x *FilterOverviewRequest) Reset() {
+	*x = FilterOverviewRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FilterOverviewRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FilterOverviewRequest) ProtoMessage() {}
+
+func (x *FilterOverviewRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FilterOverviewRequest.ProtoReflect.Descriptor instead.
+func (*FilterOverviewRequest) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *FilterOverviewRequest) GetFilter() string {
+	if x != nil {
+		return x.Filter
+	}
+	return ""
+}
+
+type SearchRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *SearchRequest) Reset() {
+	*x = SearchRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *SearchRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SearchRequest) ProtoMessage() {}
+
+func (x *SearchRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use SearchRequest.ProtoReflect.Descriptor instead.
+func (*SearchRequest) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *SearchRequest) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+type IngredientResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name   string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Amount string `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"`
+}
+
+func (x *IngredientResponse) Reset() {
+	*x = IngredientResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *IngredientResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*IngredientResponse) ProtoMessage() {}
+
+func (x *IngredientResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use IngredientResponse.ProtoReflect.Descriptor instead.
+func (*IngredientResponse) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *IngredientResponse) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *IngredientResponse) GetAmount() string {
+	if x != nil {
+		return x.Amount
+	}
+	return ""
+}
+
+type MealResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id           int32                 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+	Name         string                `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+	Category     string                `protobuf:"bytes,3,opt,name=category,proto3" json:"category,omitempty"`
+	Ingredients  []*IngredientResponse `protobuf:"bytes,4,rep,name=ingredients,proto3" json:"ingredients,omitempty"`
+	Instructions string                `protobuf:"bytes,5,opt,name=instructions,proto3" json:"instructions,omitempty"`
+	ImagePath    string                `protobuf:"bytes,6,opt,name=imagePath,proto3" json:"imagePath,omitempty"`
+}
+
+func (x *MealResponse) Reset() {
+	*x = MealResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealResponse) ProtoMessage() {}
+
+func (x *MealResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealResponse.ProtoReflect.Descriptor instead.
+func (*MealResponse) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *MealResponse) GetId() int32 {
+	if x != nil {
+		return x.Id
+	}
+	return 0
+}
+
+func (x *MealResponse) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *MealResponse) GetCategory() string {
+	if x != nil {
+		return x.Category
+	}
+	return ""
+}
+
+func (x *MealResponse) GetIngredients() []*IngredientResponse {
+	if x != nil {
+		return x.Ingredients
+	}
+	return nil
+}
+
+func (x *MealResponse) GetInstructions() string {
+	if x != nil {
+		return x.Instructions
+	}
+	return ""
+}
+
+func (x *MealResponse) GetImagePath() string {
+	if x != nil {
+		return x.ImagePath
+	}
+	return ""
+}
+
+type MealResponses struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Meals []*MealResponse `protobuf:"bytes,1,rep,name=meals,proto3" json:"meals,omitempty"`
+}
+
+func (x *MealResponses) Reset() {
+	*x = MealResponses{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealResponses) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealResponses) ProtoMessage() {}
+
+func (x *MealResponses) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealResponses.ProtoReflect.Descriptor instead.
+func (*MealResponses) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *MealResponses) GetMeals() []*MealResponse {
+	if x != nil {
+		return x.Meals
+	}
+	return nil
+}
+
+type MealOverviewResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id        int32  `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+	Name      string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+	ImagePath string `protobuf:"bytes,3,opt,name=imagePath,proto3" json:"imagePath,omitempty"`
+}
+
+func (x *MealOverviewResponse) Reset() {
+	*x = MealOverviewResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealOverviewResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealOverviewResponse) ProtoMessage() {}
+
+func (x *MealOverviewResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealOverviewResponse.ProtoReflect.Descriptor instead.
+func (*MealOverviewResponse) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *MealOverviewResponse) GetId() int32 {
+	if x != nil {
+		return x.Id
+	}
+	return 0
+}
+
+func (x *MealOverviewResponse) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *MealOverviewResponse) GetImagePath() string {
+	if x != nil {
+		return x.ImagePath
+	}
+	return ""
+}
+
+type MealOverviewResponses struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Meals []*MealOverviewResponse `protobuf:"bytes,1,rep,name=meals,proto3" json:"meals,omitempty"`
+}
+
+func (x *MealOverviewResponses) Reset() {
+	*x = MealOverviewResponses{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *MealOverviewResponses) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MealOverviewResponses) ProtoMessage() {}
+
+func (x *MealOverviewResponses) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use MealOverviewResponses.ProtoReflect.Descriptor instead.
+func (*MealOverviewResponses) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *MealOverviewResponses) GetMeals() []*MealOverviewResponse {
+	if x != nil {
+		return x.Meals
+	}
+	return nil
+}
+
+type FilterOverviewResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	ValidValues []string `protobuf:"bytes,1,rep,name=validValues,proto3" json:"validValues,omitempty"`
+}
+
+func (x *FilterOverviewResponse) Reset() {
+	*x = FilterOverviewResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_meal_meal_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FilterOverviewResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FilterOverviewResponse) ProtoMessage() {}
+
+func (x *FilterOverviewResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_meal_meal_proto_msgTypes[9]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FilterOverviewResponse.ProtoReflect.Descriptor instead.
+func (*FilterOverviewResponse) Descriptor() ([]byte, []int) {
+	return file_meal_meal_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *FilterOverviewResponse) GetValidValues() []string {
+	if x != nil {
+		return x.ValidValues
+	}
+	return nil
+}
+
+var File_meal_meal_proto protoreflect.FileDescriptor
+
+var file_meal_meal_proto_rawDesc = []byte{
+	0x0a, 0x0f, 0x6d, 0x65, 0x61, 0x6c, 0x2f, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x12, 0x04, 0x6d, 0x65, 0x61, 0x6c, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1d, 0x0a, 0x0b, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
+	0x02, 0x69, 0x64, 0x22, 0x43, 0x0a, 0x13, 0x4d, 0x65, 0x61, 0x6c, 0x4f, 0x76, 0x65, 0x72, 0x76,
+	0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x2f, 0x0a, 0x15, 0x46, 0x69, 0x6c, 0x74,
+	0x65, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x23, 0x0a, 0x0d, 0x53, 0x65, 0x61,
+	0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x40,
+	0x0a, 0x12, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75,
+	0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
+	0x22, 0xcc, 0x01, 0x0a, 0x0c, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69,
+	0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72,
+	0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72,
+	0x79, 0x12, 0x3a, 0x0a, 0x0b, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x73,
+	0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x49, 0x6e,
+	0x67, 0x72, 0x65, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x52, 0x0b, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x22, 0x0a,
+	0x0c, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x50, 0x61, 0x74, 0x68, 0x22,
+	0x39, 0x0a, 0x0d, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73,
+	0x12, 0x28, 0x0a, 0x05, 0x6d, 0x65, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x12, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x52, 0x05, 0x6d, 0x65, 0x61, 0x6c, 0x73, 0x22, 0x58, 0x0a, 0x14, 0x4d, 0x65,
+	0x61, 0x6c, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02,
+	0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x50,
+	0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65,
+	0x50, 0x61, 0x74, 0x68, 0x22, 0x49, 0x0a, 0x15, 0x4d, 0x65, 0x61, 0x6c, 0x4f, 0x76, 0x65, 0x72,
+	0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x30, 0x0a,
+	0x05, 0x6d, 0x65, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d,
+	0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x6d, 0x65, 0x61, 0x6c, 0x73, 0x22,
+	0x3a, 0x0a, 0x16, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65,
+	0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x76, 0x61, 0x6c,
+	0x69, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b,
+	0x76, 0x61, 0x6c, 0x69, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x32, 0xcd, 0x02, 0x0a, 0x04,
+	0x4d, 0x65, 0x61, 0x6c, 0x12, 0x3d, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x52, 0x61, 0x6e, 0x64, 0x6f,
+	0x6d, 0x4d, 0x65, 0x61, 0x6c, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e,
+	0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x61, 0x6c, 0x12, 0x11,
+	0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x12, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x10, 0x53, 0x65, 0x61, 0x72, 0x63,
+	0x68, 0x4d, 0x65, 0x61, 0x6c, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x13, 0x2e, 0x6d, 0x65,
+	0x61, 0x6c, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x1a, 0x13, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63,
+	0x68, 0x4d, 0x65, 0x61, 0x6c, 0x42, 0x79, 0x12, 0x19, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d,
+	0x65, 0x61, 0x6c, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x4d, 0x65, 0x61, 0x6c, 0x4f, 0x76,
+	0x65, 0x72, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22,
+	0x00, 0x12, 0x48, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1b,
+	0x2e, 0x6d, 0x65, 0x61, 0x6c, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x76, 0x65, 0x72,
+	0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6d, 0x65,
+	0x61, 0x6c, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x76, 0x69, 0x65,
+	0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x50, 0x5a, 0x4e, 0x67,
+	0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x72, 0x65, 0x75, 0x74, 0x6c, 0x69, 0x6e, 0x67, 0x65, 0x6e,
+	0x2d, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x69, 0x74, 0x79, 0x2e, 0x64, 0x65, 0x2f, 0x79,
+	0x65, 0x73, 0x69, 0x6c, 0x64, 0x61, 0x73, 0x2f, 0x6d, 0x65, 0x61, 0x6c, 0x70, 0x6c, 0x61, 0x6e,
+	0x6e, 0x65, 0x72, 0x32, 0x67, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x6d,
+	0x65, 0x61, 0x6c, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x6d, 0x65, 0x61, 0x6c, 0x62, 0x06, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_meal_meal_proto_rawDescOnce sync.Once
+	file_meal_meal_proto_rawDescData = file_meal_meal_proto_rawDesc
+)
+
+func file_meal_meal_proto_rawDescGZIP() []byte {
+	file_meal_meal_proto_rawDescOnce.Do(func() {
+		file_meal_meal_proto_rawDescData = protoimpl.X.CompressGZIP(file_meal_meal_proto_rawDescData)
+	})
+	return file_meal_meal_proto_rawDescData
+}
+
+var file_meal_meal_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
+var file_meal_meal_proto_goTypes = []interface{}{
+	(*MealRequest)(nil),            // 0: meal.MealRequest
+	(*MealOverviewRequest)(nil),    // 1: meal.MealOverviewRequest
+	(*FilterOverviewRequest)(nil),  // 2: meal.FilterOverviewRequest
+	(*SearchRequest)(nil),          // 3: meal.SearchRequest
+	(*IngredientResponse)(nil),     // 4: meal.IngredientResponse
+	(*MealResponse)(nil),           // 5: meal.MealResponse
+	(*MealResponses)(nil),          // 6: meal.MealResponses
+	(*MealOverviewResponse)(nil),   // 7: meal.MealOverviewResponse
+	(*MealOverviewResponses)(nil),  // 8: meal.MealOverviewResponses
+	(*FilterOverviewResponse)(nil), // 9: meal.FilterOverviewResponse
+	(*emptypb.Empty)(nil),          // 10: google.protobuf.Empty
+}
+var file_meal_meal_proto_depIdxs = []int32{
+	4,  // 0: meal.MealResponse.ingredients:type_name -> meal.IngredientResponse
+	5,  // 1: meal.MealResponses.meals:type_name -> meal.MealResponse
+	7,  // 2: meal.MealOverviewResponses.meals:type_name -> meal.MealOverviewResponse
+	10, // 3: meal.Meal.GetRandomMeal:input_type -> google.protobuf.Empty
+	0,  // 4: meal.Meal.GetMeal:input_type -> meal.MealRequest
+	3,  // 5: meal.Meal.SearchMealByName:input_type -> meal.SearchRequest
+	1,  // 6: meal.Meal.SearchMealBy:input_type -> meal.MealOverviewRequest
+	2,  // 7: meal.Meal.GetFilter:input_type -> meal.FilterOverviewRequest
+	5,  // 8: meal.Meal.GetRandomMeal:output_type -> meal.MealResponse
+	5,  // 9: meal.Meal.GetMeal:output_type -> meal.MealResponse
+	6,  // 10: meal.Meal.SearchMealByName:output_type -> meal.MealResponses
+	8,  // 11: meal.Meal.SearchMealBy:output_type -> meal.MealOverviewResponses
+	9,  // 12: meal.Meal.GetFilter:output_type -> meal.FilterOverviewResponse
+	8,  // [8:13] is the sub-list for method output_type
+	3,  // [3:8] is the sub-list for method input_type
+	3,  // [3:3] is the sub-list for extension type_name
+	3,  // [3:3] is the sub-list for extension extendee
+	0,  // [0:3] is the sub-list for field type_name
+}
+
+func init() { file_meal_meal_proto_init() }
+func file_meal_meal_proto_init() {
+	if File_meal_meal_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_meal_meal_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealOverviewRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FilterOverviewRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SearchRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*IngredientResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealResponses); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealOverviewResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MealOverviewResponses); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_meal_meal_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FilterOverviewResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_meal_meal_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   10,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_meal_meal_proto_goTypes,
+		DependencyIndexes: file_meal_meal_proto_depIdxs,
+		MessageInfos:      file_meal_meal_proto_msgTypes,
+	}.Build()
+	File_meal_meal_proto = out.File
+	file_meal_meal_proto_rawDesc = nil
+	file_meal_meal_proto_goTypes = nil
+	file_meal_meal_proto_depIdxs = nil
+}
diff --git a/service/planner/client/meal/meal.proto b/service/planner/client/meal/meal.proto
new file mode 100644
index 0000000000000000000000000000000000000000..63d7313fa2877f3de14eeabc388e8b85f32d93d2
--- /dev/null
+++ b/service/planner/client/meal/meal.proto
@@ -0,0 +1,64 @@
+syntax = "proto3";
+
+package meal;
+
+import "google/protobuf/empty.proto";
+
+option go_package = "gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/grpc/meal";
+
+service Meal {
+    rpc GetRandomMeal(google.protobuf.Empty) returns (MealResponse) {}
+    rpc GetMeal(MealRequest) returns (MealResponse) {}
+    rpc SearchMealByName(SearchRequest) returns (MealResponses) {}
+    rpc SearchMealBy(MealOverviewRequest) returns (MealOverviewResponses) {}
+    rpc GetFilter(FilterOverviewRequest) returns (FilterOverviewResponse) {}
+}
+
+message MealRequest {
+    int32 id = 1;
+}
+
+message MealOverviewRequest {
+    string value = 1;
+    string filter = 2;
+}
+
+message FilterOverviewRequest {
+    string filter = 1;
+}
+
+message SearchRequest {
+    string name = 1;
+}
+
+message IngredientResponse {
+    string name = 1;
+    string amount = 2;
+}
+
+message MealResponse {
+    int32 id = 1;
+    string name = 2;
+    string category = 3;
+    repeated IngredientResponse ingredients = 4;
+    string instructions = 5;
+    string imagePath = 6;
+}
+
+message MealResponses {
+    repeated MealResponse meals = 1;
+}
+
+message MealOverviewResponse {
+    int32 id = 1;
+    string name = 2;
+    string imagePath = 3;
+}
+
+message MealOverviewResponses {
+    repeated MealOverviewResponse meals = 1;
+}
+
+message FilterOverviewResponse {
+    repeated string validValues = 1;
+}
\ No newline at end of file
diff --git a/service/planner/client/meal/meal_grpc.pb.go b/service/planner/client/meal/meal_grpc.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..f24057f56162d136e679f23feab7d792f9e004a2
--- /dev/null
+++ b/service/planner/client/meal/meal_grpc.pb.go
@@ -0,0 +1,250 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.2.0
+// - protoc             v4.23.3
+// source: meal/meal.proto
+
+package meal
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+	emptypb "google.golang.org/protobuf/types/known/emptypb"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// MealClient is the client API for Meal service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type MealClient interface {
+	GetRandomMeal(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MealResponse, error)
+	GetMeal(ctx context.Context, in *MealRequest, opts ...grpc.CallOption) (*MealResponse, error)
+	SearchMealByName(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*MealResponses, error)
+	SearchMealBy(ctx context.Context, in *MealOverviewRequest, opts ...grpc.CallOption) (*MealOverviewResponses, error)
+	GetFilter(ctx context.Context, in *FilterOverviewRequest, opts ...grpc.CallOption) (*FilterOverviewResponse, error)
+}
+
+type mealClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewMealClient(cc grpc.ClientConnInterface) MealClient {
+	return &mealClient{cc}
+}
+
+func (c *mealClient) GetRandomMeal(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*MealResponse, error) {
+	out := new(MealResponse)
+	err := c.cc.Invoke(ctx, "/meal.Meal/GetRandomMeal", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *mealClient) GetMeal(ctx context.Context, in *MealRequest, opts ...grpc.CallOption) (*MealResponse, error) {
+	out := new(MealResponse)
+	err := c.cc.Invoke(ctx, "/meal.Meal/GetMeal", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *mealClient) SearchMealByName(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*MealResponses, error) {
+	out := new(MealResponses)
+	err := c.cc.Invoke(ctx, "/meal.Meal/SearchMealByName", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *mealClient) SearchMealBy(ctx context.Context, in *MealOverviewRequest, opts ...grpc.CallOption) (*MealOverviewResponses, error) {
+	out := new(MealOverviewResponses)
+	err := c.cc.Invoke(ctx, "/meal.Meal/SearchMealBy", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *mealClient) GetFilter(ctx context.Context, in *FilterOverviewRequest, opts ...grpc.CallOption) (*FilterOverviewResponse, error) {
+	out := new(FilterOverviewResponse)
+	err := c.cc.Invoke(ctx, "/meal.Meal/GetFilter", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// MealServer is the server API for Meal service.
+// All implementations must embed UnimplementedMealServer
+// for forward compatibility
+type MealServer interface {
+	GetRandomMeal(context.Context, *emptypb.Empty) (*MealResponse, error)
+	GetMeal(context.Context, *MealRequest) (*MealResponse, error)
+	SearchMealByName(context.Context, *SearchRequest) (*MealResponses, error)
+	SearchMealBy(context.Context, *MealOverviewRequest) (*MealOverviewResponses, error)
+	GetFilter(context.Context, *FilterOverviewRequest) (*FilterOverviewResponse, error)
+	mustEmbedUnimplementedMealServer()
+}
+
+// UnimplementedMealServer must be embedded to have forward compatible implementations.
+type UnimplementedMealServer struct {
+}
+
+func (UnimplementedMealServer) GetRandomMeal(context.Context, *emptypb.Empty) (*MealResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetRandomMeal not implemented")
+}
+func (UnimplementedMealServer) GetMeal(context.Context, *MealRequest) (*MealResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetMeal not implemented")
+}
+func (UnimplementedMealServer) SearchMealByName(context.Context, *SearchRequest) (*MealResponses, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SearchMealByName not implemented")
+}
+func (UnimplementedMealServer) SearchMealBy(context.Context, *MealOverviewRequest) (*MealOverviewResponses, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SearchMealBy not implemented")
+}
+func (UnimplementedMealServer) GetFilter(context.Context, *FilterOverviewRequest) (*FilterOverviewResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetFilter not implemented")
+}
+func (UnimplementedMealServer) mustEmbedUnimplementedMealServer() {}
+
+// UnsafeMealServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to MealServer will
+// result in compilation errors.
+type UnsafeMealServer interface {
+	mustEmbedUnimplementedMealServer()
+}
+
+func RegisterMealServer(s grpc.ServiceRegistrar, srv MealServer) {
+	s.RegisterService(&Meal_ServiceDesc, srv)
+}
+
+func _Meal_GetRandomMeal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(emptypb.Empty)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MealServer).GetRandomMeal(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/meal.Meal/GetRandomMeal",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MealServer).GetRandomMeal(ctx, req.(*emptypb.Empty))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Meal_GetMeal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MealRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MealServer).GetMeal(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/meal.Meal/GetMeal",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MealServer).GetMeal(ctx, req.(*MealRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Meal_SearchMealByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SearchRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MealServer).SearchMealByName(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/meal.Meal/SearchMealByName",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MealServer).SearchMealByName(ctx, req.(*SearchRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Meal_SearchMealBy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(MealOverviewRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MealServer).SearchMealBy(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/meal.Meal/SearchMealBy",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MealServer).SearchMealBy(ctx, req.(*MealOverviewRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _Meal_GetFilter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(FilterOverviewRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(MealServer).GetFilter(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/meal.Meal/GetFilter",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(MealServer).GetFilter(ctx, req.(*FilterOverviewRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// Meal_ServiceDesc is the grpc.ServiceDesc for Meal service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Meal_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "meal.Meal",
+	HandlerType: (*MealServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "GetRandomMeal",
+			Handler:    _Meal_GetRandomMeal_Handler,
+		},
+		{
+			MethodName: "GetMeal",
+			Handler:    _Meal_GetMeal_Handler,
+		},
+		{
+			MethodName: "SearchMealByName",
+			Handler:    _Meal_SearchMealByName_Handler,
+		},
+		{
+			MethodName: "SearchMealBy",
+			Handler:    _Meal_SearchMealBy_Handler,
+		},
+		{
+			MethodName: "GetFilter",
+			Handler:    _Meal_GetFilter_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "meal/meal.proto",
+}
diff --git a/service/planner/go.mod b/service/planner/go.mod
index 20eaab5fdf8eb9ceede13768a8971b5a922a863a..586ee6ef070bca59cb579a6e6937cf046d5d54f7 100644
--- a/service/planner/go.mod
+++ b/service/planner/go.mod
@@ -7,10 +7,13 @@ require (
 	github.com/gorilla/mux v1.8.0
 	github.com/sirupsen/logrus v1.9.3
 	github.com/spf13/viper v1.16.0
+	google.golang.org/grpc v1.55.0
+	google.golang.org/protobuf v1.30.0
 )
 
 require (
 	github.com/fsnotify/fsnotify v1.6.0 // indirect
+	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -20,8 +23,10 @@ require (
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/subosito/gotenv v1.4.2 // indirect
+	golang.org/x/net v0.10.0 // indirect
 	golang.org/x/sys v0.8.0 // indirect
 	golang.org/x/text v0.9.0 // indirect
+	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/service/planner/go.sum b/service/planner/go.sum
index ce66f6a326178ab86dc4c52d836a2e65b93e028a..9e732ae9b9256e1cbf6dbb10ff902c75b12d25cf 100644
--- a/service/planner/go.sum
+++ b/service/planner/go.sum
@@ -88,6 +88,9 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -99,6 +102,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -255,6 +259,8 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -440,6 +446,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -456,6 +464,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
 google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
 google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
+google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -466,6 +476,10 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
+google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/service/meal/handler/meal.go b/service/planner/handler/meal-client.go
similarity index 98%
rename from service/meal/handler/meal.go
rename to service/planner/handler/meal-client.go
index 13b1612c8f76df6dac945641f57a430b761336a2..4bf67abb130309d09178661919874691a1ac15c4 100644
--- a/service/meal/handler/meal.go
+++ b/service/planner/handler/meal-client.go
@@ -3,8 +3,8 @@ package handler
 import (
 	"net/http"
 
-	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/model"
-	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/meal/service"
+	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/planner/model"
+	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/planner/service"
 )
 
 func GetRandomMeal(w http.ResponseWriter, r *http.Request) {
diff --git a/service/planner/handler/utils.go b/service/planner/handler/utils.go
index 92a7066b5edc415fe8333499672c7f1cebd3477c..60cefdcc04bf1f1284439cfb9da02953e25eeadc 100644
--- a/service/planner/handler/utils.go
+++ b/service/planner/handler/utils.go
@@ -41,3 +41,8 @@ func getGroupId(r *http.Request) (int, error) {
 	}
 	return id, nil
 }
+
+func getValue(r *http.Request) string {
+	vars := mux.Vars(r)
+	return vars["value"]
+}
diff --git a/service/planner/main.go b/service/planner/main.go
index 49d7e79f47f6a86ba3450ede1a81d4ae7971bc8f..af28c06b8a98e202140046aaf832c6a42a958e8c 100644
--- a/service/planner/main.go
+++ b/service/planner/main.go
@@ -50,6 +50,15 @@ func main() {
 	router.HandleFunc("/group/{id}", handler.DeleteGroup).Methods(http.MethodDelete)
 	router.HandleFunc("/group", handler.GetGroups).Methods(http.MethodGet)
 	router.HandleFunc("/group", handler.CreateGroup).Methods(http.MethodPost)
+	router.HandleFunc("/meal/random", handler.GetRandomMeal).Methods(http.MethodGet)
+	router.HandleFunc("/meal/search/{value}", handler.SearchMealByName).Methods(http.MethodGet)
+	router.HandleFunc("/meal/category/{value}", handler.SearchMealByCategory).Methods(http.MethodGet)
+	router.HandleFunc("/meal/category", handler.GetCategoryOverview).Methods(http.MethodGet)
+	router.HandleFunc("/meal/area/{value}", handler.SearchMealByArea).Methods(http.MethodGet)
+	router.HandleFunc("/meal/area", handler.GetAreaOverview).Methods(http.MethodGet)
+	router.HandleFunc("/meal/ingredient/{value}", handler.SearchMealByIngredient).Methods(http.MethodGet)
+	router.HandleFunc("/meal/ingredient", handler.GetIngredientOverview).Methods(http.MethodGet)
+	router.HandleFunc("/meal/{id}", handler.GetMeal).Methods(http.MethodGet)
 	log.Infof("Server is listening on port :%v\n", port)
 	if err := http.ListenAndServe(fmt.Sprintf(":%v", port), router); err != nil {
 		log.Fatal(err)
diff --git a/service/planner/model/meal.go b/service/planner/model/meal.go
index a280c0809aa8f01e0564c9d20a1b205efd81c069..0942c8545d2432e43caa2604882d1042990f4072 100644
--- a/service/planner/model/meal.go
+++ b/service/planner/model/meal.go
@@ -25,3 +25,35 @@ type GroupMealWithId struct {
 	MealID  int    `json:"mealId"`
 	Date    string `json:"date"`
 }
+
+type Ingredient struct {
+	Name   string `json:"name"`
+	Amount string `json:"amount"`
+}
+
+type Meal struct {
+	ID           int           `json:"id"`
+	Name         string        `json:"name"`
+	Category     string        `json:"category"`
+	Ingredients  []*Ingredient `json:"ingredients"`
+	Instructions string        `json:"instructions"`
+	ImagePath    string        `json:"imagePath"`
+}
+
+type MealOverview struct {
+	ID        int    `json:"id"`
+	Name      string `json:"name"`
+	ImagePath string `json:"imagePath"`
+}
+
+type FilterOverview struct {
+	ValidValues []string `json:"validValues"`
+}
+
+const (
+	CATEGORY   Filter = "c"
+	AREA       Filter = "a"
+	INGREDIENT Filter = "i"
+)
+
+type Filter string
diff --git a/service/planner/service/meal-client.go b/service/planner/service/meal-client.go
new file mode 100644
index 0000000000000000000000000000000000000000..64086a9c33cfb84c9a32cd95b92f02d49efeb6f3
--- /dev/null
+++ b/service/planner/service/meal-client.go
@@ -0,0 +1,145 @@
+package service
+
+import (
+	"context"
+	"log"
+	"time"
+
+	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/planner/client"
+	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/planner/client/meal"
+	"gitlab.reutlingen-university.de/yesildas/mealplanner2go/service/planner/model"
+	"google.golang.org/protobuf/types/known/emptypb"
+)
+
+func convertMealResponseToModel(res *meal.MealResponse) *model.Meal {
+	result := &model.Meal{
+		ID:           int(res.Id),
+		Name:         res.Name,
+		Category:     res.Category,
+		Instructions: res.Instructions,
+		ImagePath:    res.ImagePath,
+	}
+
+	for _, v := range res.Ingredients {
+		ingredient := &model.Ingredient{
+			Name:   v.Name,
+			Amount: v.Amount,
+		}
+		result.Ingredients = append(result.Ingredients, ingredient)
+	}
+
+	return result
+}
+
+func convertMealResponsesToModel(res *meal.MealResponses) []*model.Meal {
+	var result []*model.Meal
+	for _, v := range res.Meals {
+		result = append(result, convertMealResponseToModel(v))
+	}
+
+	return result
+}
+
+func convertMealOverviewResponseToModel(res *meal.MealOverviewResponse) *model.MealOverview {
+	return &model.MealOverview{
+		ID:        int(res.Id),
+		Name:      res.Name,
+		ImagePath: res.ImagePath,
+	}
+}
+
+func convertMealOverviewResponsesToModel(res *meal.MealOverviewResponses) []*model.MealOverview {
+	var result []*model.MealOverview
+	for _, v := range res.Meals {
+		result = append(result, convertMealOverviewResponseToModel(v))
+	}
+
+	return result
+}
+
+func GetRandomMeal() (*model.Meal, error) {
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+	conn, err := client.GetMealConnection(ctx)
+	if err != nil {
+		log.Fatal("error connecting to the banktransfer service\n")
+	}
+	defer conn.Close()
+	client := meal.NewMealClient(conn)
+	res, err := client.GetRandomMeal(ctx, &emptypb.Empty{})
+	if err != nil {
+		return nil, err
+	}
+
+	return convertMealResponseToModel(res), nil
+}
+
+func GetMeal(id int) (*model.Meal, error) {
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+	conn, err := client.GetMealConnection(ctx)
+	if err != nil {
+		log.Fatal("error connecting to the banktransfer service\n")
+	}
+	defer conn.Close()
+	client := meal.NewMealClient(conn)
+	res, err := client.GetMeal(ctx, &meal.MealRequest{Id: int32(id)})
+	if err != nil {
+		return nil, err
+	}
+
+	return convertMealResponseToModel(res), nil
+}
+
+func SearchMealByName(name string) ([]*model.Meal, error) {
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+	conn, err := client.GetMealConnection(ctx)
+	if err != nil {
+		log.Fatal("error connecting to the banktransfer service\n")
+	}
+	defer conn.Close()
+	client := meal.NewMealClient(conn)
+	res, err := client.SearchMealByName(ctx, &meal.SearchRequest{Name: name})
+	if err != nil {
+		return nil, err
+	}
+
+	return convertMealResponsesToModel(res), nil
+}
+
+func SearchMealBy(value string, filter model.Filter) ([]*model.MealOverview, error) {
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+	conn, err := client.GetMealConnection(ctx)
+	if err != nil {
+		log.Fatal("error connecting to the banktransfer service\n")
+	}
+	defer conn.Close()
+	client := meal.NewMealClient(conn)
+	res, err := client.SearchMealBy(ctx, &meal.MealOverviewRequest{Value: value, Filter: string(filter)})
+	if err != nil {
+		return nil, err
+	}
+
+	return convertMealOverviewResponsesToModel(res), nil
+}
+
+func GetFilter(filter model.Filter) (*model.FilterOverview, error) {
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+	conn, err := client.GetMealConnection(ctx)
+	if err != nil {
+		log.Fatal("error connecting to the banktransfer service\n")
+	}
+	defer conn.Close()
+	client := meal.NewMealClient(conn)
+	res, err := client.GetFilter(ctx, &meal.FilterOverviewRequest{Filter: string(filter)})
+	if err != nil {
+		return nil, err
+	}
+
+	return &model.FilterOverview{
+		ValidValues: res.ValidValues,
+	}, nil
+}