VireZee
VireZee

Reputation: 58

Displaying pure JSON format with black background in GraphQL Express React

I'm having issue of displaying the response of the API. It appears white like this 1

Which is should be similar like this 2

My code in the backend server:

main.ts

import { typeDefs, resolvers } from './src/graphql/Resolver'

AppDataSource.initialize()
const app = express()
const httpServer = http.createServer(app)
const server = new ApolloServer({
    typeDefs,
    resolvers,
    plugins: [ApolloServerPluginDrainHttpServer({ httpServer })]
});
(async () => {
    await server.start()
    app.use(
        '/gql',
        cors<cors.CorsRequest>({ origin: `http://${process.env.DOMAIN}:${process.env.CLIENT_PORT}`, credentials: true }),
        express.json(),
        cp(),
        expressMiddleware(server, {
            context: async ({ req, res }) => ({ req, res })
        })
    )
    httpServer.listen(process.env.PORT)
})()

Resolver.ts

import API from './resolver/api/Data'
import Books from './resolver/api/Books'

export const typeDefs = Schema
export const resolvers = {
    API: {
        __resolveType(obj: API) {
            if ((obj as Data).user_id) return 'Data'
            else return 'Error'
        }
    },
    Data: {
        books: Books
    },
    Query: {
        api: API
    }
}

Data.ts

const Data = async (_: null, args: { api_key: string }) => {
    try {
        const userRepo = AppDataSource.getRepository(User)
        const { api_key } = args
        const hashBuffer = Buffer.from(api_key, 'hex')
        const user = await userRepo.findOne({ where: { api_key: hashBuffer } })
        if (!user) return { message: 'Invalid API Key!'}
        return {
            user_id: user.user_id,
            email: user.email,
            username: user.username
        }
    } catch {
        throw new GraphQLError('Internal Server Error', { extensions: { code: '500' } })
    }
}
export default Data

Books.ts (the parent refers to Data)

const Books = async (parent: { user_id: number }) => {
    try {
        const bookRepo = AppDataSource.getRepository(Book)
        const books = await bookRepo.find({ where: { user_id: parent!.user_id } })
        return books.map(book => ({
            cover_i: book.cover_i,
            isbn: book.isbn,
            title: book.title,
            author_name: book.author_name
        }))
    } catch {
        throw new GraphQLError('Internal Server Error', { extensions: { code: '500' } })
    }
}
export default Books

Frontend:

App.tsx

const App: React.FC = () => {
    const { loading, data, error } = useQuery(AuthGQL)
    const dispatch = useDispatch()
    React.useEffect(() => {
        if (!loading) {
            if (data) dispatch(setUser(data.auth))
            else if (error) dispatch(setUser(null))
        }
    }, [data, error])
    return (
        <BrowserRouter>
            <main>
                <Routes>
                    <Route path="API/:hash" element={<API />} />
                </Routes>
            </main>
        </BrowserRouter>
    )
}
export default App

API.tsx

interface Book {
    cover_i: string
    isbn: string
    title: string
    author_name: string
    __typename: string
}
const API: React.FC = () => {
    const { hash } = useParams<{ hash: string }>()
    const { loading, data, error } = useQuery(APIGQL, { variables: { api_key: hash } })
    const apiState = useSelector((state: RootState) => state.API)
    const dispatch = useDispatch()
    React.useEffect(() => {
        if (!loading) {
            if (data) {
                const { __typename, books, ...api } = data.api
                dispatch(setApi({
                    ...api,
                    books: books.map(({ __typename, ...book }: Book) => book)
                }))
            }
            else if (error) { }
        }
    }, [data, error])
    return (
        <pre>{JSON.stringify(apiState, null, 2)}</pre>
    )
}
export default API

I have no idea how to displaying like that. Asking GPT forces me to use CSS style while I'm pretty sure the Open Library API doesn't use that way.

Upvotes: 0

Views: 38

Answers (2)

Gxogac
Gxogac

Reputation: 113

You can't do that with GQL since GQL need a POST request. It can't return json like that. But you can combine REST with your GQL.

main.ts

(async () => {
    await server.start()
    app.use(
        '/gql',
        cors<cors.CorsRequest>({ origin: `http://${process.env.DOMAIN}:${process.env.CLIENT_PORT}`, credentials: true }),
        express.json(),
        cp(),
        expressMiddleware(server, {
            context: async ({ req, res }) => ({ req, res })
        })
    )
    // since I saw your format URL is somewhat '/API/hash'
    app.get('/API/:hash', async (req: Request, res: Response) => {
        try {
            const userRepo = AppDataSource.getRepository(User)
            const { hash } = req.params
            const hashBuffer = Buffer.from(hash, 'hex')
            const user = await userRepo.findOne({ where: { api_key: hashBuffer } })
            if (!user) res.status(404).json({ message: 'Invalid API Key!' })
            // continue the logic
            res.status(200).json(JSON.parse(JSON.stringify('return your dict response', null, 2)))
        } catch {
        }
    }
    httpServer.listen(process.env.PORT)
})()

Upvotes: 1

remix23
remix23

Reputation: 3019

Open Library API returns raw json, which is displayed in the default font and background of your browser, usually black font over white background except when using something like a dark theme. If you want to control the display you will have to use CSS and or rendering markup for your json.

The simplest way here is to style the element you're stringifying your json into:

return (
    <pre style={{ color: 'white'; background: 'black' }}>
       {JSON.stringify(apiState, null, 2)}
    </pre>
);

If you do not want to control the display instead of querying the API in a React component, just navigate to your API endpoint.

look into useNavigate if your API accepts searchParams, otherwise you probably will need a form element

Upvotes: 1

Related Questions