Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error 404 Fetching JSON data from Movie API #51

Closed
thefiend opened this issue Mar 11, 2018 · 17 comments
Closed

Error 404 Fetching JSON data from Movie API #51

thefiend opened this issue Mar 11, 2018 · 17 comments

Comments

@thefiend
Copy link

thefiend commented Mar 11, 2018

Hi, I am trying to fetch movie information from a Movie API. However, I get

libc++abi.dylib: terminating with uncaught exception of type restc_cpp::HttpNotFoundException: Request failed with HTTP error: 404 Not Found

trying to do so and wish to know how do I change the struct to fit the API.

E.g.
screen shot 2018-03-11 at 3 42 57 pm

#include <iostream>

#include <boost/lexical_cast.hpp>
#include <boost/fusion/adapted.hpp>

#include "restc-cpp/restc-cpp.h"
#include "restc-cpp/RequestBuilder.h"

using namespace std;
using namespace restc_cpp;

struct Movie {
    int page = 0;
    int total_results = 0;
    int total_pages = 0;
};

BOOST_FUSION_ADAPT_STRUCT(
        Movie,
        (int, page)
        (int, total_results)
        (int, total_pages)
)

int main() {
    auto rest_client = RestClient::Create();
    Movie found_movies = rest_client->ProcessWithPromiseT<Movie>([&](Context& ctx) {
                
                Movie movie;

                SerializeFromJson(movie,
                                  RequestBuilder(ctx)
                                          .Get("https://api.themoviedb.org/3/search/movie?api_key=30ac911b5a4841e65d905a53b31396ae&query=Jack+Reacher")
                                          .Header("X-Client", "RESTC_CPP")
                                          .Header("X-Client-Purpose", "Testing")
                                          .Execute());

                return movie;
            }).get();

    cout << "Number of Results " << found_movies.total_results << ", Page: " << found_movies.page << endl;
}
@jgaa
Copy link
Owner

jgaa commented Mar 11, 2018

I'll have a look at it

@jgaa
Copy link
Owner

jgaa commented Mar 11, 2018

The url you provide will be encoded, and that will prevent the server from decoding your authentication token.

Try

                            SerializeFromJson(movie,
                                  RequestBuilder(ctx)
                                          .Get("http://api.themoviedb.org/3/search/movie")
                                          .Argument("api_key", "30ac911b5a4841e65d905a53b31396ae")
                                          .Argument("query", "Jack+Reacher")
                                          .Header("X-Client", "RESTC_CPP")
                                          .Header("X-Client-Purpose", "Testing")
                                          .Execute());

The Argument() functions will make sure that the arguments are sent correctly.

You should 'git pull' restc-cpp, as I found and fixed a bug wen I checked this.
You may also want to get a new authentication token :)

@thefiend
Copy link
Author

thefiend commented Mar 11, 2018

I have pulled and installed the restc-cpp library and used the code above. However, I am getting an error from SerializeJson.

Assertion failed: (false), function DoRecurseToMember, file /usr/local/include/restc-cpp/SerializeJson.h, line 704.

Edit: It is due to me trying to add the struct of results and it seems to be the wrong way of adding it.

struct Movie {
    int page = 0;
    int total_results = 0;
    int total_pages = 0;
//    string results = {}; //this is causing the issue
};

BOOST_FUSION_ADAPT_STRUCT(
        Movie,
        (int, page)
        (int, total_results)
        (int, total_pages)
//        (string, results) //this is causing the issue
)

This is what I have for now:

struct Movie {
    int page = 0;
    int total_results = 0;
    int total_pages = 0;

    union results {
        struct {
            int vote_count;
            int id;
            bool video;
            string title;
            string popularity;
            string poster_path;
            string original_language;
            string original_title;
            string overview;
            string release_date;
        };
    };
};

but I am not sure how to edit

BOOST_FUSION_ADAPT_STRUCT(
        Movie,
        (int, page)
                (int, total_results)
                (int, total_pages)
//        (string, results)
)

@jgaa
Copy link
Owner

jgaa commented Mar 11, 2018

I would put the results in a structure and then and then add it as:

struct Movie {
    int page = 0;
    int total_results = 0;
    int total_pages = 0;
    std::vector<Results> results;
}

BOOST_FUSION_ADAPT_STRUCT(
        Movie,
        (int, page)
                (int, total_results)
                (int, total_pages)
        (std::vector<Results>, results)
)

Make sure that Movie has the same member, as you map directly from C++ data-type and name.

You can have a look at this header to see some more complex mappings.

@thefiend
Copy link
Author

thefiend commented Mar 11, 2018

I am getting Process finished with exit code 11 from this

struct Results {
    int vote_count= 0;
    int id= 0;
    bool video;
    double vote_average;
    string title;
    double popularity;
    string poster_path;
    string original_language;
    string original_title;
    bool adult;
    string overview;
    string release_date;
};

struct Movie {
    int page = 0;
    int total_results = 0;
    int total_pages = 0;
    std::vector<Results> results;
};

BOOST_FUSION_ADAPT_STRUCT(
        Movie,
        (int, page)
                (int, total_results)
                (int, total_pages)
                (std::vector<Results>, results)
)

@jgaa
Copy link
Owner

jgaa commented Mar 11, 2018

I'll take a look

@jgaa
Copy link
Owner

jgaa commented Mar 11, 2018

Since you are serializing Results, you need to declare that as well :)

BOOST_FUSION_ADAPT_STRUCT(
    Results,
    (int, vote_count)
    (int, id)
    (bool, video)
    (double, vote_average)
    (string, title)
    (double, popularity)
    (string, poster_path)
    (string, original_language)
    (string, original_title)
    (bool, adult)
    (string, overview)
    (string, release_date)
)

I have committed an assert for that case, and a fix where restc-cpp needs to ignore an array (genre_ids). So you should 'git poll' before testing again.

@thefiend
Copy link
Author

Awesome! Got it to work. Thank you very much. Really appreciate it. :D

@thefiend thefiend reopened this Mar 11, 2018
@thefiend
Copy link
Author

I tried querying other movies such as Titanic and Black Panther and got this exception.
Assertion failed: (current_name_.empty()), function DoKey, file /usr/local/include/restc-cpp/SerializeJson.h, line 1024.

@jgaa
Copy link
Owner

jgaa commented Mar 11, 2018

That's interesting.
Can you share with me the request URL's or the json payloads from this requests? (curl can give you the payload from the command-line).

@thefiend
Copy link
Author

thefiend commented Mar 11, 2018

It is the same as above just that I changed .Argument("query", "Jack+Reacher") to .Argument("query", "titanic")

Edit: I realised it is because genre_ids and backdrop_path are not set in struct.

struct Results {
    int vote_count= 0;
    int id= 0;
    bool video;
    double vote_average;
    string title;
    double popularity;
    string poster_path;
    string original_language;
    string original_title;
    std::vector<int> genre_ids;
    string backdrop_path;
    bool adult;
    string overview;
    string release_date;
};

struct Movie {
    int page = 0;
    int total_results = 0;
    int total_pages = 0;
    std::vector<Results> results;
};

BOOST_FUSION_ADAPT_STRUCT(
        Results,
        (int, vote_count)
                (int, id)
                (bool, video)
                (double, vote_average)
                (string, title)
                (double, popularity)
                (string, poster_path)
                (string, original_language)
                (string, original_title)
                (std::vector<int>, genre_ids)
                (string, backdrop_path)
                (bool, adult)
                (string, overview)
                (string, release_date)
)

BOOST_FUSION_ADAPT_STRUCT(
        Movie,
        (int, page)
                (int, total_results)
                (int, total_pages)
                (std::vector<Results>, results)
)

I added genre_ids and backdrop_path in struct and it works for query of Jack+Reacher but not spiderman or titanic. It causes the error:

Assertion failed: (current_name_.empty()), function DoKey, file /usr/local/include/restc-cpp/SerializeJson.h, line 1024.

@jgaa
Copy link
Owner

jgaa commented Mar 11, 2018

I'll take a look at it tomorrow. It might be a bug.

@thefiend
Copy link
Author

thefiend commented Mar 12, 2018

Did I declare the array genre_ids wrongly?
Update: It seems to work for batman but does not work for query of spiderman
Assertion failed: (current_name_.empty()), function DoKey, file /usr/local/include/restc-cpp/SerializeJson.h, line 1024.

@jgaa
Copy link
Owner

jgaa commented Mar 12, 2018

I can reproduce it. Trying to figure out what's triggering the error.

@jgaa
Copy link
Owner

jgaa commented Mar 12, 2018

You found another bug! I have committed a fix.

This list could actually be implemented as an iterator, where you loop over the content. That would allow huge result-sets. I have implemented that for one project, and been thinking about doing it in a more general fashion. If I get time in the near future, I'll see if I can use this movie API as one of the examples for such a general feature.

Thank you for digging out these bugs btw. If this was a commercial project there would have been a QA person spending considerable time figuring out how to crash the library - but with free, open source, I have to relay on my own imagination and real life cases reported by users.

@thefiend
Copy link
Author

thefiend commented Mar 12, 2018

Great! Really thankful that you made it work. I will be trying to get it to work with Twitter API next, to pull tweets from Twitter. Any idea how to authorize request on twitter API with this library?

It should work if I Add_Headers() the following for authentication?
OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1318622958", oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", oauth_version="1.0"

@jgaa
Copy link
Owner

jgaa commented Mar 13, 2018

I don't really understand why these services keeps using OAuth. It's been broken (insecure) for a long time.

Anyway, using it requires cryptographic signing of headers and content in a very specific way. I think it should be done by restc-cpp as the process is complex and will take time to comprehend an implement. It's documented here: https://developer.twitter.com/en/docs/basics/authentication/guides/authorizing-a-request

The general OAuth 1.0 protocol is documented here: https://oauth.net/core/1.0/#anchor9

I don't have time to implement this right away, but I'll put it on my list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants