Skip to content

Frontend Setup with OpenAPI

This document describes how to use the OpenAPI specification generated by this backend to create a type-safe frontend client.

Prerequisites

  • A working frontend project (e.g., React, Vue, Angular).
  • The backend server must be running to serve the OpenAPI specification.

Steps

  1. Install Dependencies: In your frontend project, you'll need openapi-typescript to generate the client and a fetching library like axios.

    npm install axios
    npm install -D openapi-typescript
    
  2. Add a Script to package.json: Add a script to your frontend's package.json to generate the API client. This script will fetch the spec from your running backend.

    "scripts": {
      "generate-api": "openapi-typescript http://localhost:5001/docs/json -o src/api/v1/schema.ts"
    }
    
    (Adjust the port and output path as needed.)

  3. Generate the Client: Make sure your backend server is running, then run the script:

    npm run generate-api
    

    This will create a src/api/v1/schema.ts file in your frontend project containing all the TypeScript types from your OpenAPI spec.

  4. Create an API Client: You can create a typed axios instance or wrapper to use these types.

    // src/api/v1/client.ts
    import axios from 'axios';
    import type { paths } from './schema';
    import type {
      operations,
    } from './schema';
    
    const apiClient = axios.create({
      baseURL: 'http://localhost:5001/api/v1',
    });
    
    export default apiClient;
    export type { paths, operations };
    
  5. Use the Client in a Component: Now you can import the client and types in your components to make type-safe API calls.

    // src/components/UserProfile.tsx
    import { useEffect, useState } from 'react';
    import apiClient from '../api/v1/client';
    import type { paths } from '../api/v1/schema';
    
    type User = paths['/users/{id}']['get']['responses']['200']['content']['application/json'];
    
    function UserProfile({ userId }: { userId: string }) {
      const [user, setUser] = useState<User | null>(null);
    
      useEffect(() => {
        const fetchUser = async () => {
          try {
            const response = await apiClient.get<User>(`/users/${userId}`);
            setUser(response.data);
          } catch (error) {
            console.error('Failed to fetch user', error);
          }
        };
    
        fetchUser();
      }, [userId]);
    
      if (!user) {
        return <div>Loading...</div>;
      }
    
      return (
        <div>
          <h1>{user.name}</h1>
          <p>{user.email}</p>
        </div>
      );
    }
    
    export default UserProfile;
    

This setup ensures that if you change your API, you can regenerate the client, and TypeScript will catch any breaking changes in your frontend code.