Complete Movie App — Data Source (2)

Prateek Sharma
Flutter Community
Published in
6 min readSep 14, 2020

You can also read this article here — https://www.techieblossom.dev/flutter/movieapp/datasources/

Hi, Glad that you’re here,

We are building a Movie App with the best coding practices and tools out there. In the previous article, I have explained how our folder structure is going to be and we will use Clean architecture concepts.

This is companion article for the Video:

Create TMDb API Key

Since we are using TMDb API to fetch the movies, let’s first create TMDb API Key. Open TMDb Login and register or login on the website.

Once logged in, you can go to settings by visiting TMDb Account. From the left side menu, open the API section and copy the value under the API Key (v3 auth). Also, read the URL of Example API Request because you’ll need the base URL while making the API calls.

Open the project and create a file api_constants.dart in the data/core folder and place the below code:

  1. Since this class should not be instantiated from outside, you should declare its constructor as private.
  2. This URL will always be prepended before specific URLs.
  3. You’ll also put the API key in this file. I recommend, that you create your own because I may turn it down after this series.
  4. The image paths that you get from TMDb API are in this format zuW6fOiusv4X9nnW3paHGfXcSll.jpg. To load images you’ve to prepend the BASE_IMAGE_URL.

TMDb API Response

Head on to https://developers.themoviedb.org/3/ and select TRENDING from the left menu. On the right side, you can see the details. You can explore more on this, but 2 very important things are media_type and time_window. As this is a movie app, the media type will be a movie and you can select a time window as day. Open the Try It Out tab and select movie as media_type, day as time_window, and put the API key in the API field. Now, you can press the SEND REQUEST button and you’ll see the request and response. You can read the whole URL and verify the BASE_URL.

Let’s copy this response and create a dart model from it. Open https://javiercbk.github.io/json_to_dart/ and paste the response in the text box. Name the class as MoviesResultModel.

Create a dart file movies_result_model.dart in the data/models folder and paste the code generated from jsonToDart.

Have a look at the fields that are created. The class generated has a list of movies. As I will not be showing you pagination, so you can delete fields related to pagination like the page, totalPages, and totalResults. To further simplify code, you can take the Results class out of this file and create a separate file named movie_model.dart in data/models. Here are the two classes that you’ll have:

Dependencies

Add 2 dependencies — http and equatable

In dart, comparison of objects is easier when you use an equatable plugin. The http plugin is used to make network calls.

Now, think of the fields you’ll need in the application because no way you’re using all of the fields together at a time on screen. The fields that will be required will be mostly id, posterPath, backdropPath, title, voteAverage, releaseDate, overview. Some fields are still extra but you’ll have to use them later in the series when we do favourite movies.

Now, In the domain/entities folder create MovieEntity class and declare the above fields as final. Extend this class with Equatable. Override props method with id and title fields. Also override the stringify method, so that you can see the id and title when you print the object.

Your MovieEntity class should look like this:

To properly tie MovieModel and MovieEntity and execute Clean architecture, extend MovieModel with MovieEntity. This will help in separating the Domain and Data Layer.

Now that MovieModel is extending MovieEntity, some changes have to be done to MovieModel.

  • Make all the fields as final.
  • Update fromJson method to the factory method and instead of assigning values directly return the MovieModel object with new values.
  • Use the super constructor to assign the values in MovieEntity. This way whenever you convert MovieModel to MovieEntity instance you can get the required fields with correct non-null values.

Here is how the updated MovieModel will look.

When you’re declaring any field as double in models, be completely sure that it’ll always be returned as double. If it is returned as an int, the convert library fails to parse it. Either you can declare this as num or use toDouble function with safe operators.

This will parse int to double if int is returned from API. As well as, if it is returned as null, 0.0 will be the default value of popularity.

Additionally, you can assign more default values to all the model fields.

Create DataSource

Let’s focus on making network calls now to fill up the models and entities.

Create a file movie_remote_data_source.dart in data/data_sources folder.

Create an abstract class MovieRemoteDataSource with one function as of now. This method will call TMDb API for trending movies by day.

In the same file add the implementation of the abstract class:

Declare a final field _client at the top and create a constructor of MovieRemoteDataSource with an instance of Client from the http package.

GetTrending Movies

Now, we will use _client to make get API call for trending movies.

  1. Create the get URL Path — https://api.themoviedb.org/3/trending/movie/day?api_key=f33521953035af3fc3162fe1ac22e60c.
  2. Keep headers as JSON because TMDb API will result in JSON format.
  3. Check whether service has given a success response.
  4. Parse the JSON response and get the body. The body will have the exact json that we copied and pasted in json2Dart tool to create models.
  5. You’ll now use fromJson factory method to parse the JSON response to the model. Notice, we only require a list of movies, hence after parsing you'll only get movies from the MovieResultModel
  6. Finally, return the movies.
  7. In case the service has responded with error results, you’ll throw an exception from the data layer itself.

Call the GetTrending()

Till the time I don’t create UI, I can show you that our network calls are working fine and giving us desired results by directly calling from main.dart.

Open main.dart and before calling runApp(MyApp()) you can call getTrending() function by below snippet:

  1. Instantiate DataSource and pass the Client from the http package.
  2. Call the function. Once you run the app, in the console you can see the movies list with each movie’s id and title, because in props we passed id and title.

GetPopular Movies

Let’s add one more API call quickly. Create another function getPopular() which will call different API to fetch popular movies. Add getPopular() in the abstract class as below:

Implement getPopular() method as below. Fortunately, there is only the URL path change, which is now movie/popular.

You can run this method as well, in the same manner as you called getTrending() from main.dart.

Core API Client

Even though till now we have added 2 methods only, but already you might have seen repeated code. So, let’s move out common code to a separate file.

Create api_client.dart in data/core.

In ApiClient class add Client as its only final field and also create the constructor with it.

Create a method with dynamic as return type, because this can return any type of model.

We’ve moved most of the code to this method and now we can update the data source implementation with very simple code. You’ll now use ApiClient instead of Client.

  1. Instead of Client, use ApiClient now.
  2. Call the get method from ApiClient with the path required to fetch trending movies.
  3. Call the get method from ApiClient with the path required to fetch popular movies.

This was all about making network calls. See you in the next part of this series.

If you loved reading the article, don’t forget to clap 👏. You can reach out to me and follow me on Medium, Twitter, GitHub, YouTube.

--

--