blomqma / next-rest-framework

Type-safe, self-documenting APIs for Next.js
https://next-rest-framework.vercel.app
Other
155 stars 20 forks source link

The routes aren't being generated from the 'app' folder. #52

Closed AhsanAyaz closed 1 year ago

AhsanAyaz commented 1 year ago

It seems like the routes are still being generated from the pages/api folder in the example code as well as in my fresh nextjs codebase as well. I.e. when using the pages router, the specs are loaded and shown on the page. However, when using the app router, the specs don't create.

blomqma commented 1 year ago

Hey, did you experience this issue when running the example application of this repository locally or your own application following the example? I verified that generating the paths in the example application works as it should, generating paths from both API routes and Route Handlers, since the config options appDirPath and apiRoutesPath are both enabled. If you wish to generate the OpenAPI spec only from your Route Handlers in your app directory, then you should only use the config option appDirPath, that is also used in the example application.

adsc commented 1 year ago

I have the opposite problem, for me, using the pages router, no docs are generated. I put [[...next-rest-framework]].ts directly in pages/api folder with content from the front page, and put todos.ts from your example app (because there are typescript errors in the api code on your front page) next to it, then created a next-rest-framework/client.ts file with content as shown below. I can go to my app's /api URL, and it loads the swagger client, but it says No operations defined in spec!.

next-rest-framework/client.ts

import { NextRestFramework } from 'next-rest-framework';

export const { defineCatchAllApiRoute, defineApiRoute } = NextRestFramework({
   apiRoutesPath: 'pages/api',
   swaggerUiPath: '/api',
   openApiJsonPath: '/api/openapi.json',
   openApiYamlPath: '/api/openapi.yaml',
});

pages/api/[[...next-rest-framework]].ts

import { defineCatchAllApiRoute } from 'next-rest-framework/client';

export default defineCatchAllApiRoute();

pages/api/todos.ts

import { defineApiRoute } from 'next-rest-framework/client';
import { z } from 'zod';

export default defineApiRoute({
   GET: {
      output: [
         {
            status: 200,
            contentType: 'text/html',
            schema: z.object({
               foo: z.string(),
               bar: z.string(),
               baz: z.string(),
               qux: z.string()
            })
         }
      ],
      handler: (_req, res) => {
         res.setHeader('content-type', 'text/html');
         res.status(200).json({ foo: 'foo', bar: 'bar', baz: 'baz', qux: 'qux' });
      }
   },
   POST: {
      input: {
         contentType: 'application/json',
         body: z.object({
            foo: z.string(),
            bar: z.number()
         }),
         query: z.object({
            test: z.string()
         })
      },
      output: [
         {
            status: 201,
            contentType: 'application/json',
            schema: z.object({
               foo: z.string(),
               bar: z.number(),
               query: z.object({
                  test: z.string()
               })
            })
         }
      ],
      handler: ({ body: { foo, bar }, query: { test } }, res) => {
         res.status(201).json({ foo, bar, query: { test } });
      }
   },
   PUT: {
      input: {
         contentType: 'application/json',
         body: z.object({
            foo: z.array(
               z.object({
                  bar: z.string()
               })
            ),
            baz: z.number()
         }),
         query: z.object({
            test: z.string()
         })
      },
      output: [
         {
            status: 201,
            contentType: 'application/json',
            schema: z.object({
               foo: z.array(
                  z.object({
                     bar: z.string()
                  })
               ),
               bar: z.number(),
               query: z.object({
                  test: z.string()
               })
            })
         }
      ],
      handler: ({ body: { foo }, query: { test } }, res) => {
         res.status(201).json({ foo, bar: 0, query: { test } });
      }
   }
});
adsc commented 1 year ago

I have now installed a new test next.js project with the latest version, and in there it seems to work. So in my other project, the version might be too low? It's 13.1.6.

adsc commented 1 year ago

I have updated my other project to next 13.5.3 now, but it's still not generating any api doc for the todos.ts file. No idea why.

blomqma commented 1 year ago

@adsc I tried your example with different combinations of versions that you mentioned and I could not reproduce your specific issue, unfortunately. However, the latest version v1.1.0 addresses a couple of App Router issues pointed by https://github.com/blomqma/next-rest-framework/issues/57 so I'm kindly asking you to upgrade to the latest version v1.1.0 and try again. Happy to help if you still encounter issues with that version.

cc. @AhsanAyaz

adsc commented 1 year ago

@blomqma Thanks. I've upgraded to 1.1.0 and I still have the same problem. It works if everything is in pages/api folder, but not if it's in pages/api/public folder. Could you take a look at https://github.com/adsc/next-rest-framework-test please?

blomqma commented 1 year ago

@adsc Thanks for the reproducible example, now I get it. It looks like your apiRoutesPath config option is incorrect. This option is simply a relative path to your API routes folder, even if your SwaggerUI and OpenAPI spec files are not served from the root API routes, and it should always be either /pages/api or /src/pages/api depending on whether your code lives inside the src folder or not. So making this change to your apiRoutesPath config option addresses the issue: pages/api/public -> /pages/api. I could take an action point from this to make stricter definitions on the apiRoutesPath/appDirPath config options to prevent developers from using incorrect values for them. Closing this issue as I verified that making the change I proposed addresses the issue in your example.

adsc commented 1 year ago

Thank you. Did you also check the code of your todos.ts as specified in your README.md file here: https://github.com/blomqma/next-rest-framework#pages-router ? Because I get typescript errors when I'm trying to use it. It's different from code included in your example folders.

blomqma commented 1 year ago

Thank you. Did you also check the code of your todos.ts as specified in your README.md file here: https://github.com/blomqma/next-rest-framework#pages-router ? Because I get typescript errors when I'm trying to use it. It's different from code included in your example folders.

Thanks for noting that, the pages router examples indeed contained some old implementation logic that results into TS errors with the latest version, those have been fixed now as well.