diff --git a/brave_test.go b/brave_test.go
index 165f725..1eec16b 100644
--- a/brave_test.go
+++ b/brave_test.go
@@ -11,6 +11,7 @@ import (
"dev.freespoke.com/brave-search"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestWeb(t *testing.T) {
@@ -125,6 +126,29 @@ func TestDuration(t *testing.T) {
}
}
+func TestRecipe(t *testing.T) {
+ svr := getTestServer("testdata/web_recipe.json", 200)
+
+ client, err := brave.New("fake", brave.WithHTTPClient(svr.Client()), brave.WithBaseURL(svr.URL))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ res, err := client.WebSearch(context.Background(), "speaker of the house")
+ require.Nil(t, err)
+ require.NotNil(t, res)
+
+ results := res.Web.Results
+ require.Len(t, results, 1)
+ r := results[0]
+ require.NotNil(t, r.Recipe)
+ require.Equal(t, "recipe", r.Subtype)
+
+ assert.Equal(t, "Chicken Alfredo", r.Recipe.Title)
+ assert.Equal(t, "desc", r.Recipe.Description)
+ assert.Equal(t, 40*time.Minute, *r.Recipe.Time.Duration())
+}
+
func getTestServer(file string, status int) *httptest.Server {
body, err := os.ReadFile(file)
if err != nil {
diff --git a/testdata/web_recipe.json b/testdata/web_recipe.json
new file mode 100644
index 0000000..64d4d2b
--- /dev/null
+++ b/testdata/web_recipe.json
@@ -0,0 +1,153 @@
+{
+ "web": {
+ "type": "search",
+ "results": [
+ {
+ "title": "Chicken Alfredo - Budget Bytes",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/",
+ "is_source_local": false,
+ "is_source_both": false,
+ "description": "This Chicken Alfredo features pasta drenched in an ultra-rich and creamy sauce and topped with juicy strips of seared chicken.",
+ "page_age": "2023-03-01T13:33:51",
+ "profile": {
+ "name": "Budget Bytes",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/",
+ "long_name": "budgetbytes.com",
+ "img": "https://imgs.search.brave.com/pTJbHVZz_ZBD3RWwYBcuyh5zjzyCR6QLy5afccTBe4U/rs:fit:32:32:1:0/g:ce/aHR0cDovL2Zhdmlj/b25zLnNlYXJjaC5i/cmF2ZS5jb20vaWNv/bnMvZTIwZWZjYTcz/MWI2MTdiNzhiZDAy/ZGJkNzcwMjQ4NTVk/YjIxMjYyMTBlYmYy/ODRhYzJjYWM0NjMz/YjI1ZWIwOC93d3cu/YnVkZ2V0Ynl0ZXMu/Y29tLw"
+ },
+ "language": "en",
+ "family_friendly": true,
+ "type": "search_result",
+ "subtype": "recipe",
+ "meta_url": {
+ "scheme": "https",
+ "netloc": "budgetbytes.com",
+ "hostname": "www.budgetbytes.com",
+ "favicon": "https://imgs.search.brave.com/pTJbHVZz_ZBD3RWwYBcuyh5zjzyCR6QLy5afccTBe4U/rs:fit:32:32:1:0/g:ce/aHR0cDovL2Zhdmlj/b25zLnNlYXJjaC5i/cmF2ZS5jb20vaWNv/bnMvZTIwZWZjYTcz/MWI2MTdiNzhiZDAy/ZGJkNzcwMjQ4NTVk/YjIxMjYyMTBlYmYy/ODRhYzJjYWM0NjMz/YjI1ZWIwOC93d3cu/YnVkZ2V0Ynl0ZXMu/Y29tLw",
+ "path": " › budget bytes › recipes › meat recipes › chicken recipes › chicken alfredo"
+ },
+ "thumbnail": {
+ "src": "https://imgs.search.brave.com/cmhiGR62ts8HtdJ-2BiFON9OdFaFLFQiE5D0ybUe9ck/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/YnVkZ2V0Ynl0ZXMu/Y29tL3dwLWNvbnRl/bnQvdXBsb2Fkcy8y/MDIyLzA3L0NoaWNr/ZW4tQWxmcmVkby1i/b3dsLmpwZw",
+ "original": "https://www.budgetbytes.com/wp-content/uploads/2022/07/Chicken-Alfredo-bowl.jpg",
+ "logo": false
+ },
+ "age": "March 1, 2023",
+ "video": {
+ "duration": "00:52",
+ "thumbnail": {
+ "src": "https://imgs.search.brave.com/P1KRHUV8JVXCRAc1KSF529sEXyvqQPJy4L7pk9aZ1Lc/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9tZWRp/YXZpbmUtcmVzLmNs/b3VkaW5hcnkuY29t/L2ltYWdlL3VwbG9h/ZC9zLS1VMFMzdHRT/Zi0tL2NfbGltaXQs/Zl9hdXRvLGZsX2xv/c3N5LGhfMTA4MCxx/X2F1dG8sd18xOTIw/L3YxNjY1MTUyMTYz/L2MxYWlncGdndnZv/dHlkcXhhY2duLmpw/Zw",
+ "original": "https://mediavine-res.cloudinary.com/image/upload/s--U0S3ttSf--/c_limit,f_auto,fl_lossy,h_1080,q_auto,w_1920/v1665152163/c1aigpggvvotydqxacgn.jpg"
+ }
+ },
+ "article": {
+ "author": [
+ {
+ "type": "person",
+ "name": "Beth - Budget Bytes"
+ }
+ ],
+ "date": "Jul 25, 2022",
+ "publisher": {
+ "type": "organization",
+ "name": "Budget Bytes",
+ "url": "https://www.budgetbytes.com/",
+ "thumbnail": {
+ "src": "https://imgs.search.brave.com/8Shgd_Y8noQ0XbCBZRR_A9CDr60fX2JaqoNVceYzQ4o/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/YnVkZ2V0Ynl0ZXMu/Y29tL3dwLWNvbnRl/bnQvdXBsb2Fkcy8y/MDIwLzExL2J1ZGdl/dGJ5dGVzX3NxdWFy/ZV9pY29uX3RyYW5z/cGFyZW50LnBuZw",
+ "original": "https://www.budgetbytes.com/wp-content/uploads/2020/11/budgetbytes_square_icon_transparent.png"
+ }
+ }
+ },
+ "recipe": {
+ "title": "Chicken Alfredo",
+ "description": "desc",
+ "thumbnail": {
+ "src": "https://imgs.search.brave.com/DYRTJR9GHBYwCOUuT--74UX5K_g2j1XkMyRsgTQ4r-Q/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly93d3cu/YnVkZ2V0Ynl0ZXMu/Y29tL3dwLWNvbnRl/bnQvdXBsb2Fkcy8y/MDIyLzA3L0NoaWNr/ZW4tQWxmcmVkby1h/Ym92ZS5qcGc",
+ "original": "https://www.budgetbytes.com/wp-content/uploads/2022/07/Chicken-Alfredo-above.jpg"
+ },
+ "url": "https://www.budgetbytes.com/chicken-alfredo/",
+ "domain": "budgetbytes.com",
+ "favicon": "https://imgs.search.brave.com/pTJbHVZz_ZBD3RWwYBcuyh5zjzyCR6QLy5afccTBe4U/rs:fit:32:32:1:0/g:ce/aHR0cDovL2Zhdmlj/b25zLnNlYXJjaC5i/cmF2ZS5jb20vaWNv/bnMvZTIwZWZjYTcz/MWI2MTdiNzhiZDAy/ZGJkNzcwMjQ4NTVk/YjIxMjYyMTBlYmYy/ODRhYzJjYWM0NjMz/YjI1ZWIwOC93d3cu/YnVkZ2V0Ynl0ZXMu/Y29tLw",
+ "time": "40:00",
+ "prep_time": "05:00",
+ "cook_time": "35:00",
+ "ingredients": "2 boneless, skinless chicken breasts (about 1.3 lb. total) ($6.49), 2 tsp Italian seasoning ($0.20), 1 Tbsp cooking oil ($0.04), 2 Tbsp butter ($0.22), 4 cloves garlic, minced ($0.32), 1 cup heavy cream ($1.25), 3/4 cup grated Parmesan ($1.08), 1/4 tsp salt ($0.02), 1/4 tsp pepper ($0.02), 1 Tbsp chopped parsley (optional garnish) ($0.10), 8 oz. fettuccine ($0.88)",
+ "instructions": [
+ {
+ "text": "Season both sides of the chicken breast with Italian seasoning and a pinch of salt.",
+ "name": "Season both sides of the chicken breast with Italian seasoning and a pinch of salt.",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/#wprm-recipe-67806-step-0-0",
+ "image": []
+ },
+ {
+ "text": "Heat a large skillet over medium. Once hot, add the cooking oil and swirl to coat the surface. Add the chicken to the skillet and cook for about 7-8 minutes on each side, or until browned on the outside and cooked through.",
+ "name": "Heat a large skillet over medium. Once hot, add the cooking oil and swirl to coat the surface. Add the chicken to the skillet and cook for about 7-8 minutes on each side, or until browned on the outside and cooked through.",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/#wprm-recipe-67806-step-0-1",
+ "image": []
+ },
+ {
+ "text": "Remove the chicken to a clean plate and turn the heat under the skillet down to medium-low.",
+ "name": "Remove the chicken to a clean plate and turn the heat under the skillet down to medium-low.",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/#wprm-recipe-67806-step-0-2",
+ "image": []
+ },
+ {
+ "text": "Add the butter and minced garlic to the skillet. Stir and cook the garlic in the melted butter for about two minutes, dissolving the browned bits from the bottom of the skillet as you stir.",
+ "name": "Add the butter and minced garlic to the skillet. Stir and cook the garlic in the melted butter for about two minutes, dissolving the browned bits from the bottom of the skillet as you stir.",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/#wprm-recipe-67806-step-0-3",
+ "image": []
+ },
+ {
+ "text": "Add the heavy cream and whisk to combine, dissolving any remaining browned bits. Allow the cream to come up to a simmer.",
+ "name": "Add the heavy cream and whisk to combine, dissolving any remaining browned bits. Allow the cream to come up to a simmer.",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/#wprm-recipe-67806-step-0-4",
+ "image": []
+ },
+ {
+ "text": "While waiting for the cream to simmer, bring a pot of water to a boil for the fettuccine. Once boiling, add the pasta and continue to boil until tender (about 7 minutes). Reserve about ½ cup of the starchy cooking water just before draining the pasta.",
+ "name": "While waiting for the cream to simmer, bring a pot of water to a boil for the fettuccine. Once boiling, add the pasta and continue to boil until tender (about 7 minutes). Reserve about ½ cup of the starchy cooking water just before draining the pasta.",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/#wprm-recipe-67806-step-0-5",
+ "image": []
+ },
+ {
+ "text": "Once the cream is simmering, add the grated Parmesan to the skillet. Continue to whisk and stir until the Parmesan has melted into the sauce and the sauce has begun to simmer. Simmer the sauce for a few minutes, or until it becomes slightly thicker. Add salt and pepper to the sauce to taste.",
+ "name": "Once the cream is simmering, add the grated Parmesan to the skillet. Continue to whisk and stir until the Parmesan has melted into the sauce and the sauce has begun to simmer. Simmer the sauce for a few minutes, or until it becomes slightly thicker. Add salt and pepper to the sauce to taste.",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/#wprm-recipe-67806-step-0-6",
+ "image": []
+ },
+ {
+ "text": "Add the drained pasta to the skillet with the creamy sauce and toss to combine. If the sauce becomes too thick, add a couple of tablespoons of the reserved pasta water and toss to combine with the sauce.",
+ "name": "Add the drained pasta to the skillet with the creamy sauce and toss to combine. If the sauce becomes too thick, add a couple of tablespoons of the reserved pasta water and toss to combine with the sauce.",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/#wprm-recipe-67806-step-0-7",
+ "image": []
+ },
+ {
+ "text": "Slice the cooked chicken breasts and serve it atop the creamy pasta. Garnish with chopped parsley, if desired.",
+ "name": "Slice the cooked chicken breasts and serve it atop the creamy pasta. Garnish with chopped parsley, if desired.",
+ "url": "https://www.budgetbytes.com/chicken-alfredo/#wprm-recipe-67806-step-0-8",
+ "image": []
+ }
+ ],
+ "servings": 4,
+ "calories": 756,
+ "publisher": "Beth - Budget Bytes",
+ "rating": {
+ "ratingValue": 4.4,
+ "bestRating": 5,
+ "reviewCount": 20,
+ "is_tripadvisor": false
+ },
+ "recipeCategory": "Dinner",
+ "recipeCuisine": "American",
+ "video": {
+ "duration": "00:52",
+ "thumbnail": {
+ "src": "https://imgs.search.brave.com/P1KRHUV8JVXCRAc1KSF529sEXyvqQPJy4L7pk9aZ1Lc/rs:fit:200:200:1:0/g:ce/aHR0cHM6Ly9tZWRp/YXZpbmUtcmVzLmNs/b3VkaW5hcnkuY29t/L2ltYWdlL3VwbG9h/ZC9zLS1VMFMzdHRT/Zi0tL2NfbGltaXQs/Zl9hdXRvLGZsX2xv/c3N5LGhfMTA4MCxx/X2F1dG8sd18xOTIw/L3YxNjY1MTUyMTYz/L2MxYWlncGdndnZv/dHlkcXhhY2duLmpw/Zw",
+ "original": "https://mediavine-res.cloudinary.com/image/upload/s--U0S3ttSf--/c_limit,f_auto,fl_lossy,h_1080,q_auto,w_1920/v1665152163/c1aigpggvvotydqxacgn.jpg"
+ }
+ }
+ }
+ }
+ ],
+ "family_friendly": true
+ }
+ }
\ No newline at end of file
diff --git a/types.go b/types.go
index a0ebb8e..fef59d1 100644
--- a/types.go
+++ b/types.go
@@ -153,32 +153,33 @@ type Thumbnail struct {
type SearchResult struct {
Result
- Type string `json:"type"`
- Subtype string `json:"subtype"`
- DeepResults *DeepResult `json:"deep_results"`
- Schemas any `json:"schemas"`
- MetaURL MetaURL `json:"meta_url"`
- Thumbnail *Thumbnail `json:"thumbnail"`
- Age *Timestamp `json:"age"`
- Language string `json:"language"`
- Restaurant *LocationResult `json:"restaurant"`
- Locations *Locations `json:"locations"`
- Video *VideoData `json:"video"`
- Movie *MovieData `json:"movie"`
- FAQ *FAQ `json:"faq"`
- QA *QAPage `json:"qa"`
- Book *Book `json:"book"`
- Rating *Rating `json:"rating"`
- Article *Article `json:"article"`
- // Product any `json:"product"`
- ProductCluster []Product `json:"product_cluster"`
- ClusterType string `json:"cluster_type"`
+ Type string `json:"type"`
+ DeepResults *DeepResult `json:"deep_results"`
+ Schemas any `json:"schemas"`
+ MetaURL MetaURL `json:"meta_url"`
+ Thumbnail *Thumbnail `json:"thumbnail"`
+ Age *Timestamp `json:"age"`
+ Language string `json:"language"`
+ ContentType string `json:"content_type"`
+
+ Subtype string `json:"subtype"`
+ Article *Article `json:"article"`
+ Book *Book `json:"book"`
Cluster []Result `json:"cluster"`
+ ClusterType string `json:"cluster_type"`
CreativeWork *CreativeWork `json:"creative_work"`
+ FAQ *FAQ `json:"faq"`
+ Locations *Locations `json:"locations"`
+ Movie *MovieData `json:"movie"`
MusicRecording *MusicRecording `json:"music_recording"`
+ ProductCluster []Product `json:"product_cluster"`
+ QA *QAPage `json:"qa"`
+ Rating *Rating `json:"rating"`
+ Recipe *Recipe `json:"recipe"`
+ Restaurant *LocationResult `json:"restaurant"`
Review *Review `json:"review"`
Software *Software `json:"software"`
- ContentType string `json:"content_type"`
+ Video *VideoData `json:"video"`
}
type ImageResult struct {
@@ -309,6 +310,33 @@ type Rating struct {
IsTripadvisor bool `json:"is_tripadvisor"`
}
+type Recipe struct {
+ Title string `json:"title"`
+ Description string `json:"description"`
+ Thumbnail *Thumbnail `json:"thumbnail"`
+ URL string `json:"url"`
+ Domain string `json:"domain"`
+ Favicon string `json:"favicon"`
+ Time *Duration `json:"time"`
+ PrepTime *Duration `json:"prep_time"`
+ CookTime *Duration `json:"cook_time"`
+ Ingredients string `json:"ingredients"`
+ Instructions []HowTo `json:"instructions"`
+ Servings int `json:"servings"`
+ Calories int `json:"calories"`
+ Rating *Rating `json:"rating"`
+ RecipeCategory string `json:"recipeCategory"`
+ RecipeCuisine string `json:"recipeCuisine"`
+ Video *VideoData `json:"video"`
+}
+
+type HowTo struct {
+ Text string `json:"text"`
+ Name string `json:"name"`
+ URL string `json:"url"`
+ Image []string `json:"image"`
+}
+
type DataProvider struct {
Type string `json:"type"`
Name string `json:"name"`