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
Related
this question has been posed in many flavours, but no one fits my needs.
I'm working on a partially complete Razor project; the original developer has left our office, and he wasn't much concerned about securing password fields, as he left all of them in clear.
These passowrd fields authorize several aspects (Ftp primary and secondary access, Ftp on AS400 and mail sending), so nothing related with login/submit forms. When I changed these fields from text to password, they revert to blank fields, regardless the content of the View Model, and this should be the correct behaviour, as per the numerous answers I've seen googlin around.
My problem is this: the user needs to know at least if a password has been configured (seeing a string of * or any other mask character the browser use), so I need to show him that value to let him know if the service is configured, and the best would be to let him also reveal the password to check if it's correct. The option to not update the particular field in the DB if it's left blank is not an option.
This site works only on Intranet, so there is no concern about hackers monitoring the connection or similar.
I've tried all (I think) the possible combinations, including building the input element manually through html, using the #Html.TextFor and #Html.PasswordFor helpers, decorating the corrisponding member in the view model with [DataType(DataType.Password)]. The data is binded when the page is loaded, so no ajax calls help me retrieving data.
I'm relatively new to Razor, as my last two projects are entirely in PHP.
Thanks for any suggestions.
Ok, no other solution found than issuing an ajax call to a dedicated HttpGet controller method to retrieve only the password fiels, then populating the dedicated fields when the controller returns the object containing all the password I need.
[I mention the sources I've looked at below]
I am designing an API and I found over and over again that warnings would be helpful, these were the 3 most common use cases:
To convey that a non-critical issue occurred when doing a POST:
(For example, data not matching some validation was ignored and the
resource was created anyway)
To convey that a side-effect occurred: (For example, an associated resource that was valid yesterday, is now expired and was removed - the main resource however is still valid)
To convey that an action was already performed: (For example, when POSTing payment data on an item that has already been paid for)
In all 3 instances the response to the verb is succesful, the relevant response is giving back the resource (in case 1 the resource was created, in case 2 the resource is still there, in case 3 the resource is now paid for)
In all 3 instances I feel like I should be informing the Client but I could not find the standard way of doing this.
Adding the response as part of the body would require me changing the resource model, which is something I'd rather avoid
A standarized "_warnings" key that is not part of the model per se is something I'm partial about (but I haven't seen implementations of it)
Ideally, I feel the information should be part of the headers, but the only similar approach I found was the Warnings headers which is deprecated (see below).
Things I've looked at:
Previous (relevant) question: https://softwareengineering.stackexchange.com/questions/315556/warnings-in-a-rest-api-as-not-critical-errors
Reason why is not 100% relevant: The question is focusing on the appropriate status code, and weather it should be doing warnings at all as opposed to focusing on the resources themselves and where to put the body
Standard warning header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Warning
Reason why is not relevant Header has behaviour associated with it (caches), and is on the verge of changing (has been deprecated)
I'm making a web app where users can create pages, edit them, and delete them. In developing the prototype, I have a user access a route such as:
localhost:8000/mypage/1
The "1" in the URL refers to the ID in the database, so that the controller can fetch the appropriate associated data and populate the page accordingly.
The obvious problem here is that a user can plug in any number to that URL and edit someone else's page.
One obvious fix would be to add logic that checks whether or not page '1' belongs to the Auth::user(). But this would be an if statement that I have to add to every controller that carries out such function.
When I think about other sites, they never have ID's in the URL, or if they do, they look 'encrypted' in some form. What is the best practice for changing an ID into some uninterpretable string that I frequently see done on other websites?
Thank you for any help.
why don't you just use a middleware that check if the route can be acceded by the user? then you can call it with
$this->middleware('middlewareName');
in the controller that you need it or even in the web.php if you want a whole set of routes protected
I'd like to have a list of just the current titles for all questions in one of the smaller (less than 10,000 questions) stackexchange site. I tried the interactive utility here: https://api.stackexchange.com/docs/questions and it both reports the result as a json at the bottom, and produces the requesting url at the top. For example:
https://api.stackexchange.com/2.2/questions?order=desc&sort=activity&tagged=apples&site=cooking
returns this JSON in my browser:
{"items":[{"tags":["apples","crumble"],"owner":{ ...
...
...],"has_more":true,"quota_max":300,"quota_remaining":252}
What is quota? It was 10,000 on one search on one site, but suddenly it's only 300 here.
I won't be doing this very often, what I'd like is the quickest way to edit that (or similar of course) url so I can get a list of all of the titles on a small site. I don't understand how to use paging, and I don't need any of the other fields. I don't care if I get them, but I'm thinking if I exclude them I can have more at once.
If I need to script it, python (2.7) is my preferred (only) language.
quota_max is the number of requests your application is allowed per day. 300 is the default for an unregistered application. This used to be mentioned directly on the page describing throttles, but seems to have been removed. Here is historical information describing the default.
To increase this to 10,000, you need to register an application and then authenticate by passing an access token in your script.
To get all titles on a site, you can use a Python library to help:
StackAPI. The answer below will use this library. DISCLAIMER: I wrote this library
Py-StackExchange
SEAPI
StackPy
Assuming you have registered your application and authenticated we can proceed.
First, install StackAPI (documentation):
pip install stackapi
This code will then grab the 10,000 most recent questions (max_pages * page_size) for the site hardwarerecs. Each page costs you one API hit, so the more items per page, the few API calls.
from stackapi import StackAPI
SITE = StackAPI('hardwarerecs')
SITE.page_size = 100
SITE.max_pages = 100
# Filter to only get question title and link
filter = '!BHMIbze0EQ*ved8LyoO6rNjkuLgHPR'
questions = SITE.fetch('questions', filter=filter)
In the questions variable is a dictionary that looks very similar to the API output, except that the library did all the paging for you. Your data is in questions['data'] and, in this case, contains a list of dictionaries that look like this:
[
...
{u'link': u'http://hardwarerecs.stackexchange.com/questions/29/sound-board-to-replace-a-gl2200-in-a-house-of-worship-foh-setting',
u'title': u'Sound board to replace a GL2200 in a house-of-worship FOH setting?'},
{ u'link': u'http://hardwarerecs.stackexchange.com/questions/31/passive-gps-tracker-logger',
u'title': u'Passive GPS tracker/logger'}
...
]
This result set is limited to only the title and the link because of the filter we applied. You can find the appropriate filter by adjusting what fields you want in the web UI and copying the filter field.
The hardwarerecs parameter that is passed when creating the SITE parameter is the first part of the site's domain URL. Alternatively, you can find it by looking at the api_site_parameter for your site when looking at the /sites end point.
I'm really struggling to wrap my head around some of this stuff. Let me give an example of where I'm struggling.
I'm using Linq-2-Sql as the DAL for my app and the IRepository pattern used in the MVC Storefront sample app from Rob Conery.
In my domain I have a Customer Model which has a collection of Address Models. In my UI there is a button which allows the user to add a new address to the customer. This opens up an address editor which let's them fill in all the information.
What happens next? Does the address get saved to the database, then added to the list in my customer object? Does it just get added to the list but not updated until the Customer object get's saved? What if the user wants to delete an address? Do I delete the address in the database and then remove it from the list? Or do they just make all the deletes/adds they want and I dump everything from the database everytime and update it with whatever is in the Customer.Addresses collection? What's the right flow here?
Should the collection of addresses only get updated via the Repository by calling something like this:
public void AddAddressToCustomer(Customer c, Address a)
{
//validate and save address to db
//add the newly saved address to the Customer Object
}
Help...
DDD is an area where I have a lot of interest but but very little experience so please treat my suggestions cautiously. I only offer them because of the absence of other, more authoritative, answers.
In 'the book' by Eric Evans address is given as an example of something that should typically be treated as a Value Object rather than as an Entity. So I believe the Add method would belong to the Customer:
customer.Add(address);
There would be a Customer Repository (but not one for addresses). This might be used like this:
customerRepository.Update(customer);
The intentional affect of this is that all the difficult questions you ask about how this is then implemented at the DB layer are not the concern of the domain objects (i.e. the customer object). I'm afraid I can't help beyond that point either.
Sounds like you don't know the context of your domain as well as you need to. Ask some more questions and get a better user story. Potentially any of your proposed scenarios may meet the business need, depending on what it is. When you understand the need then I believe this issue will iron itself out.
it depends had a great start on the answer. Once you add the address to the customer and save the customer using:
customer.Add(address);
customerRepository.Update(customer);
Your repository would then map your customer and address domain layer entities to LINQ to SQL. This will likely involve creating a new DataContext object, getting the related LINQ to SQL entities (or creating new ones) and then mapping the domain layer entities to your LINQ to SQL entities.
var context = new MyDataContext();
var linqCustomer = MapCustomerToLinqCustomer(context, customer);
var linqAddress = MapAddressToLinqAddress(context, customer.Addresses.First());
context.SubmitChanges();
You could also use DataMapper classes for mapping, but the MapXYZ methods more closely follow Rob Conery's example. If you need more help with the MapXYZ methods, let me know.