skip to Main Content

Am working on a newsapp using the newsapi.org to fetch data from the list of articles but it returns an exception of null is not a sub type of String in the Article.fromJson and i would like to ask for some help.Thank you

//this is my Article class


import 'package:news_app/source_models.dart';
class Article{
  Source source;
  String? author;
  String? title;
  String? description;
  String? url;
  String? content;

  Article({required this.source,required this.author,required this.title,required this.description,required this.url,
    required this.content});

  factory Article.fromJson(Map<String,dynamic>json){
    return Article(
      source: Source.fromJson(json['source']),
      author: json['author']as String,
      title: json['title'] !=null?json['title'].toString():'',
      description: json['description']as String,
      url: json['url']as String,
      content: json['content']as String,
    );
  }
  Map<String,dynamic>ToJson(Article article)=><String,dynamic>
  {
    "source":article.source,
    "author":article.author,
    "title":article.title,
    "description":article.description,
    "url":article.url,
    "content":article.content,


  };
}


//this is the api


import 'package:news_app/Article.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
class ApiService{
  static Future<List<Article>>article()async{
    List<Article>?articles;
    final http.Response response=await http.get(Uri.parse('https://newsapi.org/v2/everything?domains=wsj.com&apiKey=eac151759e98448f8712913e2028cfd0'));
if(response.statusCode==200){
  Map<String,dynamic>json=jsonDecode(response.body);
  List<dynamic>body=json['articles'];
  articles=body.map((item) => Article.fromJson(item)).toList();
}

 return articles!;
  }
}



//this is the source class

class Source{

  String name;

  Source({required this.name});

  factory Source.fromJson(Map<String,dynamic>json){
    return Source(

        name:json['name']);
  }
  Map<String,dynamic>ToJson(Source sources){
    return <String,dynamic>{

      "name":sources.name,
    };
  }
}

//this is my UI

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:news_app/ApiService.dart';
import 'package:news_app/Article.dart';

class HomeScreen extends StatefulWidget{
  createState()=>_HomeScreen();
}

class _HomeScreen extends State<HomeScreen>{
 bool isWaiting=false;
  List<Article>articles=[];
  void initState(){
    super.initState();
    IncomingApi();
  }

  void IncomingApi()async{
    isWaiting=true;
    var data=await ApiService.article();
    setState(() {
      articles=data;
      isWaiting=false;
    });
}
  Widget build(BuildContext context){
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body:ListView.builder(
          itemCount: articles.length,
          itemBuilder:(context, index) {
            NewsContainer(context, articles[index]);
            return Center(
                child:CircularProgressIndicator()
                    );
          }) );

  }
  Widget NewsContainer(BuildContext context,Article article){
    return Container(
      child:ListTile(
        title:Text(article.description!) ,
      )
    );
  }

}

//I made checks on all the fields but didnt work,i also tried using the futureBuilder and nothing comes out of it and i certainly dont clearly understand why the Source.fromJson didnt produce any exception if truely nothing is being passed on to the Article.fromJson.And please all answers will be appreciated.

2

Answers


  1. As some of the inputs are null, you should cast String with nullable operator ?.

    class Article{
      Source source;
      String? author;
      String? title;
      String? description;
      String? url;
      String? content;
    
      Article({required this.source,required this.author,required this.title,required this.description,required this.url,
        required this.content});
    
      factory Article.fromJson(Map<String,dynamic>json){
        return Article(
          source: Source.fromJson(json['source']),
          author: json['author']as String?,
          title: json['title'] !=null?json['title'].toString():'',
          description: json['description']as String?,
          url: json['url']as String?,
          content: json['content']as String?,
        );
      }
      Map<String,dynamic>ToJson()=><String,dynamic>
      {
        "source": source,
        "author": author,
        "title": title,
        "description": description,
        "url": url,
        "content": content,
      };
    }
    
    Login or Signup to reply.
  2. in your code author string key value is null so app is crashing so here you need to add null-safety. so you need to user ?? operator instead of !.

    also you can generate model from API response checkout this link

    Also fixed few warnings in your code.

    Prefere bellow code.

    Replace your Model classes

    class ArticleResponse {
      String? status;
      int? totalResults;
      List<Articles>? articles;
    
      ArticleResponse({this.status, this.totalResults, this.articles});
    
      ArticleResponse.fromJson(Map<String, dynamic> json) {
        status = json['status'];
        totalResults = json['totalResults'];
        if (json['articles'] != null) {
          articles = <Articles>[];
          json['articles'].forEach((v) {
            articles!.add(Articles.fromJson(v));
          });
        }
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = <String, dynamic>{};
        data['status'] = status;
        data['totalResults'] = totalResults;
        if (articles != null) {
          data['articles'] = articles!.map((v) => v.toJson()).toList();
        }
        return data;
      }
    }
    
    class Articles {
      Source? source;
      String? author;
      String? title;
      String? description;
      String? url;
      String? urlToImage;
      String? publishedAt;
      String? content;
    
      Articles(
          {this.source,
          this.author,
          this.title,
          this.description,
          this.url,
          this.urlToImage,
          this.publishedAt,
          this.content});
    
      Articles.fromJson(Map<String, dynamic> json) {
        source = json['source'] != null ? Source.fromJson(json['source']) : null;
        author = json['author'];
        title = json['title'];
        description = json['description'];
        url = json['url'];
        urlToImage = json['urlToImage'];
        publishedAt = json['publishedAt'];
        content = json['content'];
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = <String, dynamic>{};
        if (source != null) {
          data['source'] = source!.toJson();
        }
        data['author'] = author;
        data['title'] = title;
        data['description'] = description;
        data['url'] = url;
        data['urlToImage'] = urlToImage;
        data['publishedAt'] = publishedAt;
        data['content'] = content;
        return data;
      }
    }
    
    class Source {
      String? id;
      String? name;
    
      Source({this.id, this.name});
    
      Source.fromJson(Map<String, dynamic> json) {
        id = json['id'];
        name = json['name'];
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = <String, dynamic>{};
        data['id'] = id;
        data['name'] = name;
        return data;
      }
    }
    

    API Call service minor changes to map json in model.

    class ApiService {
      static Future<List<Articles>> article() async {
        List<Articles>? articles;
        final http.Response response = await http.get(Uri.parse(
            'https://newsapi.org/v2/everything?domains=wsj.com&apiKey=eac151759e98448f8712913e2028cfd0'));
        if (response.statusCode == 200) {
          
          Map<String, dynamic> json = jsonDecode(response.body); 
          final fetchData = ArticleResponse.fromJson(json); // just need to add json response to map model 
          articles = fetchData.articles ?? []; // get article array from response.
          
        }
    
        return articles!;
      }
    }
    

    Home screen widget

    class HomeScreen extends StatefulWidget {
      const HomeScreen({super.key});
    
      @override
      createState() => _HomeScreen();
    }
    
    class _HomeScreen extends State<HomeScreen> {
      bool isWaiting = false;
      List<Articles> articles = [];
      @override
      void initState() {
        super.initState();
        incomingApi();
      }
    
      Future<void> incomingApi() async {
        isWaiting = true;
        List<Articles> data = await ApiService.article();
        setState(() {
          articles = data;
          isWaiting = false;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Home'),
          ),
          body: isWaiting
              ? const Center(child: CircularProgressIndicator())
              : ListView.builder(
                  itemCount: articles.length,
                  itemBuilder: (context, index) {
                    return newsContainer(context, articles[index]);
                  }),
        );
      }
    
      Widget newsContainer(BuildContext context, Articles article) {
        return ListTile(
          title: Text(article.description ?? ''),
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search