0

I am using spoonacular API for a recipe app project. The problem occurs when trying to making multiple GET requests to the API. The first request is a simple search with a query parameter. The resulting JSON of the first request contains a Recipe ID and I use that ID to make the second GET request , where the problem occurs. The API responds only when I make the request the first time but after that it responds with error code 500 [Internal Server Error].

I have tested the GET request on Postman but there it works fine every time. I'm new to working with API's and any help would be immensely appreciated.

This is my Retrofit Service Class

public class ServiceGenerator {

public static final String API_BASE_URL = "https://spoonacular-recipe-food-nutrition-v1.p.rapidapi.com/";

private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

private static Retrofit.Builder builder =
        new Retrofit.Builder()
                .baseUrl(API_BASE_URL)
                .addConverterFactory(GsonConverterFactory.create());

private static Retrofit retrofit = builder.build();

public static <S> S createService(Class<S> serviceClass, final String HostName, final String KeyVal)
{
    if (!TextUtils.isEmpty(HostName) && !TextUtils.isEmpty(KeyVal))
    {
        HeadersInterceptor interceptor = new HeadersInterceptor(HostName,KeyVal);

        if (!httpClient.interceptors().contains(interceptor))
        {
            httpClient.addInterceptor(interceptor);
            builder.client(httpClient.build());
            retrofit = builder.build();
        }
    }

    return retrofit.create(serviceClass);
}

This is the Interceptor I am using to add Headers with the request.

public class HeadersInterceptor implements Interceptor {

private String HostName,KeyVal;

HeadersInterceptor(final String HostName,final String KeyVal) {
    this.HostName = HostName;
    this.KeyVal = KeyVal;
}

@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
    Request original = chain.request();

    Request.Builder builder = original.newBuilder()
            .addHeader("X-RapidAPI-Host",HostName)
            .addHeader("X-RapidAPI-Key",KeyVal);

    Request request = builder.build();
    return chain.proceed(request);
}

}

This is my Fragment which makes a search query and SUCCESSFULLY return results[Receipe ID's]

public class ListSelectedFragments extends Fragment {

private ProgressBar PreviewFragPrg;
private final String TAG = "ListSelectedFragment->";

private PreviewRecipeAdapter adapter;
private RecyclerView SelectedItemRV;
private ArrayList<RecipePreviewHolder> RecipePreviewsList = new ArrayList<>();

public ListSelectedFragments() {
    // Required empty public constructor
}


@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    final View view = inflater.inflate(R.layout.fragment_list_selected_fragments, container, false);
    SelectedItemRV = view.findViewById(R.id.SelectedItemRV);
    TextView DisplayNameTV = view.findViewById(R.id.DisplayNameTV);
    PreviewFragPrg = view.findViewById(R.id.PreviewFragPrg);
    ImageView BackBtn = view.findViewById(R.id.BackBtn);

    BackBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (getFragmentManager() != null) {
                getFragmentManager().popBackStackImmediate();
            }
        }
    });

    if (getArguments() != null) {
        final String QueryTag = getArguments().getString("QueryTag");
        final String CuisineName = getArguments().getString("CuisineName");

        if(CuisineName!=null){
            DisplayNameTV.setText(CuisineName);
        }
        if(QueryTag!=null){
            ProcessQuery(QueryTag);
        }
    }

    return view;
}

private void ProcessQuery(final String QueryStr){

    String hostname = getResources().getString(R.string.spoonacular_host_name);
    String key      = getResources().getString(R.string.spoonacular_apikey_val);


    final ServiceGenerator.GetDataService mService =
            ServiceGenerator.createService(ServiceGenerator.GetDataService.class, hostname,key);

    Call<RecipeInfoModel> call = mService.getRecipes(QueryStr);

    call.enqueue(new Callback<RecipeInfoModel>() {
        @Override
        public void onResponse(@NonNull Call<RecipeInfoModel> call,
                               @NonNull Response<RecipeInfoModel> response)
        {
            Log.d(TAG, "Request Response Received");
            Log.d(TAG, response.toString());

            if (response.body() != null) {
                Results[] mRES = response.body().getResults();
                SetUpRecipePreviews(mRES);
                PreviewFragPrg.setVisibility(View.GONE);
            }
        }

        @Override
        public void onFailure(@NonNull Call<RecipeInfoModel> call, @NonNull Throwable t) {
            Log.d(TAG, "Request Failed");
            Log.d(TAG, call.toString());
            Log.d(TAG, "Throwable ->" + t);
            PreviewFragPrg.setVisibility(View.GONE);
            Toast.makeText(getActivity(),"Could not get required recipes",Toast.LENGTH_SHORT).show();
        }
    });

    Log.d(TAG, "User Inputed Request\n"+call.request().url().toString());

}

private void SetUpRecipePreviews(final Results[] mRES) {

    RecipePreviewsList.clear();
    adapter = new PreviewRecipeAdapter(getActivity(),RecipePreviewsList);
    SelectedItemRV.setLayoutManager(new GridLayoutManager(getActivity(), 2));
    SelectedItemRV.setAdapter(adapter);

    for (Results mRE : mRES) {
        String ImgUrls = mRE.getImage();
        RecipePreviewHolder obj = new RecipePreviewHolder(Integer.valueOf(mRE.getId()),
                mRE.getTitle(), ImgUrls);
        Log.d("GlideLogs->","Rid->"+mRE.getId());
        Log.d("GlideLogs->","Img URL->"+ ImgUrls);
        Log.d("GlideLogs->","Name->"+mRE.getTitle());

        RecipePreviewsList.add(obj);
    }

    if(RecipePreviewsList.size()>1){
        adapter.notifyDataSetChanged();
    }
}

This is the Activity I transition to from my Fragment after clicking on a Recipe Card... Sending the Recipe ID in the extras. This function is called immediately after receiving intent extras.

private void RetrieveRecipeInfo(final int recipeID) {

    String hostname = getResources().getString(R.string.spoonacular_host_name);
    String key   = getResources().getString(R.string.spoonacular_apikey_val);


    final ServiceGenerator.GetDataService mService =
            ServiceGenerator.createService(ServiceGenerator.GetDataService.class, hostname,key);

    Call<RecipeDetailedInfo> call = mService.getInformation(185071);
    Log.d(TAG , "Your GET Request:\n"+call.request().url().toString());

    call.enqueue(new Callback<RecipeDetailedInfo>() {
        @Override
        public void onResponse(@NonNull Call<RecipeDetailedInfo> call, @NonNull Response<RecipeDetailedInfo> response)
        {
            Log.d(TAG,"OnResponse()  Called\n");
            Log.d(TAG,"Response = "+ response);

            if(response.body()!=null) {
                String obj = response.body().getSourceUrl();
                Log.d(TAG,"Getting Recipe Info\n");
                Log.d(TAG, String.valueOf(obj));
            }
        }

        @Override
        public void onFailure(@NonNull Call<RecipeDetailedInfo> call, @NonNull Throwable t){
        }
    });
}

Using postman I get the results every time but in my application the API stops responding after the first request. Is there a problem with the way I'm including headers?

Gustavo Pagani
  • 6,583
  • 5
  • 40
  • 71
Ali Lal Din
  • 53
  • 1
  • 9
  • The first request works, but the 2nd request fails. Try making the 2nd request with a hard-coded ID to see if it works. – jj. Jun 21 '19 at 17:51
  • No luck. Still getting the same error. This is the response Response{protocol=http/1.1, code=500, message=Internal Server Error, url=https://spoonacular-recipe-food-nutrition-v1.p.rapidapi.com/recipes/185071/information} – Ali Lal Din Jun 21 '19 at 18:23
  • Are you using a proxy to inspect the request coming out of your device? Are the headers present? Is the request body correct (if existing) etc. – Martin Marconcini Jun 21 '19 at 18:24
  • I think using a powerful Interceptor like `Stetho` for monitoring detail of request and respond make you free from this problem. It's a logical problem. not technical issue! – beigirad Jun 21 '19 at 18:32
  • @MartinMarconcini I'm using simple logs to see the request coming out from my device and double checking the response with postman. As for the headers I'm also pretty sure they are present because the API responds with [headers not included] if they are not sent with the request. – Ali Lal Din Jun 21 '19 at 19:04
  • Can't you use Charly proxy to intercept the network request and compare Postman with the Retrofit call; clearly *something* is different, but with the code you posted, we have no way to know what it is... maybe put a sample project that executes these calls or something? I mean, you need to help us help you here :)) – Martin Marconcini Jun 21 '19 at 19:07
  • @MartinMarconcini I have edited the attached code, maybe it will give you a better idea. I have added all the parts associated with the API. – Ali Lal Din Jun 21 '19 at 19:21
  • By reading your responses, I'm inclined to believe you are just checking logs. Are you walking through this in a debugger? If you skip the first (working) call and the 2nd call still fails, that tells me something small about that call is wrong. Does your annotations on your model class have an extra forward slash or something? – jj. Jun 21 '19 at 20:00
  • @jj I'm not seeing anything in the debugger. I think it might be that I'm using the free plan of the spoonacular API which limits my calls but that still doesn't explain that why I'm getting response every time I make the the same request in Postman. Also I should mention that the problem is the API call I make the second time, If I make the 2nd Api call [The one in RetrieRecipeInfo()] before the API call I'm making first (search query API call) then this call works. – Ali Lal Din Jun 21 '19 at 20:06

1 Answers1

1

So I finally got things working. The problem was with the HeadersInterceptor.java. I was using the Interceptor to add the Headers with the call but I found out a much easier way and it works like a charm.

Simply add @Header with the call to add headers without interceptor in Retrofit.

public interface GetDataService {
    @GET("recipes/complexSearch?")
    Call<RecipeInfoModel> getRecipes(
            @Header("X-RapidAPI-Host") String api,
            @Header("X-RapidAPI-Key") String apiKey,
            @Query("query") String query_str);
}
Ali Lal Din
  • 53
  • 1
  • 9