Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v0.10] wildcard route ':country_id' conflicts with existing edges in path '/country/:country_id/edit' #159

Closed
vzool opened this issue Apr 6, 2018 · 11 comments
Assignees
Labels

Comments

@vzool
Copy link

vzool commented Apr 6, 2018

Hi,

I'm trying to make a "Restful Web" and I followed the documentation to do these End-Points:

  • List Countries - GET /country
  • Show Create Form - GET /country/create
  • Create Country - POST /country
  • Get Country - GET /country/:country_id
  • Show Country Edit Form - GET /country/:country_id/edit
  • Update Country - PUT /country/:country_id
  • Delete Country - DELETE /country/:country_id

But I can't make it right, here is my routes:

domains {

  localhost {

    static {
      # ..
    }

    routes {
        # ..

        index {
            # ..
        }

        country{
        
            path = "/country"
            controller = "CountryController"

            routes{

               path = "/"
               
                country_create{
                    path = "/create"
                    action = "Create"
                }
                country_store{
                    action = "Store"
                    method = "POST"
                }

                routes{
                    path = "/:country_id"
                    routes{
                        country_show{
                            action = "Show"
                        }
                        country_edit{
                            path = "/edit"
                            action = "Edit"
                        }
                        country_update{
                            method = "PUT"
                        }
                        country_delete{
                            method = "Delete"
                        }
                    }
                }
            }
        }

    } # end - routes

  } # end - localhost

} # end - domains

And here is my controller:

package controllers

import (
	"aahframework.org/aah.v0"
)

// CountryController struct application controller
type CountryController struct {
	*aah.Context
}

// Index method is country list page.
func (a *CountryController) Index() {
	a.Reply().Ok().Text("Country Index Page")
}

// Create method is a form to create new country record page.
func (a *CountryController) Create() {
	a.Reply().Ok().Text("Country Create Page")
}

// Store method is country create record.
func (a *CountryController) Store() {
	a.Reply().Ok().Text("Country Store Page")
}

// Show method is country one record page.
func (a *CountryController) Show() {
	a.Reply().Ok().Text("Country Show Page")
}

// Edit method is country edit form record page.
func (a *CountryController) Edit() {
	a.Reply().Ok().Text("Country Edit Page")
}

// Update method is country to do update record page.
func (a *CountryController) Update() {
	a.Reply().Ok().Text("Country Update Page")
}

// Delete method is country to delete record.
func (a *CountryController) Delete() {
	a.Reply().Ok().Text("Country Delete Page")
}

What I did wrong?

Thanks

@vzool vzool changed the title wildcard route ':country_id' conflicts with existing edges in path '/country/:country_id/edit' [v0.10] wildcard route ':country_id' conflicts with existing edges in path '/country/:country_id/edit' Apr 6, 2018
@vzool
Copy link
Author

vzool commented Apr 6, 2018

By the way, I did try to figured it how to be fixed and I found it in radix_tree.go and I commented lines from 245 to 248, after that the problem gone. But, there is a conflict between /country/create & /country/:country_id/edit.

I think radix_tree.go can't distinguish between 2 level and 3 level urls seperation! Is this a bug?

@jeevatkm
Copy link
Member

jeevatkm commented Apr 6, 2018

@vzool aah router tells you have problem in route definitions, those lines (245 to 248) are required not to be commented.

I will try to explain, problem is these two route definition (happening at same level; not level 2 or level 3)

  • Show Create Form - GET /country/create
  • Get Country - GET /country/:country_id

For example:

Request 1: http://localhost:8080/country/create
Request 2: http://localhost:8080/country/10001

Where it would send it to???

This is the problem router tells you. You need to thing about route URLs.

I hope it helps.


BTW, remove this line path = "/", its not required.

@jeevatkm jeevatkm self-assigned this Apr 6, 2018
@vzool
Copy link
Author

vzool commented Apr 6, 2018

@jeevatkm Aha, I see.

Request 1: should send to page that Show Create Form
Request 2: should send to page that Show one record

Ok, I will looking for a different naming to /country/create.

But, when I remove path = "/" and access /country by GET call it returns an error back:
"405 Method Not Allowed"

In fact, I felt it's a little strange to me at first time!

@jeevatkm
Copy link
Member

jeevatkm commented Apr 6, 2018

@vzool I thought to give you a suggestion.

Typically if you design Web and REST API together in one application. Following design approach works well and makes sense.

Web:

  • Show Create Form - GET /country/create
  • Show Country Edit Form - GET /country/edit

REST API (if API application itself separate project, then /api not needed): Always version your API, its good approach

  • List Countries - GET /api/v1/countries
  • Create Country - POST /api/v1/countries
  • Get Country - GET api/v1/countries/:countryId
  • Update Country - PUT /api/v1/countries/:countryId
  • Delete Country - DELETE /api/v1/countries/:countryId

Controllers package structure -

/app/controllers
                /country.go => CountryController
                /api/v1
                      /api_country.go => ApiCountryController

So routes definition would look like -

routes {
  # Web routes definition
  # You can keep this in separate file and reference it here
  # include "routes/web.conf" 
  country {
    path = "/country"
    controller = "CountryController"
    routes {
      country_create {
        action = "Create"
      }
      country_edit {
        method = "post"
        action = "Edit"
      }
    }
  }

  # API routes definition
  # You can keep this in separate file and reference it here
  # include "routes/api_v1.conf" 
  api_v1 {
    path = "/api/v1"
    routes {
      api_countries {
        path = "/countries"
        controller = "api/v1/ApiCountryController"
        action = "List"
        routes {
          api_countries_create {
            method = "post"
            action = "Create"
          }
          routes {
            path = "/:countryId"
            routes {
              api_countries_get {
                action = "Show"
              }
              api_countries_update {
                method = "put"
                action = "Update"
              }
              api_countries_delete {
                method = "delete"
                action = "Delete"
              }
            }
          } # end of "/:countryId" routes
        }
      } # end of "/countries" routes        
    }
  } # end of "/api/v1" routes
}

I hope this would give a very good start point.

@vzool
Copy link
Author

vzool commented Apr 7, 2018

@jeevatkm Thanks for your suggestions, it's helpful.

In fact, I'm trying to implement a "Pyramid Hierarchy URL" for a situation like this:

Country -> State -> City -> District -> House

or simply

Country -> City -> District

So, the routes would be something like this:

+-----------+-----------------------------------------------------------+-------------------------------------------+
| Method    | URI                                                       | Controller@Action                         |
+-----------+-----------------------------------------------------------+-------------------------------------------+
| GET|HEAD  | country                                                   | Controllers\CountryController@Index       |
| GET|HEAD  | country/create                                            | Controllers\CountryController@Create      |
| POST      | country                                                   | Controllers\CountryController@Store       |
| GET|HEAD  | country/{country}                                         | Controllers\CountryController@Show        |
| GET|HEAD  | country/{country}/edit                                    | Controllers\CountryController@Edit        |
| PUT       | country/{country}                                         | Controllers\CountryController@Update      |
| DELETE    | country/{country}                                         | Controllers\CountryController@Delete      |
+-----------+-----------------------------------------------------------+-------------------------------------------+
| GET|HEAD  | country/{country}/city                                    | Controllers\CityController@Index          |
| GET|HEAD  | country/{country}/city/create                             | Controllers\CityController@Create         |
| POST      | country/{country}/city                                    | Controllers\CityController@Store          |
| GET|HEAD  | country/{country}/city/{city}                             | Controllers\CityController@Show           |
| GET|HEAD  | country/{country}/city/{city}/edit                        | Controllers\CityController@Edit           |
| PUT       | country/{country}/city/{city}                             | Controllers\CityController@Update         |
| DELETE    | country/{country}/city/{city}                             | Controllers\CityController@Delete         |
+-----------+-----------------------------------------------------------+-------------------------------------------+
| GET|HEAD  | country/{country}/city/{city}/district                    | Controllers\DistrictController@Index      |
| GET|HEAD  | country/{country}/city/{city}/district/create             | Controllers\DistrictController@Create     |
| POST      | country/{country}/city/{city}/district                    | Controllers\DistrictController@Store      |
| GET|HEAD  | country/{country}/city/{city}/district/{district}         | Controllers\DistrictController@Show       |
| GET|HEAD  | country/{country}/city/{city}/district/{district}/edit    | Controllers\DistrictController@Edit       |
| PUT       | country/{country}/city/{city}/district/{district}         | Controllers\DistrictController@Update     |
| DELETE    | country/{country}/city/{city}/district/{district}         | Controllers\DistrictController@Delete     |
+-----------+-----------------------------------------------------------+-------------------------------------------+

But, I don't know how can I do that with current routing system! I think we need new routing system as an option to cover this area.

What do you think?

@jeevatkm
Copy link
Member

jeevatkm commented Apr 7, 2018

@vzool As far as my understanding, not only aah or with any routing library; you may not be able to achieve if you have path param or wildcard Paramlike these-

country/create
country/{country}
country/{country}/edit

So, no issues with currently routing system (FYI, aah uses radix tree implementation from this library https://github.com/julienschmidt/httprouter).

I'm always looking for a ways to improve aah to give best framework experience. If you come across any library which supports above routes structure, please let me know. Surely I will learn and adapt that feature into aah routing system.

PS: You may have to rethink your URL structure, that's why I gave you optimal URL design approach.

@vzool
Copy link
Author

vzool commented Apr 7, 2018

@jeevatkm I feel that "Pyramid Hierarchy URL" looks and behave just like "BTree", as I think Radix Tree did it too.

But, why the Method is missing here, algorithm just care about naming and forget the Method entirely!

BTY, I found an interesting library can implement this new way, it's called Bone, and I really did a testing for it here.

alt tag

Funny picture used for the library, ha ha ha

@vzool
Copy link
Author

vzool commented Apr 7, 2018

@jeevatkm While I'm testing it, it looks and behave really fast with ton of features.

@jeevatkm
Copy link
Member

jeevatkm commented Apr 7, 2018

@vzool Thank you for your finding, I have a look and get back to you 😄

@jeevatkm
Copy link
Member

jeevatkm commented Apr 7, 2018

@vzool Seems like, your input gonna make aah much more flexible on routing system with multiple routing algorithms.

I have created this issue #160 to do overhaul on aah routing system. I have scheduled it for v0.12.0 release since I'm doing considerable internal improvements (currently in-progress) and features planned for v0.11.0.

I hope this plan works for you 😄

@jeevatkm jeevatkm closed this as completed Apr 7, 2018
@vzool
Copy link
Author

vzool commented Apr 7, 2018

@jeevatkm Of course, I'm totally fine with that plan.
Let's give any idea a proper time to complete its shape into reality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants