klar
v1.0.5
Published
A tool to infer and generate static type definitions of resources returned by backend APIs.
Downloads
13
Maintainers
Readme
klar
klar reads responses from backend endpoints and generates strongly typed interface definitions that clearly describe the data returned. It outputs GraphQL Schemas, TypeScript Definitions, and flow types.
klar returns interfaces whose members are always scalar values. If a member is a nested object, it continues to recursively define interfaces until final scalar values are available.
It could be extended to also just describe any old POJSO.
Motivation
Developer experience is something that is important to me. Developer convenience is something I enjoy. I'd like to, just before yarn start
ing a web application that interacts with some type of backend, fetch the latest, greatest resource type definitions for my project, and then take full advantage of my editor's incredible intellisense, allowing me to have on-demand autocomplete for the data I'm working with.
Getting Started
To get started with klar, you'd need to tell it where your data lives. To do this, you'd need to create a config file. I know zero-config is currently sexy, but this is information that we have no way of inferring.
A klar.config.js
is a file that points klar in the right direction. Consider,
module.exports = {
url: "https://jsonplaceholder.typicode.com",
resources: {
Post: "/posts",
Comment: "/comments",
Album: "/albums",
Photo: "/photos",
Todo: "/todos",
User: "/users",
},
};
As soon as your config file is in place, simply npx klar
in your project, and you'll magically have interface definitions. Alternatively, yarn add klar -D
will add it as a dependency in your project so it can be attached to a prestart
script or similar.
Config File
klar.config.js
is a barebones file that points klar in the right direction. It does so by giving klar a URL against which to send requests, and a map of resource names and their respective paths as we've already seen in the previous example.
A full illustration of the config options available to you in this file is below.
module.exports = {
url: "https://jsonplaceholder.typicode.com",
/**
* A function that is applied to the immediately
* returned data.
*/
resolve: data => data.iOnlyWantThisKey,
resources: {
Post: "/posts",
// You can also specify resource-level resolvers,
Comment: { path: "/comments", resolve: data => data.comment },
Album: "/albums",
Photo: "/photos",
Todo: "/todos",
User: "/users",
},
/**
* Request options that follow the Init spec
* of the fetch API: https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
*/
request: {
// headers, credentials, etc. go in here.
},
};
CLI Configuration
As a CLI tool, klar supports the following configuration options:
--configFile
, -c
Path to an alternative config file instead of klar.config.js
that implements an identical exported schema.
--outDir
, -o
This option specifies an output folder for your definition files. Current working directory by default.
--dataProp
, -d
Usually in the GraphQL world, but also quite common: data sometimes lives in a data
property in a returned response. When this flag is set, it simply unwraps the response and defines interfaces based on the shape of response.data
.
--graphql
, -g
Output GraphQL schema definitions instead of TypeScript files. 🔥
--flow
, -f
Output Flow type definitions instead of TypeScript files.
--prefix
, -p
This option will prefix interface names with the name of the resource defined in the config file. Consider,
// klar.config.js
{
resources: {
Bae: '/wolf',
}
}
// in terminal,
klar -p
// Bae.d.ts
interface Bae {
name: string
otherNestedProperty: BaeOtherNestedProperty
}
interface BaeOtherNestedProperty {
like: boolean
}
Without the prefix option, otherNestedProperty
's interface definition would have been un- prefixed: OtherNestedProperty
. This namespacing helps multiple exported interfaces with identical identifiers.
Why klar?
klar is the German word for "clear". I chose to call this project klar because it makes resource types (or object shapes) fairly clear.
Typically, in German culture, when a type of contract is formed, it's usually agreed upon with the phrase "Alles klar", or "all clear".
I like how the metaphor applies to this use case of clear communication between client and server.
Next Steps
While this tool has already helped me quite a lot, there is room for improvement! Below is a summary of how it can be improved, and areas wherein you can get involved!
- Cover klar with tests for what can be tested.
- Find a comfortable way to handle authenticated requests.
- Find a comfortable way to request specific resources without requiring specific IDs: currently, the resource map from the config file expects a path to a resource with a specific ID, which it fetches and whose type information it infers. It would be interesting to see how we proceed when specific IDs are unknown.
Contributing
Start with an issue. Let's discuss the issue, and then one of us will submit a pull request.