I tried to use Moralis API to call NFT via wallet address, but got following error.
Unhandled Exception: type 'Null' is not a subtype of type 'String'
These are the code lines that were pointed out as having errors.
final meta = jsonDecode(map?['metadata']);
meta_name = meta['name'] ?? '';
meta_image = meta['image'] ?? '';
meta_description = meta['description'] ?? '';
if (response.statusCode == 200) {
nfts = jsonDecode(response.body)['result'].map<Nfts>((result) {
return Nfts.fromMap(result);
}).toList();
}
The full code for the first one is below.
import 'dart:convert';
class Nfts {
late String total;
late String page;
late String page_size;
late String cursor;
late String result;
late String token_id;
late String token_address;
late String amount;
late String owner_of;
late String token_hash;
late String block_number_minted;
late String block_number;
late String contract_type;
late String name;
late String symbol;
late String token_uri;
late String metadata;
late String last_token_uri_sync;
late String last_metadata_sync;
late String minter_address;
late String meta_name;
late String meta_image;
late String meta_description;
Nfts({
required this.total,
required this.page,
required this.page_size,
required this.cursor,
required this.result,
required this.token_id,
required this.token_address,
required this.amount,
required this.owner_of,
required this.token_hash,
required this.block_number_minted,
required this.block_number,
required this.contract_type,
required this.name,
required this.symbol,
required this.token_uri,
required this.metadata,
required this.last_token_uri_sync,
required this.last_metadata_sync,
required this.minter_address,
required this.meta_name,
required this.meta_image,
required this.meta_description,
});
Nfts.fromMap(Map<String, dynamic>? map) {
total = map?['total'] ?? '';
page = map?['page'] ?? '';
page_size = map?['page_size'] ?? '';
cursor = map?['cursor'] ?? '';
result = map?['result'] ?? '';
token_id = map?['token_id'] ?? '';
token_address = map?['token_address'] ?? '';
amount = map?['amount'] ?? '';
owner_of = map?['owner_of'] ?? '';
token_hash = map?['token_hash'] ?? '';
block_number_minted = map?['block_number_minted'] ?? '';
block_number = map?['block_number'] ?? '';
contract_type = map?['contract_type'] ?? '';
name = map?['name'] ?? '';
symbol = map?['symbol'] ?? '';
token_uri = map?['token_uri'] ?? '';
metadata = map?['metadata'] ?? '';
last_token_uri_sync = map?['last_token_uri_sync'] ?? '';
last_metadata_sync = map?['last_metadata_sync'] ?? '';
minter_address = map?['minter_address'] ?? '';
final meta = jsonDecode(map?['metadata']);
meta_name = meta['name'] ?? '';
meta_image = meta['image'] ?? '';
meta_description = meta['description'] ?? '';
}
}
The full code for the second one is below.
class NftsProviders{
Uri uri = Uri.parse('https://deep-index.moralis.io/api/v2/(personal metamask wallet address)/nft?chain=polygon&format=decimal');
Future<List<Nfts>> getNfts() async {
List<Nfts> nfts = [];
final response = await http.get(uri, headers: {
'accept': 'application/json',
'X-API-Key' : 'o1g9ywaRjZvZaeaByxhZc7mFOBVVvDJEksU0jeZ8b34fNX03ISTc72fltfsAnuYG'
});
if (response.statusCode == 200) {
nfts = jsonDecode(response.body)['result'].map<Nfts>((result) {
return Nfts.fromMap(result);
}).toList();
}
else {
throw Exception('Failed to load NFT');
}
return nfts;
}
}
With this API, I tried to create a Gridview.builder.
class NftsScreen extends StatefulWidget {
@override
_NftsScreenState createState() {
return new _NftsScreenState();
}
}
class _NftsScreenState extends State<NftsScreen> {
List<Nfts> nfts = [];
bool isLoading = true;
NftsProviders nftsProvider = NftsProviders();
Future initNfts() async {
nfts = await nftsProvider.getNfts();
}
@override
void initState() {
super.initState();
initNfts().then((_) {
setState(() {
isLoading = false;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("nfts http"),
),
body: isLoading
? Center(
child: const CircularProgressIndicator(),
)
: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.5,
crossAxisSpacing: 20,
mainAxisSpacing: 20),
itemCount: nfts.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
// Text(nfts[index].name),
// Text(nfts[index].metadata),
CupertinoButton(
onPressed: () {},
// CircleAvatar with NetworkImage(nfts[index].meta_image)
// size of 100, 100
child: CircleAvatar(
radius: 100,
backgroundImage: NetworkImage(nfts[index].meta_image,),
)
)
],
),
);
}),
);
}
}
I want to request NFT information according to the user’s wallet address called from Firebase.
Thanks in advance.
- This is part of the api call response.
{
"total": null,
"page": 1,
"page_size": 100,
"cursor": null,
"result": [
{
"token_address": "0x53a0018f919bde9c254bda697966c5f448ffddcb",
"token_id": "46388765668907266497641806581710410401632846941109288029645926940148068689172",
"owner_of": "0xe3281571a136c11cc66d225902d494d29aaf7cb9",
"block_number": "30362645",
"block_number_minted": "30362645",
"token_hash": "8b025de30055bd161b2774da64fc283a",
"amount": "1",
"contract_type": "ERC721",
"name": "EDNS",
"symbol": "EDNS",
"token_uri": "https://api.edns.domains/metadata/0x53a0018f919bde9c254bda697966c5f448ffddcb/46388765668907266497641806581710410401632846941109288029645926940148068689172/metadata.json",
"metadata": "{"name":"goyangtwo.meta","description":"Domain goyangtwo.meta from EDNS Domains","image":"https://api.edns.domains/metadata/0x53a0018f919bde9C254bda697966C5f448ffDDcB/46388765668907266497641806581710410401632846941109288029645926940148068689172/image.svg","attributes":[{"trait_type":"TLD","value":"meta"}]}",
"last_token_uri_sync": "2022-12-06T14:08:39.924Z",
"last_metadata_sync": "2022-12-06T14:08:44.789Z",
"minter_address": "0x805ec22fca66eca02e244689b47fc2f180a94f01"
}
],
"status": "SYNCED"
}
2
Answers
can you share the response of the api call, most probably there will be a typo in the JSON decoding
try quicktype.io to generate response models
What’s the source of Nfts? Do you not have accidently defined a field like cursor or total as String instead of String? Otherwise, please provide the code for Nfts as it might have fields of type String without defaults that are not present in the json, causing the Nfts.fromMap(result); to fail.
As a general tip, it is wise to NOT assume that this will always succeed. In case it fails, then i.e. return null instead of crashing your app.
Edit added solution:
In the function
the variable map will be the full map (with total, page, result, etc. entries) which does not contain a metadata tag, so…
will be the same as
which is the reason for the error message. A string is expected!
However, you already jsonDecode (d) the response, so why do it again, because you already have a map of the response 🙂
You just need to pick the right tags from the map.