cebe / yii2-openapi

REST API application generator for Yii2, openapi 3.0 YAML -> Yii2
MIT License
130 stars 21 forks source link

How to generate controller code with distinct method names in case of prefix in paths #84

Open SOHELAHMED7 opened 2 years ago

SOHELAHMED7 commented 2 years ago

I have use-case like below

Here the base controller generates:

    abstract public function actionDomains();

    abstract public function actionDomains($id);

Two method with same name leads to errors.

How can code generation for above end-points can be achieved?

Insolita commented 2 years ago

Seems there is no way. This route is out of json-api resource conception.

GET /domains GET /domains/{id} will return different actions

Also

GET /calendar/{calendarId}/domains GET /calendar/{calendarId}/domains/{id}
will works correct

Insolita commented 2 years ago

Or do you assume REST usage, without JsonApi? That part probably should be checked better, as well as last time jsonApi was most focused

But anyway - we need to detect and support CRUD operations (list/view/create/update/delete) and non-crud operations like /password/recovery/{token} /confirm/email/{email} /avatar/upload/{id}

SOHELAHMED7 commented 2 years ago

As of now I need to use with JSON:API.

I am using your package. It is very helpful. Generic actions fulfil my most use-cases. I am using it most to avoid custom actions.


regarding above end-points:

Calendar in not model or a DB table in my use-case as of now.

It is just a prefix.

Insolita commented 2 years ago

It is just a prefix.

So, prefixes are not supported. We expects that a resource name is a single world You can use

GET /domains GET /domains/{id}

or

GET /calendar-domains GET /calendar-domains/{id}

or

GET /calendar/domains/list GET /calendar/domains/{id} (But generated templates may be different for this way)

Insolita commented 2 years ago

If we will start supporting prefixed resource routes, GET /calendar/domains - should be pointed to DomainController or CalendarDomainController -> actionList
POST /calendar/domains - -> actionCreate GET /calendar/domains/{id} - actionView($id) PATCH /calendar/domains/{id} - actionUpdate($id) DELETE /calendar/domains/{id} - actionDelete($id)

But now POST /auth/confirm/{email} points to AuthController actionConfirm POST /password/recovery points to PasswordController actionRecovery GET /metric/visits points to MetricController actionVisists if we will start supporting prefixed resources - we can't detect differences between crud resources and standalone actions.

@cebe what you think?

cebe commented 2 years ago

JSON-API itself does not really say anything about URL design in this case. https://jsonapi.org/recommendations/#urls

if we will start supporting prefixed resources - we can't detect differences between crud resources and standalone actions.

it should probably be a configuration option to allow specifying grouping prefixes. If the API contains these prefixes a configuration could decide what to do with it. In some cases it might also make sense to generate Modules from URL prefixes.

So for example:

$urlPrefixes = [
    'calendar' => '', // drop prefix, create controller in main app
    'order' => 'order', // create controller in the order module
    'base/auth' => 'auth', // create controller in the auth module
    'auth' => 'auth/base', // create controller in the base/auth module - not sure if this case is needed (never used submodules in any application)
]
Insolita commented 2 years ago

'auth' => 'auth/base', // create controller in the base/auth module

It is not clear about the "base/auth module"

We can define 'prefix' => 'moduleName', or prefix => 'moduleName/subModuleName'

Namespace and path should be resolved from Yii::$app->getModule('moduleName')->controllerNamespace etc/

or we need explicit 'prefix' =>['path' => '@app/modules/auth/controllers/base', 'namespace' => '/app/modules/auth/base']

cebe commented 2 years ago

good point, we might need to generate the module if it does not exist so we have no idea about namespaces and paths. Need to allow making these configurable.

We could allow both, string for module name and use default assumptions about naming and path. and allow array configuration for more detailed config.

SOHELAHMED7 commented 2 years ago

I suggest to make module creation for every prefix optional.

Example:

Lets take my above calendar example.

I need calendar prefix in my path but don't want calendar Yii module in my code. Also I don't have calendar DB table. Also there is no huge feature or functionalities around calendar

I just need it as prefix.

Path /calendar/* should be handled by controller defined in main app and not in any Yii module.

Current code generation Yii2-app-api for

GET /calendar/entry/{name} will create CalendarController and actionEntry()

this is fine

CalendarController file will be present in main app and not in any module

Now coming to main question that is present in issue description.

How to generate distinct function name for case like:

GET /calendar/domains - get all domains. Domain here is model and DB table. calendar is just the prefix
GET /calendar/domains/{id} - get a domain by ID.

This should be taken care of by code generator. A thought of mine:

GET /calendar/domains => CalendarController/actionDomains GET /calendar/domains/{id} => CalendarController/actionDomainById (actionGetDomain or so...)

To achieve this I think we can use

yii\web\GroupUrlRule::$prefix

yii\web\GroupUrlRule::$routePrefix

 new GroupUrlRule([
     'prefix' => 'calendar',
     'routePrefix' => '',
     'rules' => [
         'GET domains' => 'calendar/domains',
         'GET domains/<id:\d+>' => 'calendar/domain-by-id',
         ...
     ],
 ]);
Insolita commented 2 years ago

I suggest to make module creation for every prefix optional.

Yes, module definition will be optional.
You will be able to define 'urlPrefixes' => [ 'calendar' => '' ] in yii2-openapi and 'calendar' part will be handled by main app, without modules, but about next part...

This should be taken care of by code generator. A thought of mine:

GET /calendar/domains => CalendarController/actionDomains
GET /calendar/domains/{id} => CalendarController/actionDomainById (actionGetDomain or so...)

But what by you mind should be for POST /calendar/domains,
PATCH /calendar/domains/{id} , DELETE /calendar/domains/{id}

SOHELAHMED7 commented 2 years ago

But what by you mind should be for

You mean to ask what are my thoughts about controller and action for below paths? If yes, then I think we can name it like:

POST /calendar/domains, => CalendarController -> actionAddDomain
PATCH /calendar/domains/{id}  => CalendarController -> actionUpdateDomain($id),
DELETE /calendar/domains/{id} => CalendarController -> actionDeleteDomain($id),
cebe commented 2 years ago

I don't get why these routes should not generate DomainControlller with actionList(), actionCreate(), actionUpdate()...

do you suggest do provide GroupUrlRule in config to determine generated routes, controller and action from it?