npm package: @parli/sdk
Description: This exposes the Lustre API as a series of React hooks in a type-safe way. It will automatically account for routing and request batching, and users of this SDK should avoid trying to manually optimize requests. If anything appears not optimal, please fil
Latest version: 0.2.0

# Lustre API

This exposes the Lustre API as a series of React hooks in a type-safe way.
It will automatically account for routing and request batching, and users of this SDK should avoid trying to manually optimize requests.
If anything appears not optimal, please file a bug rather than attempting to work around it.

## API and Versioning

This package follows semantic versioning practices.

Anything not exported from the root-level package IS NOT considered part of the public API, and may be unstable.
Attempting to "reach in" deeper to the package is not supported in any way, and has no guarantees about following SemVer.

Additionally, the `type` field on identifiers is considered a private implementation detail and is also not covered by SemVer.
See the section on identifers below.

## Required Set-up

In order to set up the necessary React Context, the Provider must be registered:

```tsx
// index.tsx or somewhere else near the package root
import React from 'react'
import ReactDOM from 'react-dom'
import { ApiProvider } from '@parli/sdk' // Add this
import App from './App'

// Replace this
// ReactDOM.render(<App />, document.getElementById('root'))
// With this:
ReactDOM.render(<ApiProvider><App /></ApiProvider>, document.getElementById('root'))
```

The API hooks *WILL NOT FUNCTION* without this provider registered into the rendering tree.

Additionally, an API key SHOULD be set for applications that must use one:

```ts
import { setApiKey } from '@parli/sdk'
setApiKey('your-access-token')
```

## Usage

**Important**:
Any function in the package starting with `use` is a React Hook, and its usage is strictly required to follow the [Rules of Hooks](https://reactjs.org/docs/hooks-rules.html) (RoH).
As they are the primary interaction with this package, developers should be familiar with the RoH and are *strongly* encouraged to set up the RoH linters.

In general, avoid trying to be clever about request management or other batching.
This library will optimize request handling, and if you find yourself trying to outsmart it, it's probably a bug - please file one!

### Queries

`import { queries } from '@parli/sdk'`

All of the functions in this structure correspond to the various Queries in the API.
They are all type-safe, and parameterized in a way to avoid type juggling.
Queries will be routed automatically to the correct back-end service, and batched appropriately.

The names do not necessarily correspond 1:1 with the API names, especially for "either-or" queries (e.g. `graph_search` accepts `question` or `context` but not both, so two methods will be exposed to handle those cases)

The `queries` functions return the body to be passed to the `useQuery` hook, _not the actual response_.
The formatted outbound request is **not** intended for use in any other place.
See its documentation below.

### Hooks

#### `useEntity`
Takes an entity identifer and returns the entity, or `undefined` if the entity has not been loaded yet.
A request to load the entity will automatically run.

Generally, the identifer will be the return type of something else - either a query response or the property of some other entity.

#### `useEntities`
Takes a list of entity identifiers and returns a list of loaded entities.
Any entities not yet loaded will be requested.
For convenience with the mechanics of `useQuery`'s not loaded state, this method also accepts `undefined`.

**Note**:
If multiple entity Id types are passed (e.g. a Brand Id and a Spec Id), the return type will infer that the entities can be any of those corresponding entities (e.g. `Array<Entities.Brand | Entities.Spec>`).
In most circumstances, this is an anti-pattern and should be avoided.

#### `useQuery`
Takes a typed Query (i.e. the return value from one of the `queries` functions) and returns the response from the API.
This will deal with the client hashes via the input parameters, so you don't need to think about that.


### Identifiers
Entities and many queries work with identifers.
Due to limitations of Javascript (and therefore typescript), type information of identifers needs to be manually propagated - this is done as a tiny object of `{ id: string, type: string }`.
Day to day, this can be mostly ignored, as the hooks accept this structure and know what to do with it.

You SHOULD use identifers as React component props, and pass them around as a whole object:

```tsx
import React from 'react'
import { Entities } from '@parli/sdk'

const ParentComponent: React.FC = () => {
  const brandId = ... // query result, field from property, etc
  return (
    <ChildComponent brandId={brandId} />
  )
}

interface ChildProps {
  brandId: Entities.Brand['id']
}
const ChildComponent: React.FC<ChildProps> = ({ brandId }) => {
  // const brand = useEntity(brandId)
  // ...
}
```

However, when dealing with [lists and keys](https://reactjs.org/docs/lists-and-keys.html#keys), it will be necessary to interact with the internals:

```tsx
// in a React FC
const entities: Entities.Brand[] = [] // e.g. result of a query or useEntities
return (
  <ul>
    {entities.map(brand => <li key={brand.id.id}>{brand.name}</li>)}
  </ul>
)
```

*If you find yourself inspecting the contents of the `Id` structure anywhere else, you are probably doing something wrong.*

### Examples

```tsx
import React from 'react'

import {
  Entities,
  queries,
  useEntities,
  useEntity,
  useQuery,
} from '@parli/sdk'

const MyComponent: React.FC = () => {
  const familyIds = useQuery(queries.uncategorizedFamiliesQueue())
  const families = useEntities(familyIds)

  return (
    <ul>
      {families.map(fam => <li key={fam.id.id}>{fam.name}</li>)}
    </ul>
  )
}

export default MyComponent
```

## Types

The type information for Entities is explicitly exported, for the common use-case of adding type annotations to a component.

```tsx
import React from 'react'
import { Entities } from '@parli/sdk'

interface Props {
  brandId: Entities.Brand['id']
}
const MyComponent: React.FC<Props> = ({ brandId }) => {
  // ...
}
```

At this time, query responses are not directly exported for similar use.
However, type information will still be attached to the return value of `useQuery`.

## Known issues

### Bugs

- Reducers don't directly tie to state tree, resulting in potential synchroniztion issues
    - e.g. before fmly entity reducer is added, useEntity(famId) is a hard crash

### Missing functionality

- Most entities are missing
- Most queries are missing
- Attributes are not supported yet
- Mutations are not supported yet