[TypeScript] WaniKani API Types (šŸ†• 2.0!)

:warning:This is a third-party script/app and is not created by the WaniKani team. By using this, you understand that it can stop working at any time or be discontinued indefinitely.


Howdy WaniKani Community!

I have for you a decently sized collection of type definitions for the WaniKani API, possibly for use in your next TypeScript application/library/etc. that needs to work with the WaniKani API.

Documentation: https://wanikani-api-types.bachman.dev/

It has:

  • Resource, Collection, and Report types for everything that’s returned by the API
  • Parameter types for constructing query strings for Collections, as well as a helper function to help stringify them
  • Payload types for data you JSON.stringify() and send to the API, such as updating preferences, starting an assignment or creating a review
  • A bunch of other type definitions found in the documentation, such as, known API revisions, various ranges/minimums/maximums, etc
  • Valibot schemas that match every type, for those who need runtime validation of their data
  • A Request Factory for building out complete, type-safe requests to the API, for use in your favorite HTTP API/Library
  • A Subject Markup Matcher for finding Japanese text, Radical/Kanji/Vocab names, meaning references, etc. within mnemonics and hints, as well as a function that can parse subject markup into a nested format for easier rendering

I encourage you to give it a spin if you feel it may be useful.

npm install @bachman-dev/wanikani-api-types
yarn add @bachman-dev/wanikani-api-types
deno add npm:@bachman-dev/wanikani-api-types
bun add @bachman-dev/wanikani-api-types
5 Likes

Thank you. This will come in handy for an idea I’m toying with (sveltekit app).

1 Like

Ahh, has Svelte/SvelteKit sucked you in yet?
I’m using it for a project at the moment. It’s refreshingly simple, yet doesn’t sacrifice.

2 Likes

Sweet! I also have some types for WKOF if you ever need them

It grabbed me hard and hasn’t let go, but I’ve not been doing too much coding recently. I wrote the ganbarometer in svelte.

Thought I’d play with a standalone app for a change. Then I took a nap until the feeling went away.

I put up a static site recently using astro.build which made it trivial to include svelte components. My brain still finds ā€œmultipageā€ easier to grok (and most of the stuff I create is mostly just a pile of static content), but sveltekit looks to have settled down enough for me to at least start playihg with it.

2 Likes

Sorry to do this to you, but…

2 Likes

Heh. I will add it to my stack of ā€œclick if you dareā€ links.

Fortunately I’m not easily distr… squirrel!

1 Like

Hope everyone had a good weekend. Just popping in with some updates:

  • We’re gonna fix that type in 0.3.0 by tomorrow night, along with any other issues with Payloads or their responses – after I test the other two (the aforementioned laundry list will have more info). For now it means deprecating WKUpdatedAssignment and removing in 1.0 since it’s mistyped, and updating WKCreatedReview to just use WKAssignment under updated_resources – under a minor version bump.
  • Other than that we’ve fixed a bug or two, exported some constants for people who dislike magic numbers in their code, and soft-renamed WKMaxSrsStagesMinusOne to WKMaxSrsReviewStages (i.e. the former type is deprecated and will get removed in 1.0)

In short, it’s the joys of the Zero Version~~

That’s what I have for now. You can keep an eye on the release notes for all the latest and greatest changes. I’ll be sure to swing by again once in a while to keep folks apprised of any important updates, bugs, answer to any questions, etc. Have a good rest of your weekend!

3 Likes

Hello again everyone. The nights are getting longer and colder (at least here in the Northeastern US), and at the same time, this library draws nearer to Version 1.0.0.

I’m finally at a point where I can pinpoint a release date with some confidence after testing things, adding some additional type guards, adjusting types so they narrow better, etc. Assuming there aren’t any major issues (which I’m fairly certain, but never wanna be too cocky, lol), y’all can expect Version 1.0.0 to drop on December 11th.

TypeScript Version 4.9 is set to release this Tuesday November 15th, so once that’s released and the library’s development version is updated, I will release version 1.0.0-rc1. This is still considered unstable, but at this point breaking changes would be highly unlikely, if anything it would be little bug fixes. I’m then giving myself (and others) a somewhat wide berth of 26 days to test this release candidate out, and if we find any other issues,we’ll push out 1.0.0-rc2, 1.0.0-rc3, etc. Keep an eye on the aforementioned release notes for the latest info.

Otherwise I just wanna give the documentation alongside the code a final proofread (I know there’s at least one formatting issue), and we’ll be all set. Everything else I’d set out to do on the previously-mentioned checklist has been completed.

Lastly, I’ve created a dedicated set of code examples in EXAMPLES.md on GitHub. I created these while testing out the various types/constants/functions. They aren’t completely robust (i.e. missing things like rate limiting and whatnot), but they should give a good idea on what this library can do.

As always feel free to let me know of any questions/feedback/issues here or on GitHub. Enjoy the rest of your Sunday evenings, and/or best of luck on your Monday mornings!

1 Like

Howdy everyone. Can’t believe there’s only a couple weeks left in the year!

Happy to announce that version 1.0.0 is out – as Stable as it can be. Aside from removing some types that were either deprecated based on testing this library against the API, or from being replaced with better typedefs, the only other breaking change was the removal of the wanikani_compatibility_mode property under WKUserPreferences, reflecting the removal of Script Compatibility Mode at the end of November.

In addition to supporting TypeScript 5.0 when it launches this Spring, I have a couple new features sitting in my brain that I’ll eventually get coded. Still putting some thought into them, but ideally…

  1. Provide a Routes object with functions that return everything one needs to make a request to any API endpoint; they won’t make the request for you, but will provide a URL and RequestInit (or similar) for you to use in fetch() or whatever HTTP/request library you prefer.
  2. Regex Pattern Matchers for Markup Highlighting, with Named Capture Groups so you can extract, format, etc. any radicals, kanji, vocab, meanings, and readings that show up in subject mnemonics and hints.

And of course, if anyone has any feature ideas that could improve this library, I’m welcome to suggestions here or on GitHub – in addition to any questions, comments, etc. you might have. Thanks in advance!

1 Like

Hello again everyone. ā€œSpringā€ might be here, but if you live in the northeastern United States like I do, you know we still might have a little more wintry weather to go.

Still, the potential for lousy weather can’t stop a new version of the library being released – 1.1.0 – and it has some new features:

Support for TypeScript 5.0

And better yet, still able to support TypeScript 4.5 and up.

WKRequestFactory and Request Types

Documentation

In version 1.0, I provided a means for converting a Parameters object (i.e. when requesting a Collection) into a string, to be appended onto the end of the URL for the given resource. So a request to get a user’s lessons might start with something like this:

const params: WKAssignmentParameters = {
  immediately_available_for_lessons: true,
}
const url = `https://api.wanikani.com/v2/assigmnents${stringifyParameters(params)}`;
const headers = {
  Authorization: `Berer ${SECRET_API_TOKEN}`,
  "Wanikami-Revision": WK_API_REVISION,
};

const init: RequestInit = {
  headers,
}

const response = await fetch(url, init);
if (!response.ok) {
  throw new Error(`HTTP Error ${response.status}`);
}

But if you sent that request, you’d throw an error, cause WaniKani would respond with HTTP Error 401. Fix that, and now it throws due to HTTP Error 404. Fix that, and while you’ll get the data you’d expect today, if WaniKani bumps their API revision, you’ll still get data from revision 20170710!

For those who prefer to do this sort of thing programmatically, you can use WKRequestFactory to build complete, type-safe requests to the API. The example above becomes…

const params: WKAssignmentParameters = {
  immediately_available_for_lessons: true,
}
const wk = new WKRequestFactory(
  {
    apiToken: SECRET_API_TOKEN,
    revision: WK_API_REVISION,
  }
);
const { url, headers } = wk.assignments.get(params);

const init: RequestInit = {
  headers,
}

const response = await fetch(url, init);
if (!response.ok) {
  throw new Error(`HTTP Error ${response.status}`);
}

And of course, if you don’t like or don’t have access to the Fetch API, the returned WKRequest object’s properties can be used in whichever HTTP API/Library you prefer or need to use. There’s also options available to set additional headers for one or all requests noted in the documentation.

If you can’t or don’t want to use the entire factory to build out your requests, that’s fine, too! The WKRequestHeaders interface can help make sure your request’s headers are named and formatted properly (e.g. saying Bearer, not Berer for the Authoriztion header, setting valid Accept and Content-Type headers, offering autocomplete for editors, etc.), and stringifyParameters will always be around to append onto resource URLs just like before.

Subject Markup Matchers

A new object WK_SUBJECT_MARKUP_MATCHERS provides Regex Literals for the Japanese text, Radical/Kanji/Vocab names, meanings/readings, etc. found in the subject meaning/reading mnemonics and hints. They have a named capturing group, innerText, that can be accessed on methods like String.prototype.matchAll().

For instance, if you’re building a React-powered website, you may want to stylize Radical names similar to WaniKani’s site.

import { WK_SUBJECT_MARKUP_MATCHERS } from "@bachmacintosh/wanikani-api-types/dist/v20170710";
import reactStringReplace from "react-string-replace";

reactStringReplace(
  'The <radical>ground</radical> moves under my feet.', 
  WK_SUBJECT_MARKUP_MATCHERS.radical,
  (match, i) => (
    <span className="bg-light-blue text-white font-bold">
      {match}
    </span>
));
/* 
=> [
  'The ',
  <span className="bg-light-blue text-white font-bold">ground</span>,
  ' moves under my feet.' 
] 
*/

For info on the methods available on these patterns, see RegExp. Note that these regex literals are global, something to keep in mind when using certain string and regex methods.

Validators

If you need to do runtime validation of Parameter and/or Payload objects, or are running into weird TypeScript type-widening behavior on the Parameter types that you need to step around, the validateParameters() and validatePayload() helper functions are what you need. They throw a TypeError if the object is missing or has unexpected properties. And of course, these can be used when making requests to catch errors before you actually send or request data via the API; I even use them in the already-mentioned WKRequestFactory methods.


As always, any feedback or issues are welcome here or on GitHub. The library has over 99% test coverage, but you never know about that less than 1% chance of a bug or other weird behavior.

Otherwise, see you in a couple months with version 1.2, which will support TypeScript 5.1 – any new features yet to be determined.

1 Like

Huh

I’m not gonna lie, this may actually get me to work on that Android WK API client I’ve had on the back burner for a while

Version 1.2 is now available! It’s a small update accommodating a big change (well, I think it’s kinda big anyway) to WaniKani’s subjects.

Kana Vocabulary Types

We’ve added type definitions for Kana Vocabulary, a new subject type that is like vocabulary, but is only made up of hiragana and/or katakana, and thus has no kanji readings attached.

  • WKKanaVocabulary for an entire single kana-only vocabulary resource (top-level)
  • WKKanaVocabularyCollection for a collection of kana-only vocabulary
  • WKKanaVocabularyData for the actual data found within the resource (characters, parts of speech, the mnemonic, etc.)
  • WKSubject was also updated to include WKKanaVocabulary in its union, in case you’re working with mixed or unknown subject types

Other Changes

The documentation now has a nice sidebar with dropdowns of all the categories of things this library exports.

The supported TypeScript version range in our peerDependencies has also been updated to better illustrate the correct supported versions. Previously, it was ^4.5.0 || ^5.0.0, which did not correctly specify our support of only TypeScript 4.5 to 5.0, not including 5.1, 5.2, etc. until they are released and tested against (since TS doesn’t use Semantic Versioning). The range now reads 4.5.x - 5.0.x which should be more clear on which TS versions are supported.

Last, we now provide package provenance on package versions. This will give you a quick glimpse on where the version was built, what git commit was referenced, what build steps were taken, etc. Most users won’t need this info, but it can help for those with a knack for version integrity in their dependency tree.

Unless WaniKani surprises us with another new feature in the next couple weeks, see y’all in early June for 1.3 and TypeScript 5.1 support!

1 Like

Version 1.3.0 is out, with support for TypeScript 5.1; we also still support TypeScript going back to 4.5!

I don’t have any planned features between now and late August/early September when TypeScript 5.2 is released, but instead plan on looking into a couple ways to improve the building and testing pipeline of the project. That said, I’ll see y’all in late Summer with version 1.4. :slight_smile:

1 Like

Howdy howdy! I’ve been keeping this library up-to-date over on GitHub the past couple of years, mostly just to widen the supported TypeScript versions, and occasionally to fix an upstream regression with the WaniKani API.

I’ve moved the library from the @bachmacintosh scope over to @bachman-dev, so any current installs will want to change the package specifier per the runtime being used.

-"@bachmacintosh/wanikani-api-types": "^1.7.0",
+ // or stay on 1.8.0 if you can't upgrade right away!
+"@bachman-dev/wanikani-api-types": "^2.0.0",

Version 2.0.0 was also recently released. It contains a decent amount of breaking changes. We have an Upgrade Guide that lists them all and includes some code change considerations.. The new features, such as runtime schema validation for all the types, and type guards for all data returned by the WaniKani API, should make the inconvenience worth it.

If it’s a bit much to upgrade right now, don’t worry. Version 1.8.0 is the latest 1.x version, and between it having no actual dependencies and its TypeScript supported version being widened to anything >= 4.5, it should work for a long while. Just remember to update the scope of the package specifier, as mentioned above.

Either way, I plan to keep maintaining this package mostly to keep TypeScript support going, as well as keeping an eye out for any regressions in the API that might get announced. Otherwise feel free as always to leave any questions, comments, suggestions, etc. either in this thread or over on GitHub. :tada:

1 Like