# Define Resources

[Resources](https://dataclient.io/rest/api/resource.md) are a collection of `methods` for a given `data model`.

[Entities](https://dataclient.io/rest/api/Entity.md) and [Schemas](https://dataclient.io/rest/api/schema.md) declaratively define the [_data model_](https://dataclient.io/vue/concepts/normalization.md).
[Endpoints](https://dataclient.io/rest/api/Endpoint.md) are the [_methods_](https://en.wikipedia.org/wiki/Method_\(computer_programming\)) on
that data.

**REST**

```bash
npm install @data-client/rest
```

[ Codegen](https://chatgpt.com/g/g-682609591fe48191a6850901521b4e4b-typescript-rest-codegen) 
[ Skills](https://skills.sh/reactive/data-client)

[resource()](https://dataclient.io/rest/api/resource.md) constructs a namespace of [RestEndpoints](https://dataclient.io/rest/api/RestEndpoint.md)

```typescript title="TodoResource"
import { Entity, resource } from '@data-client/rest';

export class Todo extends Entity {
  id = 0;
  userId = 0;
  title = '';
  completed = false;

  static key = 'Todo';
}

export const TodoResource = resource({
  urlPrefix: 'https://jsonplaceholder.typicode.com',
  path: '/todos/:id',
  schema: Todo,
  searchParams: {} as { userId?: string | number } | undefined,
  paginationField: 'page',
});

/** Methods can be called as functions or used in hooks */

// GET https://jsonplaceholder.typicode.com/todos/5
TodoResource.get({ id: 5 });
// GET https://jsonplaceholder.typicode.com/todos
TodoResource.getList();
// GET https://jsonplaceholder.typicode.com/todos?userId=1
TodoResource.getList({ userId: 1 });
// POST https://jsonplaceholder.typicode.com/todos
TodoResource.getList.push({ title: 'my todo' });
// POST https://jsonplaceholder.typicode.com/todos?userId=1
TodoResource.getList.push({ userId: 1 }, { title: 'my todo' });
// GET https://jsonplaceholder.typicode.com/todos?userId=1&page=2
TodoResource.getList.getPage({ userId: 1, page: 2 });
// PUT https://jsonplaceholder.typicode.com/todos/5
TodoResource.update({ id: 5 }, { title: 'my todo' });
// PATCH https://jsonplaceholder.typicode.com/todos/5
TodoResource.partialUpdate({ id: 5 }, { title: 'my todo' });
// PATCH https://jsonplaceholder.typicode.com/todos/5
TodoResource.getList.move({ id: 5 }, { completed: true });
// DELETE https://jsonplaceholder.typicode.com/todos/5
TodoResource.delete({ id: 5 });
```

**GraphQL**

```bash
npm install @data-client/graphql
```

[GQLEndpoint](https://dataclient.io/graphql/api/GQLEndpoint.md) helps quickly defined [queries](https://dataclient.io/graphql/api/GQLEndpoint.md#query) and [mutations](https://dataclient.io/graphql/api/GQLEndpoint.md#mutate)

```typescript title="TodoResource"
import { GQLEndpoint, GQLEntity } from '@data-client/graphql';

const gql = new GQLEndpoint('/');

export class Todo extends GQLEntity {
  title = '';
  completed = false;

  static key = 'Todo';
}

export const TodoResource = {
  getList: gql.query(
    `
  query GetTodos {
    todo {
      id
      title
      completed
    }
  }
`,
    { todos: new Collection([Todo]) },
  ),
  update: gql.mutation(
    `mutation UpdateTodo($todo: Todo!) {
    updateTodo(todo: $todo) {
      id
      title
      completed
    }
  }`,
    { updateTodo: Todo },
  ),
};
```

**Async/Promise**

```bash
npm install @data-client/endpoint
```

Pre-existing TypeScript definitions can be used in Data Client with
[Endpoint](https://dataclient.io/rest/api/Endpoint.md) and [EntityMixin](https://dataclient.io/rest/api/EntityMixin.md).

```typescript title="existing/Todo"
export class Todo {
  id = 0;
  userId = 0;
  title = '';
  completed = false;
}

/* These are just examples but it could be any promise API */
export const getTodo = (id: string) =>
  fetch(`https://jsonplaceholder.typicode.com/todos/${id}`).then(
    res => res.json(),
  );

export const getTodoList = () =>
  fetch('https://jsonplaceholder.typicode.com/todos').then(res =>
    res.json(),
  );

export const updateTodo = (id: string, body: Partial<Todo>) =>
  fetch(`https://jsonplaceholder.typicode.com/todos/${id}`, {
    method: 'PUT',
    body: JSON.stringify(body),
  }).then(res => res.json());

export const partialUpdateTodo = (id: string, body: Partial<Todo>) =>
  fetch(`https://jsonplaceholder.typicode.com/todos/${id}`, {
    method: 'PATCH',
    body: JSON.stringify(body),
  }).then(res => res.json());

export const createTodo = (body: Partial<Todo>) =>
  fetch(`https://jsonplaceholder.typicode.com/todos`, {
    method: 'POST',
    body: JSON.stringify(body),
  }).then(res => res.json());

export const deleteTodo = (body: Partial<Todo>) =>
  fetch(`https://jsonplaceholder.typicode.com/todos/${id}`, {
    method: 'DELETE',
  }).then(res => res.json());
```

```typescript title="TodoResource"
import { Collection, Endpoint, EntityMixin, Invalidate } from '@data-client/endpoint';
import {
  Todo,
  getTodo,
  getTodoList,
  updateTodo,
  partialUpdateTodo,
  createTodo,
  deleteTodo,
} from './existing/Todo';

export const TodoEntity = EntityMixin(Todo, { key: 'Todo' });

export const TodoResource = {
  get: new Endpoint(getTodo, { schema: TodoEntity }),
  getList: new Endpoint(getTodoList, {
    schema: new Collection([TodoEntity]),
  }),
  update: new Endpoint(updateTodo, {
    schema: TodoEntity,
    sideEffect: true,
  }),
  partialUpdate: new Endpoint(partialUpdateTodo, {
    schema: TodoEntity,
    sideEffect: true,
  }),
  create: new Endpoint(createTodo, {
    schema: new Collection([TodoEntity]).push,
    sideEffect: true,
  }),
  delete: new Endpoint(deleteTodo, {
    schema: new Invalidate(TodoEntity),
    sideEffect: true,
  }),
};
```

To aid in defining `Resources`, composable and extensible protocol specific helpers are provided for [REST](https://dataclient.io/rest.md), [GraphQL](https://dataclient.io/graphql.md),
[Websockets+SSE](https://dataclient.io/vue/concepts/managers.md#data-stream).

To use existing API definitions, or define your own protocol specific helpers, use
[Endpoint](https://dataclient.io/rest/api/Endpoint.md) and [EntityMixin](https://dataclient.io/rest/api/EntityMixin.md) from [@data-client/endpoint](https://www.npmjs.com/package/@data-client/endpoint).
\[See `Async/Promise` tab above]
