[SOLVED] Help with API request

I am developing a page to check the tokens a user has in a contract based on the token_id that he types. And by that I mean that the person writes himself the id of the token that he wants to see.

But I am having problems with the code since, when I try to send the token ID, I get the following error:

Also I am facing another problem, and in case someone could help me I will be very grateful. And the problem is that I am trying to avoid the user having to type his wallet, so this page opens from another one where I am passing his wallet address through http request (/page?owner_of=“xxxx”), however I am always getting the error that the address was not defined.

This is the code I am using on the page:

import Moralis from "moralis";
import { useState } from "react";
import { Flex, Button, Text, Input, Select } from "@chakra-ui/react";

function App(context) {
    const [tokenid, settokenid] = useState("");

    async function CheckUser(context) {
        const { query } = context;
        console.log(tokenid);

        await Moralis.start({ apiKey: '1234567890' });

        const response = await Moralis.EvmApi.nft.getNFTTokenIdOwners({
            owner_of: query.owner_of,
            tokenAddress: '1234567890',
            chain: 5,
            token_id: tokenid,
        });

        console.log(response.result);
    }

    function tokenidChange(e) {
        settokenid(e.target.value);
    }

    return (
        <>
            <Flex
            direction="column" 
            alignItems="center" 
            justifyContent="center" 
            maxwidth="100vw" height="100vh" 
            >
                <Text direction="column" alignItems="center" justifyContent="center" fontSize="6xl" fontWeight="bold">
                See Your NFT
                </Text>
                
                <Input
                placeholder='Token ID'
                value={tokenid}
                onChange={(e) => tokenidChange(e)}
                width='auto'
                mt={5}
                >
                </Input>

                <Button direction="column" mt="5" alignItems="center" justifyContent="center"  onClick={CheckUser}>
                Click Here
                </Button>
            </Flex>
        </>
    );
}

export default App;

You could add some logging to see what is the value for that token id

I try to make some changes and it is now sending me back a response but it is not for an specific owner:

As a response I got all of the owners of that token:

Is there a way I can use the owner as a parameter for this request?

What changes did you make?

context is not available in this way. One way is to use getServerSideProps.

export async function getServerSideProps(context) {
  const { owner_of } = context.query;

  return {
    props: { owner_of },
  };
}

function App(props) {
  console.log("props", props);

  ...
}

Also you should rename CheckUser to checkUser as it is not a component.

I didn’t make any changes that solved my problem, I just found out what was causing the error. I noticed that it occurs when I try to put as query/path parameter the owner’s address that I am sending by http request and I don’t know if there is a way to use it as a parameter.
That’s what I am trying to figure it out now. Trying to resume, what I want to use as parameters: the owner address, the token id and the contract address.

Thank you so much for this!

Thanks just did it :grin:

Actually another problem has appeared, when I try to enter an input a token_id other than 0 I get the following error:

The code is like this:

function App(props) {
    const [tokenid, settokenid] = useState("");
    console.log("props", props);

    //Pega todos os donos do token ID 0
    async function checkUser() {
        console.log(tokenid);

        await Moralis.start({ apiKey: "xxxxxxxx" });

        const response = await Moralis.EvmApi.nft.getNFTTokenIdOwners({
            address: '1234567890',
            chain: 5,
            tokenId: tokenid,
        });
        console.log(response.raw.result)

        const owner_of = response.raw.result[tokenid].owner_of
        const token_id = response.raw.result[tokenid].token_id
        const amount = response.raw.result[tokenid].amount

        console.log(owner_of, token_id, amount)
...

This won’t work (unless tokenid is 0 for one or more results), you’re trying to reference the index of each object in the response.raw.result array.

You are logging this:

console.log(response.raw.result)

From this, check what you can use. E.g. if you get at least one valid result, you can use:

response.raw.result[0].owner_of

For the first object.

That is why passing the parameter owner_of at the begging would solve this problem, because I would have only one response from the API. But that is not possible, right? Is there a way to pass as a parameter for the API the owner address together with token id and contract address?

Is there a way using this sentence that I can reach a specific user?

Because the response from the API is like this, so it would always bring me the information from the first user and not the real one who sent the request (that could be the number 1 on the list below):

Is there a way to pass as a parameter for the API the owner address together with token id and contract address?

Not with getNFTTokenIdOwners. There may be a better way but you could search all the results for the specific owner_of you’re looking for. Something like:

const userResult = response.raw.result.find(
      (owner) => owner.owner_of == 'addressyouwanttolookfor'
);

Thanks for the code, using console.log I could see that indeed return the requested user information.

But I don’t know if it was this part of the code itself, but I am trying to send these requests to a database and I am constantly getting this error:

But I know that there is nothing wrong with my Schema, because I get data from user on other pages of my website and I send successfully the data to my database, just to try to make myself more clear here is how the code looks right now:

...
async function checkUser() {
        console.log(tokenid);

        await Moralis.start({ apiKey: "xxxxxx });

        const response = await Moralis.EvmApi.nft.getNFTTokenIdOwners({
            address: '1234567890',
            chain: 5,
            tokenId: tokenid,
        });

        if (typeof response.raw.result.find( (owner) => owner.owner_of == props.owneradd ) === 'undefined') {
            console.log("not okay")
            return false
        }
        else {
            const userResult = response.raw.result.find( (owner) => owner.owner_of == props.owneradd );
            console.log(userResult)

            const owner_of = userResult.owner_of
            const token_id = userResult.token_id
            const amount = userResult.amount
            console.log(owner_of, token_id, amount);
            console.log("ok");

            const { Users } = require('../lib/userSchema')
            
            const MongoUser = await Users.findOne({token_id: token_id});

            if (!MongoUser) {
                const newUser = new Users({
                    owner_of: owner_of,
                    token_id: token_id,
                    amount: amount,
                })
                await newUser.save();

                console.log("user is being created")
            }

            return user
        };
    };
...

Can you post that userSchema.js code as well. That get error is only coming from that new mongoose.Schema line?

Sure here is the code:

import mongoose from "mongoose";

const userSchema = new mongoose.Schema(
  {
    owner_of: {
      type: String,
    },
    token_id: {
      type: String,
    },
    amount: {
      type: String,
    },
  },
  { timestamps: true },
);

let Users = mongoose.models.users || mongoose.model("users", userSchema);

export default Users;

Note: I edit the code on the previous post, because I moved the function “await connectDB ()” from inside the function to outside, putting it on the “getServerSideProps” since inside the function I was getting another error.

Actually now it looks like this:

...
        else {
            const userResult = await response.raw.result.find( (owner) => owner.owner_of == onwerad );
            console.log(userResult);

            const owner_of = userResult.owner_of
            const token_id = userResult.token_id
            const amount = userResult.amount
            console.log(owner_of, token_id, amount);
            console.log("ok");
            
            const MongoUser = await Users.exists({owner_of: owner_of});

            if (!MongoUser) {
                const newUser = new Users({
                    owner_of: owner_of,
                    token_id: token_id,
                    amount: amount,
                })
            }
            await newUser.save();
            console.log("everything works fine");
        };
...
...
...
...
export async function getServerSideProps(context) {
    const { owneradd } = context.query;
    await connectDB ();

    return {
        props: { owneradd },
    };
};
export default App;

You have fixed the get error? Or what is the new error?

when you add data to the database without using the Parse SDK you have to take care to make the id (object id) as string, it will not work everything as expected if the object id is not string

The same error remains, I was just saying that if I move the “connectDB” function from the getServerSideProps to inside the function I would get a new error. But the error “Cannot read propertie of null (reading ‘get’)” remains.

what line generates that error?

I am sorry Cryptokid but what do you mean? The response I am sending as a parameter it is not a string?

The code below returns me just a string with each value of the object I request from the userResult

const userResult = response.raw.result.find( (owner) => owner.owner_of == props.owneradd );

const owner_of = userResult.owner_of
const token_id = userResult.token_id
const amount = userResult.amount

It seems like the error is generated from the userSchema:

But I am not sure about that, because I try using the same Schema on another page but instead of using inside a function triggered by a button, I try using it inside of "export async function getServerSideProps() " at the end of the page and in this case it worked.

You are not setting the object id there, you may get to this issue later after you make it work

You can try to add a try catch there to see if you get more info