restful-react로 시작하는 OPEN API

53117 단어 ReactTypeScripttech

개시하다


OpenAPI를 사용하여 개발하는 사람들은 대부분 코드 발생기를 사용한다.
그중 이번에는 제가 최근에 제품에서도 사용했던restful-react를 소개해 드리고 싶습니다.

이른바 restful-react


OpenAPI의 yml을 읽고 괜찮은 유형 정보와 요청용 연결을 생성합니다.
https://github.com/contiamo/restful-react
보기 좋을 뿐만 아니라 간단하기 때문에 코드를 보는 것이 더 빠를 것이다.
바로 사용해 보세요!

설치하다.


yarn add restful-react

유형 생성 시도

Get localhost:8080/users사용자의 일람을 얻을 수 있는 단점을 생각해 봅시다.
우선 오픈api의yml를 정의합니다.
schema.yml
openapi: 3.0.0
info:
  description: "restful-react example."
  title: "test endpoints"
  version: "1.0.0"

servers:
  - url: http://localhost:8080
paths:
  /users:
    get:
      description: get users
      operationId: get users
      responses:
        200:
          $ref: "#/components/responses/users"
components:
  schemas:
    user:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
      required:
        - id
        - name
        - email
  responses:
    users:
      description: users
      content:
        application/json:
          schema:
            type: array
            items:
              $ref: "#/components/schemas/user"
package.json에 생성용 명령을 추가합니다.
package.json
{
  "name": "restful-react-example",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    ...
    "restful-react": "^15.1.3",
    ...
  },
  ...
  "scripts": {
    ...
    "generate": "restful-react import --file ./schema.yml --output ./src/api/generate.tsx"
  }
}
그럼 코드를 만들어 보세요.
yarn run generate
성공하면 다음 로그가 출력됩니다.
yarn run v1.22.4
$ restful-react import --file ./schema.yml --output ./src/api/generate.tsx
🎉  Your OpenAPI spec has been converted into ready to use restful-react components!
✨  Done in 0.97s.
나는 생성된 파일이 이렇다고 생각한다.
src/api/generate.tsx
/* Generated by restful-react */

import React from "react";
import { Get, GetProps, useGet, UseGetProps } from "restful-react";
export interface User {
  id: number;
  name: string;
  email?: string;
}

/**
 * users
 */
export type UsersResponse = User[];

export type GetUsersProps = Omit<GetProps<UsersResponse, unknown, void, void>, "path">;

/**
 * get users
 */
export const GetUsers = (props: GetUsersProps) => (
  <Get<UsersResponse, unknown, void, void>
    path={`/users`}
    
    {...props}
  />
);

export type UseGetUsersProps = Omit<UseGetProps<UsersResponse, unknown, void, void>, "path">;

/**
 * get users
 */
export const useGetUsers = (props: UseGetUsersProps) => useGet<UsersResponse, unknown, void, void>(`/users`, props);
중요한 부분만 봐요.
우선,yml의components/schemas/user와 대응하는 것은
export interface User {
  id: number;
  name: string;
  email?: string;
}
다음,ymlcomponents/responses/users에 대응하는 것은
export type UsersResponse = User[];
마지막으로 paths/users에서 정의한 단점에 대한 요청에 대한 사용자 정의 연결은 다음과 같다.
export const useGetUsers = (props: UseGetUsersProps) => useGet<UsersResponse, unknown, void, void>(`/users`, props);
이 정도면 충분히 개발할 수 있어!

부탁을 해봐


방금 생성된 유형 정보를 사용하여 실제 요청을 시도해 보십시오.
src/App.tsx
import React from 'react'
import { useGetUsers } from './api/generate'

export const App = () => {
  const { data, loading, error } = useGetUsers({}) // これでリクエストされる

  if (loading) return <div>loading</div>
  if (error) return <div>{error}</div>
  if (!data) return <div>ユーザーが見つかりません</div>

  return (
    <div>
      {data.map(user => (
        <div>
          <div>{user.id}</div>
          <div>{user.name}</div>
          <div>{user.email || 'none'}</div>
        </div>
      ))}
    </div>
  )
}
방금 생성된 useGetUsers 마운트할 때 요청합니다.
요청이 완료되면 응답이 저장됩니다.
데이터의 유형은 방금 생성된 유형data을 사용했다.
요청자는restful-react의 UsersResponse | null에 URL을 지정합니다.
src/index.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { RestfulProvider } from 'restful-react'
import { App } from './App'

ReactDOM.render(
  <React.StrictMode>
    {/* URLを指定 */}
    <RestfulProvider base="http://localhost:8080">
      <App />
    </RestfulProvider>
  </React.StrictMode>,
  document.getElementById('root'),
)
아주 간단하네요.스타일링이 좋아서 안심이 돼요.
그럼 실행해 보세요.
yarn run start

RestfulProviderGet의 요구가 이루어졌다!

매개변수 사용

localhost:8080/usersURL 매개 변수를 포함하는 끝점에 요청하고 싶습니다.
우선 패턴을 수정한다.
schema.yml
...
paths:
  # 追加
  /users/{id}:
    get:
      description: get user
      operationId: get user
      parameters:
        - $ref: "#/components/parameters/id"
      responses:
        200:
          description: ok
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/user"
  ...
components:
  # 追加
  parameters:
    id:
      name: id
      in: path
      description: id
      required: true
      schema:
        type: integer
        minimum: 0
  ...
패턴을 수정한 후 코드를 다시 생성하세요.
yarn run generate
방금 생성된 코드는 다음과 같은 내용을 추가할 것이라고 생각합니다.
src/api/generate.tsx
...

export interface GetUserPathParams {
  /**
   * id
   */
  id: number
}

export type GetUserProps = Omit<GetProps<User, unknown, void, GetUserPathParams>, "path"> & GetUserPathParams;

/**
 * get user
 */
export const GetUser = ({id, ...props}: GetUserProps) => (
  <Get<User, unknown, void, GetUserPathParams>
    path={`/users/${id}`}
    
    {...props}
  />
);

export type UseGetUserProps = Omit<UseGetProps<User, unknown, void, GetUserPathParams>, "path"> & GetUserPathParams;

/**
 * get user
 */
export const useGetUser = ({id, ...props}: UseGetUserProps) => useGet<User, unknown, void, GetUserPathParams>((paramsInPath: GetUserPathParams) => `/users/${paramsInPath.id}`, {  pathParams: { id }, ...props });
...
그럼, 제가 방송을 주문할게요.
src/App.tsx
import React from 'react'
import { useGetUser } from './api/generate'

export const App = () => {
  const { data, loading, error } = useGetUser({
    id: 2, // ここでidを入れる
  })

  if (loading) return <div>loading</div>
  if (error) return <div>{error}</div>
  if (!data) return <div>ユーザーが見つかりません</div>

  return (
    <div>
      <div>{data.id}</div>
      <div>{data.name}</div>
      <div>{data.email || 'none'}</div>
    </div>
  )
}
URL 매개 변수와 질의 매개 변수는 연결 옵션으로 지정됩니다.
그럼 확인해 보시죠.
Get localhost:8080/users/{id} 요청 받았네!

body 사용

localhost:8080/users/2사용자의 단점을 만드는 데 json을 요청한다고 가정하십시오.
schema.yml
...
paths:
  ...
  /users:
    ...
    post:
      description: create user
      operationId: create user
      responses:
        200:
          $ref: "#/components/schemas/user"
      requestBody:
        $ref: "#/components/requestBodies/createUser"
components:
  ...
  requestBodies:
    createUser:
      description: create user
      content:
        application/json:
          schema:
            type: object
            properties:
              name:
                type: string
              email:
                type: string
src/App.tsx
import React from 'react'
import { useCreateUser } from './api/generate'

export const App = () => {
  const { mutate, loading, error } = useCreateUser({
    onMutate: (_, res) => {
      // mutateが呼ばれた後に呼ばれる
      window.location.href = `http://localhost:3000/users/${res.id}`
    },
  })

  if (loading) return <div>loading</div>
  if (error) return <div>{error}</div>

  return (
    <div>
      <button
        onClick={() => {
          // mutateに `components/requestBodies/createUser` の情報を渡す
          mutate({ name: 'Alice', email: '[email protected]' })
        }}
      >
        create
      </button>
    </div>
  )
}
mutation의 경우 생성된 연결고리는 Post localhost:8080/users라는 함수가 있다.
이 함수를 호출해서 요청합니다.반대로 부르기 전에는 팟캐스트가 되지 않으니 주의하세요.
또한 연결 옵션mutate에 등록된 함수는 호출onMutate 후 호출되기 때문에 자원을 만든 후 상세한 화면으로 옮기기가 편리합니다.

외부 서비스에도 사용하고 싶어요.


본사의 백엔드 이외의 경우restful-react를 사용할 수 있습니다.
그러나 이 경우 코드를 생성할 수 없으므로 URL 요청을 직접 지정할 수 있습니다.
import React from 'react'
import { useGet, useMutate } from 'restful-react'

export const App = () => {
  const { data, loading, error } = useGet({
    path: 'https://example.com/foo/1',
  })
  const { mutate, loading, error } = useMutate({
    path: 'https://example.com/foo/1',
    verb: 'DELETE',
  })

신경 쓰이는 곳


union에서 enum 생성


왜 그런지 모르겠지만 좀 불편해요. 이렇게 쓰고 싶은데 엔음보다 유니언을 더 사용하고 싶다는 것 같아요.대충 그런 거 아닐까요?
참조↓
https://www.kabuku.co.jp/developers/good-bye-typescript-enum
생성된 코드도 봐.
schema.yml
  schemas:
    user:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
        role:
          type: string
          enum: [read, write] # unionになる
      required:
        - id
        - name
src/api/generate.tsx
export interface User {
  id: number;
  name: string;
  email?: string;
  role?: "read" | "write"; // enumではない
}

최후


어때?설명 안 한 옵션이 몇 개 더 있는데 여기까지만 정보가 있으면 한 번 개발할 수 있지 않나요?
처음에도 썼지만 실제로 제품에서 사용하기 때문에 백엔드와 대화를 하는 부분에서 빠르게 개발할 수 있습니다.
여러분도 꼭 해보세요!

좋은 웹페이지 즐겨찾기