Мы рады объявить о выпуске ChiselStrike 0.15, предоставляя нашим разработчикам клиентский API TypeScript для использования в веб-приложениях и программах Node.js. У нас всегда был автоматически сгенерированный REST API, полученный из вашей модели данных, и теперь этот клиент значительно упрощает работу, особенно с одностраничными приложениями. Он был разработан специально для работы с TanStack Query, популярным инструментом для управления запросами и повышения их производительности в ваших веб-приложениях.

Какая польза?

Приложения, построенные на ChiselStrike, обычно объявляют одну или несколько сущностей для описания своей модели данных. Сущности — это просто классы TypeScript, добавленные в специальный исходный каталог models, например:

import { ChiselEntity } from "@chiselstrike/api"

export class BlogPost extends ChiselEntity {
    author: string = "Anonymous"
    content: string
    publishedAt: number
    hidden: boolean
}

Затем, чтобы предоставить полностью RESTful CRUD API для этой сущности, этот код помещается в каталог routes (в данном случае это файл с именем posts.ts — это имя важно, как мы увидим позже):

import { BlogPost } from "../models/BlogPost"

export default BlogPost.crud()

Это весь код, необходимый для начала чтения и записи объекта BlogPost через HTTP. Но обычно для создания всех URL-адресов со строками запроса и анализа ответов JSON требуется много клиентского кода. JSON также теряет все данные типа о BlogPost и его свойствах. Мы хотим удалить все эти шаблоны, а также предоставить в ответ строго типизированные данные BlogPost. Это то, что делает новая клиентская библиотека.

Как это работает

Чтобы клиентский код имел правильные типы для объекта BlogPost, нам нужно сгенерировать некоторый специальный код на основе класса объекта выше. ChiselStrike CLI теперь может сделать это за вас. Сначала ваш локальный сервер разработки должен быть запущен в оболочке:

$ npm run dev

Затем в другой оболочке выполните следующую команду и выберите каталог, в который будет записан исходный код TypeScript:

$ npm exec chisel generate [path/to/dir]

chisel generate запрашивает работающий сервер об активных объектах и ​​маршрутах и ​​создает несколько файлов в выбранном каталоге, большинство из которых вам не нужно читать. Важными частями являются сгенерированный тип для BlogPost в models.ts:

export type BlogPost = {
    id: string;
    author: string;
    content: string;
    publishedAt: number;
    hidden: boolean;
};

И фабричная функция для клиента в client.ts:

export function createChiselClient(config: ClientConfig)

Для каждого объекта, связанного с маршрутом, будет один сгенерированный тип.

Как это использовать

Допустим, у вас есть приложение React, и вы сгенерировали вышеуказанные файлы в его каталог src/chisel. Теперь вы можете импортировать client.ts и models.ts и начать использовать их против локального сервера разработки. Вот как это выглядит, если вы хотите запросить все экземпляры BlogPost и поместить их в массив:

import { Message } from "./chisel/models"
import { createChiselClient } from "./chisel/client"

const chiselClient = createChiselClient({
    serverUrl: "http://localhost:8080"
})

const posts: BlogPost[] = await chiselClient.posts.getAll()

Обратите внимание, что в объекте chiselClient, возвращаемом createChiselClient, есть свойство с именем posts. Это свойство существует из-за маршрута, объявленного в исходном файле posts.ts, определенном выше. Будет одно такое свойство для каждого маршрута, который chisel generate обнаруживает с работающего сервера. Внутри клиентская функция getAll делает чудеса, сопоставляя ответ JSON от REST API с объектами BlogPost с правильными типами.

Конечно, вызов getAll должен быть в хуке, и вы должны использовать его в шаблоне JSX для заполнения компонента.

Как это работает с TanStack Query

Если вы еще не используете TanStack Query, сделайте это! Он берет на себя большую часть тяжелой работы, которая делает запросы к базе данных простыми и эффективными. С ним хорошо работает клиентский API ChiselStrike. Вот как может выглядеть компонент React при минимальном использовании TanStack и ChiselStrike:

function usePosts() {
  return useQuery(["posts"], () => {
     // Here we use the ChiselStrike API in the TanStack Query function
     return chiselClient.messages.getAll()
  })
}

function PostsComponent() {
  const { data, status, isLoading, error } = usePosts()
  if (isLoading) return <div>Loading</div>

  // data is now an array of BlogPost, or undefined
  return (
    <div>
      { data?.map(post => (
        <div key={ post.id }>
          <div>{ post.author }</div>
          <div>{ post.content }</div>
        <div/>
      ))}
    </div>
  );
}

function App() {
  return (
    <div className="App">
      <QueryClientProvider client={queryClient}>
        <PostsComponent/>
      </QueryClientProvider>
    </div>
  )
}

Хук useQuery TanStack принимает функцию запроса, внутри которой мы просто используем клиентский API ChiselStrike для возврата обещания, которое выполняется с массивом объектов BlogPost для рендеринга. TanStack сохраняет тип массива, так что результирующий объект данных имеет строго типизированные объекты BlogPost для повторения.

Что еще нужно знать

Клиентский API полностью поддерживает различные HTTP-методы, поддерживаемые ChiselStrike и объединяет их в простой в использовании API. Он также понимает любые отношения сущностей, которые вы могли установить в своей модели.

API внутри использует стандартный API веб-выборки для выполнения HTTP-запросов. Это означает, что сгенерированный TypeScript также работает в средах Node.js, где доступен API выборки. Это замечательно, если вы используете Node 18 для предварительного рендеринга своего сайта, так как вы можете использовать тот же клиентский код для запроса контента для рендеринга.

Подробную документацию и примеры кода см. в Документации по клиентскому API. А если вы что-то строите с помощью ChiselStrike, сообщите нам об этом в Discord или Twitter. Удачного долбления!