Solidity NFT metadata loading issue

I’m in the process of developing an NFT collection and currently testing it on the Ropsten network. My NFT metadata is hosted on my site, for instance, boredApes.com/tokens/3.json. The problem I’m encountering is that the contract fetches boredApes.com/tokens/3 without the .json suffix. How do I modify my contract to ensure it retrieves the full metadata? Here’s the Solidity function I’m using:

function _baseURI() internal pure override returns (string memory) {
    return "https://boredApes.com/tokens/";
}

I appreciate any help with this!

Interesting - I’ve hit similar issues but not this exact one. Are you overriding tokenURI anywhere else in your contract? Usually tokenURI just combines baseURI with tokenId to make the full URL.

If you’re missing the .json extension, you probably need to override tokenURI to add it:

function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
    require(_exists(tokenId), "token does not exist");
    string memory baseURI = _baseURI();
    return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString(), ".json")) : "";
}

What testing tool are you using? Have you tried manually visiting the generated URL to see if it’s actually missing .json or just displaying weird? Sometimes it’s a frontend issue, not the contract.

Also - are you using OpenZeppelin’s ERC721 as your base?

The default implementation of ERC721 concatenates baseURI with tokenId, which is why your metadata lacks the .json extension. To resolve this, you’ll need to override tokenURI to append the extension yourself. I experienced a similar issue when I initially deployed my NFT collection.

Here’s how to modify the tokenURI function:

function tokenURI(uint256 tokenId) public view override returns (string memory) {
    require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
    return string(abi.encodePacked(_baseURI(), tokenId.toString(), ".json"));
}

Also, ensure you import @openzeppelin/contracts/utils/Strings.sol to use toString(). With this change, your contract should correctly fetch the metadata in JSON format.

yeah, this happens often. you need to override tokenURI and append .json at the end. just calling _baseURI() won’t cut it since ERC721 defaults to baseuri + tokenId. and remember to import Strings.sol for toString(), or itll break.