javascriptsparqlsame-origin-policywikidata

Searchstring to WikiData entity ID


Question

How do I get from an animal name (tiger) to its WikiData entity id (Q19939) in a static website?

Context

I am writing a small static website (no backend, just html and vanilla javascript) where the user enters the name of an animal (tiger) and the website displays information about that animal.

I want to get the shown data from WikiData. (I am new to WikiData, so this is a good opportunity to learn). This works great if I have the WikiData entity id (Q19939 for tiger). With that I can query the wikidata-sparql-api and get all the data I need.

How do I get the WikiData entity id (Q19939) from the animal name (tiger)?

Here is a minimal example of how the final website might look like:

<!doctype html>
<html>
    <body>
        <div id="output"></div>

        <script>
            async function getWikidataId(entityName) {
                // TODO find id somehow
                return undefined;
            }

            async function tell_reader_about(animalName) {
                const wikidataId = await getWikidataId(animalName);
                document.getElementById("output").innerText =
                    `${animalName} has WikiData entity ID ${wikidataId}`;
            }
            tell_reader_about("tiger");
        </script>
    </body>
</html>

What I tried

I see mainly two ways here:

Attempt A: Use the MediaWiki API

The MediaWiki API seems perfect for my usecase. I can provide the animal name as an query parameter.

https://www.wikidata.org/w/api.php?action=wbsearchentities&search=tiger&language=en

It returns a list of fitting wikidata entities with a description.

{
    "search": [
        {
            "id": "Q79081545",
            "label": "Tiger",
            "description": "unisex given name",
            ...
        },
        {
            "id": "Q19939",
            "label": "tiger",
            "description": "species of big cat",
            ...
        },
        {
            "id": "Q16282104",
            "label": "Tiger",
            "description": "family name",
        },
        ...
    ],
    "search-continue": 7,
    "success": 1,
    ...
}

This is awesome, from here I could choose which id is the right one and use it.

But when I do this in my static website I get the following error:

Cross-Origin Request Blocked:
The Same Origin Policy disallows reading the remote resource at https://www.wikidata.org/w/api.php?action=wbsearchentities&search=apple&language=de&format=json.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Status code: 200.

This sounds to me like that API is not available for me to use. Or is there a way to make this work?

Attempt B: Use the WikiData sparql API

I could try to do another sparql request. (The sparql API seemingly has that CORS header set) As far as I can see Wikidata doesn't like to match entities against strings, only against other entities. But it should work in theory. I tried a few queries, but they all timed out or didn't give me any results.

SELECT ?item ?itemLabel WHERE {
  ?item wdt:P31 wd:Q16521.
  FILTER(LCASE(?itemLabel) = LCASE("tiger")) .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],mul,en". }
}

try it

How a solution could look like

I can think of multiple solutions to this problem:


Solution

  • As @UninformedUser said: Use entity search via SPARQL:

    SELECT ?item
    WHERE {
      SERVICE wikibase:mwapi {
        bd:serviceParam wikibase:api "EntitySearch" ;
                        wikibase:endpoint "www.wikidata.org" ;
                        mwapi:search "tiger" ;
                        mwapi:language "en" .
        ?item wikibase:apiOutputItem mwapi:item .
        ?num wikibase:apiOrdinal "true"^^xsd:boolean .
      }
    }
    ORDER BY (?num)
    LIMIT 5