Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: metadata api #44

Closed
wants to merge 12 commits into from
Closed

feat: metadata api #44

wants to merge 12 commits into from

Conversation

justgigio
Copy link
Contributor

@justgigio justgigio commented Jul 14, 2021

Rendered Design

We'll keep current token meta endpoint for retro compatibility and remove it once the explorer is reaching the new endpoint.

Before Merge

  • Create a PR removing the old token meta endpoint and things related to them
  • Create new bucket and folders
  • Copy meta jsons to new bucket

After Merge

  • Delete old bucket

@justgigio justgigio self-assigned this Jul 14, 2021
@justgigio justgigio linked an issue Jul 14, 2021 that may be closed by this pull request
:type nft: :py:class:`domain.metadata.token_metdata.TokenNFT`
"""
id: str
verified: Optional[bool] = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Optional? What does None mean in this case? Add the description in the docstring, please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to let the json have only the fields that matter. Docstring updated.

"""
id: str
verified: Optional[bool] = False
banned: Optional[bool] = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Optional? What does None mean in this case? Add the description in the docstring, please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to let the json have only the fields that matter. Docstring updated.

id: str
verified: Optional[bool] = False
banned: Optional[bool] = False
reason: Optional[str] = ''
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Optional? What does None mean in this case? Add the description in the docstring, please.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property only make sense for banned tokens

@@ -80,7 +80,7 @@ jobs:
REDIS_HOST: ${{ secrets.REDIS_HOST }}
REDIS_PORT: 6379
REDIS_DB: 0
TOKEN_METADATA_BUCKET: token-metadata-testnet
METADATA_BUCKET: metadata-testnet
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add this in the TODO as well.

Create new buckets, migrate token info from old bucket to the new one and delete old bucket when everything is working fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still missing some
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it covers all, but i'll be more specific

usecases/get_metadata.py Outdated Show resolved Hide resolved
gateways/metadata_gateway.py Show resolved Hide resolved


@dataclass
class MetaTransaction:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we add any new property in transaction metadata we need to update the explorer service? Imagine we want to mark a tx as banned or as important (don't know why but just imagining possible situations). How do we handle this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and i think that is the right thing to do. Otherwise we could broke things in explorer or have other unpredictable problems.



class GetTokenMetadata:

def __init__(self, token_gateway: Union[TokenGateway, None] = None) -> None:
self.token_gateway = token_gateway or TokenGateway()
def __init__(self, metadata_gateway: Union[MetadataGateway, None] = None) -> None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Optional[MetadataGateway].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -1,17 +1,17 @@
from typing import Union

from gateways.token_gateway import TokenGateway
from gateways.metadata_gateway import MetadataGateway


class GetTokenMetadata:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mark as deprecated and that it will be removed soon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


class GetMetadata:

def __init__(self, metadata_gateway: Union[MetadataGateway, None] = None) -> None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Optional[MetadataGateway].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


def get(self, type: str, id: str) -> Union[dict, None]:
metadata_methods = {
'token': self.metadata_gateway.get_token_metadata,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the end of the day, both are "BaseTransactions" in the DAG. Isn't it easier to use just one gateway?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gateway is the same, only the method changes. Each method return a different type of meta.

usecases/get_metadata.py Show resolved Hide resolved


class TokenGateway:
"""Gateway for Token

:param s3_client: Client for s3 manipulation, default to domain S3Client
:type s3_client:
:param hathor_core_client: Client for make hathor-core requests, default to domain HathorCoreClient
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HathorCoreClient?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It is the client to make requests for a full-node. get_token method uses it therefore will be changed soon.

def _metadata_bucket(self) -> str:
metadata_bucket = METADATA_BUCKET

if metadata_bucket is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it better to validate all configuration in the constructor? So we can assume everything is right when we get to this point?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so as we can have methods that don't need this constant.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All methods need this constant for now, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pedroferreira1 yes, but i still feel it's not good to check in constructor. We don't have this var in test env, for instance and i don't think we must to. Of course for some tests we have to mock it, but some tests just don't care about it and i think it doesn't make sense to mock a var only for the class to not break.

I know it's just test but i think it's a good indication why maybe it's not so good to check this on constructor.


:param id: token id
:type id: str
:raises Exception: The name of the bucket used to store the jsons must be on config
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel this error should belong to this method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. This error is thrown by _get_metadata method, i've removed from the docstring.


return TransactionMetadata.from_dict(transaction_metadata)

def get_token_metadata(self, id: str) -> Union[TokenMetadata, None]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Optional[TokenMetadata].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


@dataclass
class TransactionMetadata(Metadata):
data: Optional[MetaTransaction] = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we using two classes? I feel it would be simper to use one class with all fields there. Well, we can group in subclasses for specific cases if there are too many fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have only specific cases by now. We can use Union[Meta1, Meta2] in places that will handle metadata but i think that is not scalable.

@justgigio justgigio changed the base branch from dev to main July 28, 2021 03:43
@justgigio justgigio changed the base branch from main to dev July 28, 2021 03:43
@justgigio justgigio force-pushed the feat/metadata-api branch from faf15fa to ee657c0 Compare July 28, 2021 03:44
domain/metadata/token_metadata.py Outdated Show resolved Hide resolved
gateways/metadata_gateway.py Show resolved Hide resolved
def _metadata_bucket(self) -> str:
metadata_bucket = METADATA_BUCKET

if metadata_bucket is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All methods need this constant for now, right?

text/0003-metadata-api.md Outdated Show resolved Hide resolved
text/0003-metadata-api.md Outdated Show resolved Hide resolved
domain/metadata/token_metadata.py Outdated Show resolved Hide resolved
"nft_media": {
"type": "IMAGE",
"file": "http://curtis-white.com/mean/officer.png",
"loop": false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it required even for image files? Does it work only for videos or audios can play in loop as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not required in s3 json files but will be always present on responses.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the documentation must have the details for each field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the datails on fields structure explanation

domain/metadata/token_metadata.py Outdated Show resolved Hide resolved
domain/metadata/token_metadata.py Outdated Show resolved Hide resolved
domain/metadata/token_metadata.py Outdated Show resolved Hide resolved

```
TokenMeta { // if type is token
id: string, // hash id of token or transaction
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: 'hash id of token or transaction ' -> 'token uid'

banned: boolean, // if token is banned
reason: string, // reason of ban
nft: boolean, // if token is a NFT
nft_media: { // media data of NFT
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: 'media data of NFT (optional)'

}

TransactionMeta {
id: string, // hash id of token or transaction
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: 'hash id of token or transaction ' -> 'transaction hash'

Base automatically changed from dev to main September 14, 2021 01:58
@r4mmer
Copy link
Member

r4mmer commented Oct 12, 2021

Feature implemented on #67

@r4mmer r4mmer closed this Oct 12, 2021
@r4mmer r4mmer deleted the feat/metadata-api branch December 1, 2021 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: Tx/Token Metadata API
4 participants