Skip to content

Generate typed effects and queries from OpenAPI 3

License

Notifications You must be signed in to change notification settings

borolgs/openapi-ff

Repository files navigation

openapi-ff

openapi-ff is a type-safe tiny wrapper around effector and farfetched to work with OpenAPI schema.

It works by using openapi-fetch and openapi-typescript.

Setup

pnpm i openapi-ff @farfetched/core effector openapi-fetch
pnpm i -D openapi-typescript typescript

Next, generate TypeScript types from your OpenAPI schema using openapi-typescript:

npx openapi-typescript ./path/to/api/v1.yaml -o ./src/shared/api/schema.d.ts

Usage

import createFetchClient from "openapi-fetch";
import { createClient } from "openapi-ff";
import { createQuery } from "@farfetched/core";
import type { paths } from "./schema"; // generated by openapi-typescript

export const client = createFetchClient<paths>({
  baseUrl: "https://myapi.dev/v1/",
});
export const { createApiEffect } = createClient(client);

const blogpostQuery = createQuery({
  effect: createApiEffect("get", "/blogposts/{post_id}"),
});
import { useUnit } from "effector-react";

function Post() {
  const { data: post, pending } = useUnit(blogpostQuery);

  if (pending) {
    return <Loader />;
  }

  return (
    <section>
      <p>{post.title}</p>
    </section>
  );
}

Advanced Usage:

import { chainRoute } from "atomic-router";
import { startChain } from "@farfetched/atomic-router";
import { isApiError } from "openapi-ff";

const getBlogpostFx = createApiEffect("get", "/blogposts/{post_id}", {
  mapParams: (args: { postId: string }) => ({ params: { path: { post_id: args.postId } } }),
});
const blogpostQuery = createQuery({
  effect: getBlogpostFx,
  mapData: ({ result, params }) => ({ ...result, ...params }),
  initialData: { body: "-", title: "-", postId: "0" },
});

export const blogpostRoute = chainRoute({
  route: routes.blogpost.item,
  ...startChain(blogpostQuery),
});

const apiError = sample({
  clock: softwareQuery.finished.failure,
  filter: isApiError,
});

Runtime Validation

openapi-ff does not handle runtime validation, as openapi-typescript does not support it.

openapi-typescript by its design generates runtime-free static types, and only static types.

However, openapi-ff allows adding a contract factory when creating a client and provides a corresponding method, createApiEffectWithContract:

const { createApiEffectWithContract } = createClient(fetchClient, {
  createContract(method, path) {
    // ... create your own contract
    return contract; // Contract<unknown, unknown>
  },
});

const query = createQuery({
  ...createApiEffectWithContract("get", "/blogposts"),
});
npx typed-openapi path/to/api.yaml -o src/zod.ts -r zod # Generate zod schemas
pnpm install zod @farfetched/zod
import { EndpointByMethod } from "./zod";
import { zodContract } from "@farfetched/zod";

const { createApiEffectWithContract } = createClient(fetchClient, {
  createContract(method, path) {
    const response = (EndpointByMethod as any)[method][path]?.response;
    if (!response) {
      throw new Error(`Response schema for route "${method} ${path}" doesn't exist`);
    }
    return zodContract(response);
  },
});

const query = createQuery({
  ...createApiEffectWithContract("get", "/blogposts"),
});

orval example

Alternatively, you can simply add any contract to a query:

pnpm install zod @farfetched/zod
npx orval --input path/to/api.yaml --output src/zod.ts --client zod --mode single
import { zodContract } from "@farfetched/zod";
import { getBlogpostsResponseItem } from "./zod";

const blogpostQuery = createQuery({
  effect: createApiEffect("get", "/blogposts/{post_id}"),
  contract: zodContract(getBlogpostsResponseItem),
});

TODO

Add createApiQuery:

createApiQuery({
  method: "get",
  path: "/blogposts/{post_id}",
  mapParams: (args: { postId: string }) => ({ params: { path: { post_id: args.postId } } }),
  mapData: ({ result, params }) => ({ ...result, ...params }),
  initialData: { body: "-", title: "-", postId: "0" },
});

About

Generate typed effects and queries from OpenAPI 3

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published