Best(Standard) practice to send multiple parameters to REST get resource - Spring
What's the best practice to send multiple parameters on a REST GET resource call. Normally we can call GET call with path param &/ query. what is the best practice on how to achieve this(second and third).
Ex: /user/{username}/locaction} - Its a standard way
2. /user/{username}/{locaction}/{mobile_umber} - is it a standard way?
3. /user/{username}/{locaction}/{mobile_umber}/{age} - is it a standard way?
In terms of URLs, params tend to be more like RPC where you're invoking a function, e.g.:
/user?username=123
which is more like a traditional RPC call:
Object user = GetUsername(123);
REST represents a state of a resource which can be made up of many "states". Core information such as personal info, where 123 is the username:
/user/123 -> {"name":"Joe Bloggs"}
some aspects of the state of the user could change over time:
/user/123/location -> {"username":"123",lat:123456,lon:54568}
aspects of the user that are unlikely to change rapidly could be included in the core info /user/123 or if they're unlikely to be needed by a client, they can be requested separately:
/user/123/mobile -> {"username":"123",mobile:"345345"}
A User has a location and a User has a mobile and a User has an age. A location doesn't have a mobile or age so those aspects would never come under /user/location. They would come under the URL that represents the object that does have them:
/user/123/age -> {"username":"123", "age":100}
A location can have an accuracy which can either be requested separately:
/user/123/location/accuracy {"accuracy":"-1"}
or more likely included in the response to /user/123/location.
So the REST structure in this case mirrors the object hierarchy, the has parts.
The REST structure could also mirror the business structure:
/user/account
/user/contactinfo
/user/location
it just depends how you want to expose the data that represents a User and their states.
Related
I have a application hosted on some site say "www.myapp.com" which makes a request to another application(say compute_app) hosted somewhere else by passing few parameters and then the compute_app does some computation and returns the data back to primary app.
Say I need to implement two operations : Addition and Decrement in compute_app.
Addition : This operation would need say 2 numbers and output is 1 number
Decrement : This operation needs only 1 number as input and result is the decremented number by some constant value
Let's assume compute_app is hosted at "www.heroku.com/compute_app"
Now basically I need to pass a string "add/dec" along with 2/1 numbers from "www.myapp.com" to "www.heroku.com/compute_app" which does the computation and the result is returned back to "www.myapp.com"
How should I go about designing this by making USE of GET/POST Requests.
The example that I took here is figurative.
Basically I am in need of doing REST API calls from my "myapp" to a externally hosted app (compute app- which does some data pre-processing) and then it actually makes the REST call to Servers serving LIVE data.
So control flow is like:
myapp(raw data)---->compute_app(pre-processing & make call to REST servers) .
Now Rest Servers------>return JSON response to compute_app(it again does pre-processing) and then--->return data to myapp.
myapp = ChatBot
compute_app= 3rd party app for writing Java/PHP code for preprocessing bcoz the framework doesn't allow me to write any scripting code.
I have a single client application - Angular JS frontend and a Rails API backend with a MySQL DB. I'm trying to convert the application into a single schema multi tenant application. I've done a lot of reading and:
I do not want to use a gem if possible - Apartment, which is multiple schemas and uses Postgres doesn't fit the bill, and act_as_tenant seems to use Thread.current to identify the tenant which I do not want to do.
I have read that default_scope should not be used as well, for a host of reasons I won't get into here.
I'm passing a tenant token in the request header from the frontend to the Rails backend, and using the tenant token I identify the tenant in my ApplicationController. I'm now figuring out the best way to both read and write data so that is associated with the tenant that made the request.
Having ruled out the options above, the only option I can see is to go into all of my controller methods and update them wherever data is being written and read. I would much rather apply some sort of callback to each of my Models, so that the tenant id is always written when data is being written and the tenant id is always used as a filter whenever data is being read.
Given that I cannot access the tenant token in the models, I am not sure how to proceed with this other than updating all my controller methods, which would be an arduous and mistake prone process.
Thanks in advance!
Not using default_scope is a good idea - it behaves as sort of a black box and can wreck havoc down the line especially if you ever do anything with paranoid deletion.
One way to do what you asked is to use thread_mattr_accessor. You can define the tenant_id token at the beginning of the web request, and then access it through the class attribute for the duration of the web request. This creates a thread-safe attributes accessor on your tenant model.
In your controller you can detect the tenant for the current request (using subdomain or token) and set the Token.current_id variable. This variable will be available for the duration of the request. Note that it will not automatically be available for any background jobs or other processes because the variable is set inside the current thread.
This method is demonstrated using scopes in this RailsCast, but you don't have to use scopes. You can set a helper method like current_tenant and then explicitly scope all your queries like current_tenant.posts.
# models/tenant.rb
class Tenant < ApplicationRecord
thread_cattr_accessor :current_id
# ...
end
# controllers/application_controller.rb
class ApplicationController < ActionController::Base
around_action :scope_current_tenant
private def scope_current_tenant
Tenant.current_id = current_tenant.id
yield
ensure
Tenant.current_id = nil
end
def current_tenant
#current_tenant ||= Tenant.find_by_token! params[:token]
end
helper_method :current_tenant
end
I'm building an application that stores files into the FIWARE Object Storage. I don't quite understand what is the correct way of storing files into the storage.
The code python code snippet below taken from the Object Storage - User and Programmers Guide shows 2 ways of doing it:
def store_text(token, auth, container_name, object_name, object_text):
headers = {"X-Auth-Token": token}
# 1. version
#body = '{"mimetype":"text/plain", "metadata":{}, "value" : "' + object_text + '"}'
# 2. version
body = object_text
url = auth + "/" + container_name + "/" + object_name
return swift_request('PUT', url, headers, body)
The 1. version confuses me, because when I first looked at the only Node.js module (repo: fiware-object-storage) that works with Object Storage, it seemed to use 1. version. As the module was making calls to the old (v.1.1) API version instead of the presumably newest (v.2.0), referencing to the python example, not sure if that is an outdated version of doing it or not.
As I played more with the module, realised it didn't work and the code for it was a total mess. So I forked the project and quickly understood that I will need rewrite it form the ground up, taking the above mention python example from the usage guide as an reference. Link to my repo.
As of writing this the only methods that aren't implement is the object storage (PUT) and object fetching (GET).
Had some addition questions about the Object Storage which I sent to fiware-lab-help#lists.fiware.org, but haven't heard anything back so asking them here.
Haven't got much experience with writing API libraries. Should I need to worry about auth token expiring? I presume it is not needed to make a new authentication, every time we interact with storage. The authentication should happen once when server is starting-up (we create a instance) and it internally keeps it. Should I implement some kind of mechanism that refreshes the token?
Does the tenant id change? From the quote below is presume that getting a tenant I just a one time deal, then later you can use it in the config to make less authentication calls.
A valid token is required to access an object store. This section
describes how to get a valid token assuming an identity management
system compatible with OpenStack Keystone is being used. If the
username, password and tenant details are known, only step 3 is
required. source
During the authentication when fetching tenants how should I select the "right" one? For now i'm just taking the first one similar as the example code does.
Is it true that a object storage container belongs to only a single region?
Use only what you call version 2. Ignore your version 1. It is commented out in the example. It should be removed from the documentation.
(1) The token will be valid for some period of time. This could be an hour or a day, depending on the setup. This period of time should be specified in the token that is returned by the authentication service. The token needs to be periodically refreshed.
(2) The tenant id does not change.
(3) Typically only one tenant id is returned. It is possible, however, that you were assigned more than one id, in which case you have to pick which one you are currently using. Containers typically belong to a single tenant and are not shared between tenants.
(4) Containers are typically limited to a single region. This may change in the future when multi-region support for a container is added to Swift.
Solved my troubles and created the NPM module that works with the FIWARE Object Storage: https://github.com/renarsvilnis/fiware-object-storage-ge
My http api uses JSON to pass parameters, it looks like:
{
param1: xxx
param2: xxx
param3: xxx
}
However, my system is a plugin system that each plugin needs to have its own parameters in the JSON body and all plugins will cooperate with each other to produce final result.
for example, let's say the api is
CreateACar {
name: xxx
description: xxx
model: xxxx
}
the base api has three fields for basic meta data. And the system has plugins like:
CarColorPlugin: needs parameters as
{
doorColor: xxx
roofColor: xxx
decoratorColor: xxx
}
TirePlugin: needs parameters as
{
tireSize: xxx
tireBrand: xxx
}
WindShieldPlugin: needs parameters as
{
brand: xxx
needRearWindShield: true or false
}
you can imagine this kind of plugins as many as possible. Now the problem is all plugins need api CreateACar to carry their information and sometimes later a new plugin may join the system so CreateACar must be extensible for future needs.
Now I am considering to put a map in JSON body and passing api CreateACar to all plugins so they can fetch parameters by themselves.
However, this design looks a little ugly to me. I have been researching for a while, the projects having beautiful api usually have limited business domain. For projects having broad unanticipated business domain usually use extensible data structure like XML in API body, however, all these API I have seen so far are mess, especially these without good documentation.
Yes - presumably many of your requests will ask for one car, not all of them, though.
Here's my overall design suggestion:
Use the Java SPI system to handle your plugins. Define a plugin interface that includes a method to identify the plugin's key ("color", "wipers", and so on) and one that takes a Map and returns a plugin data object. Collect all of the implementations in a Map<String,Plugin>.
Write a getPlugins() method on your Car class that does not have a backing field but instead collates the information from all of the plugins applied to the Car in a nested Map.
Write a setPlugins() method that takes the nested map, iterates over the keys, looks up the appropriate factory plugin by name, and rehydrates the plugin data object from the JSON object data.
I am currently adding a REST API over http to an online service and I am confronted with a very simple problem for which I cannot find an answer that satisfies me:
I have mainly 2 resources: 'user' and 'reports', as you would have guessed reports are associated to users (to one and only one, = foreign key in my db)
Anyway I have this url mapping for GET :
mywebsite/api/users/{id} : returns a user and related information, or a list of users if id is not present
mywebsite/api/report/{id} : returns a report and related information, or a list of reports if id is not present
Now I would like to get the reports for a specific user, my way of doing it now is to add an optional parameter to the GET method for reports: ?username={username} and if it is present, I am filtering the results to return only the reports for this user.
I can't help but think something is wrong... if I start doing things like this I will have my methods handling GET full of if/else looking for missing parameters...
Other solutions I I thought of are:
incorporate the reports in the resulting GET on mywebsite/api/users/{id} but I have many many reports so in the end it will become really bad...
map another url just for this function, but it just doesn't feel right...
I am just getting the grips of this REST thing, I like the concept but a little explanation on this matter would really help me understand it better.
Thanks
Edit:
It seems I have hit a common problem in the REST world, I have tied my resources to a model. If you tie a resource to a model you end up having trouble with aggregate attributes.
Some guy describes this error here http://jacobian.org/writing/rest-worst-practices/ but I have yet to understand how to manage that as he said...
fyi I am using django/piston but this question should be answerable regardless of any language.
I can't help but think something is wrong...
The only thing you're doing wrong is thinking that your URI structure makes your application more or less RESTful. The original REST literature never says that query strings are bad. People tend to get hung up on URI structure and seem to think that your URIs must be structured a certain way to be considered RESTful. There is nothing wrong with using ?username=<username>. A URI is just an ID (though some can be more human friendly than others).
Bottom line: don't get hung up on how your URIs look. There are much more important things to focus on (promoting hyperlinking/hypermedia, sticking to a uniform interface - typically HTTP, cacheability, etc.).
This may be a big of a digression but, as for your comment about the coupling of resources to models, you're still okay. If you do go the /reports/ID/user route, just think of 'user' as a relationship name on your reports model. Surely your model defines the relationship between a report and a user. You can just parse the last part of your URI so that it matches the name of this relationship. In the case of one to one relationship like you describe its always a good idea to also set the Content-Location header to match the canonical URI of the user.
For example. Say report 123 belongs to user 1. You now have two ways of referring this user:
http://example.com/reports/123/user
http://example.com/user/1
For the first URI, it would also be a good idea to set Content-Location: http://example.com/user/1 header
Here's how I would implement this:
mywebsite/api/users : returns a list of users
mywebsite/api/users/{id} : returns a user and related information if user exists, otherwise 404
mywebsite/api/users/{id}/reports : returns reports for a specific user if exists, otherwise 404
mywebsite/api/users/{id}/reports/{id} : returns specific report for a specific user if exists, otherwise 404
mywebsite/api/reports : returns a list of reports
mywebsite/api/reports/{id} : returns a report and related information if exists, otherwise 404
HTH,
-aj