I'm trying to write up an API and struggling to figure out a nice way of adding custom actions to a resource. For example, in my User resource I want to have the actions enabled and disable, but within the usual blueprint grouping I can't add these under a group:
## User [/users/{id}]
### Update a User [PATCH]
...
### Delete a User [DELETE]
...
### Disable a User [PATCH]
....
Here, the Disable a User and Update a User both point to the same URL which isn't what I want. I want these to produce the URLs /users/{id} and /users/{id}/disable respectively.
Looking through other API source, others have done it without using named resources, which would give:
## /users/{id}
### Update a User [PATCH]
...
### Delete a User [DELETE]
...
## /users/{id}/disable
### Disable a User [PATCH]
...
Whilst I can use this approach, I'd prefer to use the first approach as it's cleaner when it gets rendered by most blueprinting tools.
Is there a way of having custom actions using the first approach, or does anyone else have a cleaner way of implementing the same kind of thing
In this example, because there are two different URLs, you actually will end up with two separate resources. One resource is a User resource, while the other is a Disable User resource. To organize these in your API Blueprint, you can group these resources together with a Resource Group.
# Group User Resources
## User [/users/{id}]
### Update a User [PATCH]
...
### Delete a User [DELETE]
...
## Disable User [/users/{id}/disable]
### Disable User [PATCH]
...
This allows you to have separate actions on separate URLs while keeping them tied together in your documentation.
Related
Specifically, can SCIM be used to add Users to pre-existing (non SCIM-created) groups? We need to provision users via SCIM, but then add them to Groups created manually in the site (a .Net application).
As I understand it, it can't be done like this. Group Update requests (i.e. PATCH requests) seem to require the "id" attribute as the unique identifier for the group, and this "id" seems to be only generated in SCIM Create Requests. So if a Resource (Group / User) wasn't originally created via SCIM, SCIM can't update/replace/delete it. Is that correct?
e.g. PATCH /Groups/acbf3ae7-8463-4692-b4fd-9b4da3f908ce
I thought about a workaround convention, such as using "user:1234" and "group:1234" as the "id" attribute format (i.e. [resource type]:[internal type-specific ID]), and then any User or Group can be specified by "id", even if it wasn't created via SCIM. But that seems pretty hacky.
Is there a better way of doing this? Many thanks for any help, very new to SCIM!
Yes, SCIM can be used to manage "brownfield" scenarios where existing non-SCIM created objects exist.
Typically the logic flow that happens for a user object is:
GET on /users with a filter (as defined in RFC7644 3.4.2.2) using an attribute that is uniqueness constrained (such as userName, email).
If no user found matching that criteria, create a new user with POST to /users
If a user was found, it should bereturned with an id value even if it was not created via SCIM
The general logic of "Search using a friendly identifier -> create if not found/cache the id value and associated it with existing user in the other directory" is pretty simple and can be successfully used with other object types (ie: groups) as well.
I am working on a Magento 2 project and have been having trouble saving category descriptions.
In the Catalog Save controller action (Magento\Catalog\Controller\Adminhtml\Category\Save), I was logging the request parameters:
$this->getRequest()->getParams()
On most categories all of the request parameters would come through, but certain ones would completely ignore the POST parameters.
After playing around with the description value being posted, I noticed that the request would not come through when my text had an instance of the text select followed later by an instance of from.
My text was something like the following:
"We carry a selection of knives from satin to mirror finish"
I checked the modsecurity logs. It had filtering the requests, mistaking them as SQL injections.
To fix the issue, we add configuration to remove the ModSecurity rules for our specific domains with:
<LocationMatch .*>
SecRuleRemoveById 950004
</LocationMatch>
More on removing ModSecurity rules:
http://www.inmotionhosting.com/support/website/modsecurity/find-and-disable-specific-modsecurity-rules
I'm starting to build a really small API and I need to authenticate some endpoints, not all of them. I want to be able to select which endpoint to force authentication with an authenticate! method to be called in the body of the 'route'.
For example:
resource :groups do
desc 'List all groups.'
get do
authenticate!
{ groups: "list of groups v1"}
end
end
I have this working. I used a helper where I manually get the base64 encoded data from the header using: request.env["HTTP_AUTHORIZATION"]. I decode that data and check against the database if the user and secret belongs to a registered user. This is working fine, but I want to use Grape's helper to avoid all the base64 decoding etc etc:
http_basic do |username, password|
end
My idea is inside that method always return true, assign username and password to #username and #password and have a helper that grabs those variables and check against the db. All that works fine, the problem is that for routes that doesn't require authentication as the 'Authorization' header is empty the popup asking for password appears, and I want to avoid that. Is there a way to use the helper to do what I want to do??
BTW: I'm using grape mounted on rails-api
Thanks!
Ok, if I got it right you don't want the username / password box to appear, but instead decide in your code if you actually need the authentication information.
Grape itself uses the default Rack::Auth::Basic class. If you create a customized version of this class you should be able to make your assertions at the beginning of the call method and even pass any other variables to your http_basic block.
You can then add your Authentication strategy to Grape via:
# Add authorization strategy to grape and replace default http_basic
Grape::Middleware::Auth::Strategies.add(:http_basic, Your::Namespace::CustomizedBasicAuth, ->(options) { [options[:realm]] })
This way there is also no need to save the credentials in #username and #password. You could just include or reference the logic inside this authentication strategy.
Nevertheless I somehow would still prefer to split up the API into two parts as Eric already mentioned.
You can break up your Grape::API into multiple modules. Group the modules that need http_basic auth together. Group the modules that don't need http_basic auth separately
I'm just getting started with Apiary and I can't tell if this is a limitation of the product or just me not understanding what to do.
I'm documenting an API which authenticates the user as part of every request. Sometimes the authentication is part of the path (a request for the user's profile would have the user id in the path), other times just as parameters (?user_id=1&auth=secret), and for POST requests, part of the incoming body as JSON.
Also, there are 3 methods of authentication in the app. You can log in with a Facebook UID, email address, or using the unique id of the device you're using. The result is something that looks like this:
##User [/user/{facebook_uid}{?access_token}, /user/{email}{?device_id}, /users/{device_auth_id}{?device_id}]
This works fine, and displays in the API as I'd expect:
But this introduces 2 issues:
1) If I wanted to add a set of parameters shared by all authentication methods, I would need to add it to all 3 like this:
## User [/user/{facebook_uid}{?access_token, extra_thing, this_too},
/user/{email}{?device_id, extra_thing, this_too},
/users/{device_auth_id}{?device_id, extra_thing, this_too}]
This seems a bit messy, it'd be much nicer to apply shared parameters at the end of the path array so they apply to all, something like this:
## User [/user/{facebook_uid}{?access_token}, /user/{email}{?device_id}, /users/{device_auth_id}{?device_id}]{&extra_thing, this_too}
But this doesn't work. Is there a way to do this? The documentation wasn't very helpful with more complicated stuff like this.
Also, would there be a way to create some kind of template which I could apply to all my methods? In the case where the authentication is part of the path its a bit unavoidable, but for other requests it would be nice to just do something like include: authentication and have it pull the unique_id/auth combo from a defined template somewhere.
Thanks!
First, there isn't really support for having a single model with multiple resource representations. It is an unusual thing to do and is actually good food for thought.
Second, using multiple URIs in [path segment] is probably going to confuse Apiary's mock server and make it unusable.
In my opinion, I'd split this into three models: Facebook User, E-mail User and Device User, with slightly different documentation (how are they created? Can you really create all of them through api? etc. etc.)
It also depends on how you want to document this. As path segments are not validated (it would be strange to have different resources based on the type of the arguments), you can just have (and I'd personally do just that)
## User [/user/{id}{?access_token, extra_thing, this_too}]
+ Parameters
+ id (required, string, `test#example.com`)...id of the user. Can be either user's e-mail, facebook id or device id from where user was created.
As for reusable parts, this is currently being implemented with authentication being part of that.
For a user generated content website, I want to give ability to my users to restrict on who can see the content.
Domain based restriction seems like a good choice( users can embed content content on their own site).
Any samples/suggestions/known gotchas on how we should implement domain restriction on content?
Our solution is developed on asp.net mvc
The authorization scheme you would use is independent of whether you use DDD or not.
You would probably use a Role-based authorization scheme. Every item of content then comes with an Access Control List (ACL), which is basically a list of roles and their rights -- for instance, all users who are in the FoodAuthors group can modify a particular piece of content, and all users in the FoodReaders group can only read it. Users who are in neither group/role have no access to the content.
Furthermore, you can divide up your content into categories (or "channels", whatever term you prefer), and organize these categories/channels in a tree structure. Then you can put ACLs on the categories/channels rather than on the content itself. So, an article on whole foods would be put in the /Health/Food channel, for instance, and the FoodReaders group would get read access to all content in that channel.