How to find all WaniKani Kanji through API. (JavaScript)

I’m currently trying to create an extension in which I would like to see all of the radicals, kanji, and vocabulary that is offered on WaniKani.

I was able to fetch the first 1000 of them through the endpoint: https://api.wanikani.com/v2/courses
basing my code off of here.

However, when I try to fetch more kanji (through the link provided in response.pages.next_url):
https://api.wanikani.com/v2/courses?page_after_id=1000

I get a 403 error:

Access to fetch at 'https://api.wanikani.com/v2/subjects?page_after_id=1000' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I have tried to circumvent the problem by sending my GET requests through a back-end server with node.js to no avail.

Would there be any way around this problem, or another endpoint which could be used to fetch this information?

Here’s my code:

const token = '<token>';
const headers = new Headers({
  Authorization: 'Bearer ' + token,
});

let grab = (endpoint) => {
  fetch('https://api.wanikani.com/v2/' + endpoint, {
      method: 'GET',
      headers: headers
    }
  )
    .then(response => response.json())
    .then(responseBody => {
      console.log(responseBody);
    });
}

grab("subjects");
grab("subjects?page_after_id=1000"); // error

For your information, the Item Inspector script has the All Wanikani Items table by default.

1 Like

Thank you, I will try that out.

Weird! I believe the addition of an Authorization header makes your requests “non-simple” (see Mozilla documentation on simple requests) which triggers the CORS preflight check, and since WK’s API doesn’t return a Access-Control-Allow-Origin header, your requests are being disallowed (edit: actually it does return CORS — see replies below).

I don’t understand why your first request would work and the second one wouldn’t though — my reading of the documentation is that query strings wouldn’t affect simple versus non-simple, and just having Authorization in there would cause a CORs check to always happen.

If you’re okay using JS from Node, you could probably use a non-Fetch API client to circumvent the problem, but when trying to run it from a browser, you might be out of luck — they’re pretty stringent on behavior around cross-server requests as it’s deeply baked into the security model.

Since subjects are relatively static, you could also consider just fetching them via command line and then bundling up the JSON into your extension directly:

export WANI_KANI_API_TOKEN=...
curl -H "Authorization: Bearer $WANI_KANI_API_TOKEN" 'https://api.wanikani.com/v2/subjects' > page1.json
curl -H "Authorization: Bearer $WANI_KANI_API_TOKEN" 'https://api.wanikani.com/v2/subjects?page_after_id=1000' > page2.json

1 Like

CORS is now enabled on the WK API it seems so that’s not the issue here. I think this is a recent change?

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Expose-Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
Access-Control-Max-Age: 7200
Access-Control-Allow-Headers: authorization

I wrote a Python fetcher for vocab at some point, and afaik, you can’t fetch more than 1k items at a time. See the API docs:
https://docs.api.wanikani.com/20170710/#introduction

In the end I had to filter by WaniKani level so perhaps that’s an option as well.

EDIT:
I read the OP again, my bad. Please disregard if the link is not useful :slight_smile: .

Huh, you’re right — I was accidentally looking at the headers on the main API response rather than checking a preflight request with OPTIONS.

Still though, it seems like with or without query string, you get a valid set of CORS headers back, so I’m still not sure what would cause the discrepancy:

$ curl -X OPTIONS -i -H "Authorization: Bearer $WANI_KANI_API_TOKEN" 'https://api.wanikani.com/v2/subjects' -H "Access-Control-Request-Method: GET" -H "Access-Control-Request-Headers: origin, x-requested-with" -H "Origin: https://foo.bar.org"
HTTP/1.1 200 OK
Server: Cowboy
Date: Sun, 31 Oct 2021 00:02:18 GMT
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Expose-Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
Access-Control-Max-Age: 7200
Access-Control-Allow-Headers: origin, x-requested-with
Vary: Accept-Encoding
Transfer-Encoding: chunked
Via: 1.1 vegur

$ curl -X OPTIONS -i -H "Authorization: Bearer $WANI_KANI_API_TOKEN" 'https://api.wanikani.com/v2/subjects?page_after_id=1000' -H "Access-Control-Request-Method: GET" -H "Access-Control-Request-Headers: origin, x-requested-with" -H "Origin: https://foo.bar.org"
HTTP/1.1 200 OK
Server: Cowboy
Date: Sun, 31 Oct 2021 00:03:02 GMT
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Expose-Headers: RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
Access-Control-Max-Age: 7200
Access-Control-Allow-Headers: origin, x-requested-with
Vary: Accept-Encoding
Transfer-Encoding: chunked
Via: 1.1 vegur
1 Like