-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Remountable APIs, allows to re-mounting all APIs #1803
Conversation
Creates a new module that can replace a Grape::API in most cases which allows APIs to be re-mounted
Fixes all remaining issues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! This looks great. Minor changes in text and what not please?
@namusyaka Can I have a second pair of eyes when you have a chance?
README.md
Outdated
You can mount the same endpoints in two different locations | ||
|
||
```ruby | ||
class Voting::API < Grape::GrapeAPI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grape::API
README.md
Outdated
end | ||
|
||
class Post::API < Grape::API | ||
mount Voting::API, with: {votable: 'posts'} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rubocop, add spaces between { votable: 'posts' }
.
spec/grape/remountable_api_spec.rb
Outdated
root_api | ||
end | ||
|
||
describe 'mounted RemountableAPI' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We no longer have RemountableAPI.
Other than our own fear, uncertainty and doubt, what are the downsides? Specs pass. We trust the specs. I will do a thorough code review. In the meantime do consider if any parts of the remountable implementation can be simplified by moving them into the api instance class itself. |
lib/grape/api_instance.rb
Outdated
module Grape | ||
# The API Instance class, is the engine behind Grape::API. Each class that inherits | ||
# from this will represent a different API | ||
class APIInstance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this be better called Grape::API::Instance
? Or Grape::SomethingSomething::API
(to match how we have Grape::DSL::API
)? Just thinking out loud, no strong feelings.
The naming could be important because if someone is having trouble with the new Grape::API
they could just inherit from Grape::API::Instance
, making the diff prettier ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy with that naming. Regarding the solution if someone's having trouble: Should I add an entry that says something among those lines in updating.md
?
lib/grape/api_instance.rb
Outdated
require 'grape/router' | ||
|
||
module Grape | ||
# The API Instance class, is the engine behind Grape::API. Each class that inherits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.. represent a different API instance?
lib/grape/dsl/routing.rb
Outdated
@@ -77,9 +77,12 @@ def do_not_route_options! | |||
namespace_inheritable(:do_not_route_options, true) | |||
end | |||
|
|||
def mount(mounts) | |||
def mount(mounts, with: {}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we use named parameters elsewhere. I know we no longer support older Rubies, but if we don't maybe make this consistent as opts = {}
and opts[:with] || {}
?
lib/grape/dsl/routing.rb
Outdated
mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair) | ||
mounts.each_pair do |app, path| | ||
if app.respond_to?(:mount_instance) | ||
return mount(app.mount_instance(configuration: with) => path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This return seems odd, can you explain? What if we have more mounts
? I think it should be a if ... else
for whatever follows?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the point of this return is not to execute the rest of the code as part of a Grape::API, only as part of a Grape::API::Instance. However, I do agree that return is the wrong approach, I just need to call next.
I'm surprised no test complained. Perhaps we don't have test coverage for mounting multiple apps, path on a single call?
Can you help me write a failing spec to make sure I better understand what the use case of this each_pair
?
Do we support something like:
mount(API1 => '/api_1', API2 => '/api_2'})
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're definitely missing tests.
I didn't know that we support this kind of mounting, but it looks like! Thanks for looking into it.
spec/grape/remountable_api_spec.rb
Outdated
@@ -0,0 +1,85 @@ | |||
require 'spec_helper' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More naming, this is just about remounting, so maybe api_remount_spec.rb
? NBD
No good reason, it's mainly because this is my first contribution to Grape, and due to the potential impact I wanted to avoid modifying the core behaviour so drastically. However, if you are happy with giving it a large look, I'm happy with implementing and supporting this changes. |
lib/grape/dsl/routing.rb
Outdated
mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair) | ||
mounts.each_pair do |app, path| | ||
if app.respond_to?(:mount_instance) | ||
return mount(app.mount_instance(configuration: opts[:with] || {}) => path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return issue is still not addressed, I still need a failing spec to see whether next
is appropiate, or whether this is better handled by a refactor
Also waiting on what you think we should do on the updating (as technically no change is required, but might be helpful to have information explaining how to fallback) |
What could go wrong :)
Yes, go for it. |
You should write a paragraph in UPGRADING. |
Fixes routing to get specs working
Done. The only point is that I've added the upgrading to Let me know anything else you need to get this over the line 😄 |
By trying it out on a big project, I've faced a bunch of breaking issues with no easy solution
I'm back to the drawing board, and adding specs to represent these issues later today |
So. After a lot of investigation, issues were rooted in 2 main causes. After fixing these 2 things, I've got my project back working. I'm waiting on your thoughts and what's next then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should open an issue in Grape::Swagger related to this, we'll want a proper fix there before we release Grape 1.2 with this change since that gem is very popular. Maybe you can attempt it too? ;)
README.md
Outdated
@@ -366,6 +368,59 @@ class Twitter::API < Grape::API | |||
end | |||
``` | |||
|
|||
## Remounting | |||
|
|||
You can mount the same endpoints in two different locations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick, we have periods at the end of sentences ;)
README.md
Outdated
end | ||
``` | ||
|
||
Assuming that the post and comment endpoints are mounted in `/posts` and `/comments`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
UPGRADING.md
Outdated
@@ -3,6 +3,15 @@ Upgrading Grape | |||
|
|||
### Upgrading to >= 1.1.1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably 1.2, lets increment this everywhere as part of this PR?
To summarize where we are:
|
Bumped up the version, and opened this PR on grape-swagger: ruby-grape/grape-swagger#717 that had green specs locally (when changing the gemfile to point to the right branch) |
I've managed to address the auto-loading issues, currently on the project I'm working on upgrading to this branch + upgrading swagger was done seamlessly with no failing specs, nor code-changes required. I've updated the grape-swagger PR addressing the requested changes. I'm still waiting for the second reviewer to take a look. Let me know if there's anything else I can do |
LGTM, I'll wait on someone else to comment (@namusyaka if you have a moment?) otherwise will merge in a few. |
Sorry, I overlooked this PR. I'll review the code & design this weekend. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, nice work!
I merged this. @myxoh would you like to join the co-maintainers group and get this to release? If yes what's your rubygems email? (feel free to send it over to dblock[at]dblock[dot]org if you prefer) |
Hi @dblock I've wrote you an e-mail from myxoh10[at]gmail[dot]com |
Addresses this feature request: #570
A lot of times (specially when using versioning) we want to re-mount an endpoint in a different namespace, perhaps with some tiny bit of different configuration each time.
On our project, for example, we have a massive API using Grape, and while we want to introduce versioning we don't want to:
1- Have to copy & paste the whole project (nor re-write the whole project at once),
2- Have to re-write our project to use one of the proposed meta-programming approaches.