My app (Laravel/Vue) has some API endpoints like /api/price/{id} and /api/buy/{id} first endpoint gives the price of a product and second buy x quantity (passed by POST) of that product.
Prices have too much volatility (think things like cryptocurrencies), so the /price/ endpoint will do some calcs and give the realtime price. When I click the buy button on the browser it goes to the /buy/ endpoint, of course. The first thing it has to do is to calculate the real time price, just as the /price/ endpoint does, then write to the database etc.
For some reason beyond my control the endpoints are in different controllers, I have a PriceController and a BuyController, so I have several options to make this work:
I write the same code in both endpoints. Of course, I don't like a bit this solution, because of maintenance
(Which I'm currently using) Inside my BuyController I do an API call to PriceController, and yeah, sure it works, but I find it quite strange to go to the network to access something local, I don't know if it will have any performance impact under load (in development, it doesn't seem to be any)
Should I do a helper function to do all the calcs needed and use it as the price source for both /price/ and /buy/ endpoints? I feel this approach might be better. I normally don't use helpers so I can't start imagining what name to give to the helper function.
What should be the "correct" approach?
Maybe the correct way is to "unify" /price/ and /buy/ endpoints and have a function inside the resulting controller, but I don't know how many changes should I make to the rest of the app.
Probably you should write a Service and use it in both controllers (if you move your controller's logic to service even better - ), but if you are using 'calculation logic' frequently, then maybe using a helper function would be more suitable.
if you are not comfortable using services, you can also use this approach
Related
I am building a microservice that will have a management layer, and another corresponding microservice for a public api. The management layer's client will be imported into the api service as well as a few other apps. What I am wondering is what the proper way to structure the mgmt layer's calls would be. I'm using rpc.
For example, let's say the service contains Human, Dog, Food. Food has to be owned by a Human OR Dog, not both and not neither.
Now since the mgmt service will only be accessed by client and not url, would it be better to define the specs like:
POST: /humans/id/food Client call: mgmtService.createFoodForHuman(humanId, Food)
POST: /dogs/id/food Client call: mgmtService.createFoodForDog(dogId, Food)
or
POST: /food Client call: mgmtService.createFood(Food)
where the second instance of Food will require the user to pass in one of human id or dog id.
To me, the first example seems more straightforward from a code-client perspective since the methods are more defined and the second example doesn't give any info of what kind of id is needed, but I am interested if there is any thoughts on which one is best practice. Thanks!
It is actually depends, on larger scale you would want to apply the first method. Sometimes, when you works with the other teams to build a complex services, it is possible that the other teams has to fix your bug because of your absent or any case where you can't fix the bug that time, if the bug is really an urgent cases, you wouldn't want it becomes a blocker because they did not understand how your code works.
Well, you can always provide a documentation for every API details on your platform such as Confluence, but still that would takes time to look for it.
On the other hand, with second method you can achieve that one for all API.
TL;DR -> Large scale 1st method, small scale 2nd method.
I'm making a search agreggator and I've been wondering how could I improve the performance of the search.
Given that I'm getting results from different websites, currently I need to wait to receive the results for each provider but this is done one after another so the whole request takes a while to respond.
The easiest solution would be to just make a request from the client for each provider, but this would end up with a ton of request per search, (but if this is the proper way I'll just do it.)
Why I've been wondering is if there's way to return results everytime a provider responds, so if we have providers A, B and C and B already returned results then send it back to the client. In order for this to work all the searchs would need to run in parallel of course.
Do you know a way of doing this?
I'm trying to build a search experience similar to SkyScanner, that loads results but then you can see it still keeps getting more records and it sorts them on the fly (on client side as far as I can see).
Caching is the key here. Best practices for external API (or scraping) is to be as little of a 'taker' as possible. So in your Laravel setup, get your results, but cache the results for as long as makes sense for your app. Although the odds in a skyscanner situation is low that two users will make the exact same request, the odds are much higher that a user will make the same request multiple times, or may share the link, etc.
https://laravel.com/docs/8.x/cache
cache(['key' => 'value'], now()->addMinutes(10));
$value = cache('key');
To actually scrape the content, you could use this:
https://github.com/softonic/laravel-intelligent-scraper
Or to use an API which is the nicer route:
https://docs.guzzlephp.org/en/stable/
On the client side, you could just make a few calls to your own service in separate requests and that would give you your asynchronous feel you're looking for.
I'm currently developing an app in Laravel. While trying to adhere to REST API guidelines I've come across a scenario that I'm not sure how to handle RESTfully.
I have a Lease resource that handles multiple actions:
Route::get('/lease/create', 'API\LeaseController#create');
Route::get('/lease/{leaseId}', 'API\LeaseController#show');
Route::post('/lease', 'API\LeaseController#store');
Route::patch('/lease/{leaseId}', 'API\LeaseController#update');
Route::delete('/lease/{leaseId}', 'API\LeaseController#destroy');
So far these are a 1:1 between the URI and the controller actions. Now I have additional operations that I need to perform on a Lease and this is where I'm not sure what the best way to handle this is.
1) A Lease can be renewed (clone existing lease with new start and end dates).
2) A Lease can be ended (status changed to Inactive, end date updated).
When I think about doing this RESTfully I look at these two additional operations as a post and a patch to existing endpoints (both would map to the store and update method on the controller and could use the existing URIs.
Should I continue to think about it that way and map them both to existing endpoints? My concern with that is how would I handle different responses? For example if after a renew operation completes I want to pass a message saying "This lease has been successfully renewed.", how would I differentiate between a renew operation and a regular store operation since they both hit the same end point?
Or should I create two new URI's, something like:
Route::patch('/lease/{leaseId}/end', 'API\LeaseController#updateLeaseEnd');
Route::post('/lease/{leaseId}/renew', 'API\LeaseController#storeLeaseRenew');
And control logic in two separate functions even though it would be somewhat redundant since they really are just additional stores and updates?
It looks like you are trying to fit a RPC style API into a RESTful style API, which is possible, but can be confusing. You could do like you were saying with using the PATCH method, but now you have an overloaded method that should only do a partial update, but now it might execute an action on the resource. That would be confusing.
One way I've seen this done is by using what is called a verb (not to be confused by the "HTTP Verb") in the URI. This is essentially what you were stating as your last option in the question.
Structure
https://api.domain.com/namespace/resource/_verb
https://api.domain.com/namespace/resource/{id}/_verb
Example
https://api.domain.com/namespace/lease/{id}/_end
https://api.domain.com/namespace/lease/{id}/_renew
The underscore is there to signify that this is not a resource, but rather an execution call.
Another option would be to separate your REST API from your RPC API. You could use the traditional SOAP web service or go with the new gRPC, by Google.
I'm providing RESTful API to my (JS) client from (Java Spring) server.
Main site page contains a number of logical blocks (news, last comments, some trending stuff), each of them has a corresponding entity on server. Which way is a right one to go, handle one request like
/api/main_page/ ->
{
news: {...}
comments: {...}
...
}
or let the client do a few requests like
/api/news/
/api/comments/
...
I know in general it's better to have one large request/response, but is this an answer to this situation as well?
Ideally, you should have different API calls for fetching individual configurable content blocks of the page from the same API.
This way your content blocks are loosely bounded to each other.
You
can extend, port(to a new framework) and modify them independently at
anytime you want.
This comes extremely useful when application grows.
Switching off a feature is fairly easy in this
case.
A/B testing is also easy in this case.
Writing automation is
also very easy.
Overall it helps in reducing the testing efforts.
But if you really want to fetch this in one call. Then you should add additional params in request and when the server sees that additional param it adds the additional independent JSON in the response by calling it's own method from BL layer.
And, if speed is your concern then try caching these calls on server for some time(depends on the type of application).
I think in general multiple requests can be justified, when the requested resources reflect parts of the system state. (my personal rule of thumb, still WIP).
i.e. if a news gets displayed in your client application a lot, I would request it once and reuse it wherever I can. If you aggregate here, you would need to request for it later, maybe some of them never get actually displayed, and you have some magic to do if the representation of a news differs in the aggregation and /news/{id}-resource.
This approach would increase communication if the page gets loaded for the first time, but decrease communication throughout your client application the longer it runs.
The state on the server gets copied request by request to your client or updated when needed (Etags, last-modified, etc.).
In your example it looks like /news and /comments are some sort of latest or since last visit, but not all.
If this is true, I would design them to be a resurce as well, like /comments/latest or similar.
But in any case I would them only have self-links to the /news/{id} or /comments/{id} respectively. Then you would have a request to /comments/latest, what results in a list of news-self-links, for what I would start a request only if I don't already have that news (maybe I want to check if the cached copy is still up to date).
It is also possible to trigger the request to a /news/{id} only if it gets actually displayed (scrolling, swiping).
Probably the lifespan of a news or a comment is a criterion to answer this question. Meaning the caching in the client it is not that vital to the system, in opposite of a book in an Book store app.
I need to know the relative position of an object in a list. Lets say I need to know the position of a certain wine of all wines added to the database, based in the votes received by users. The app should be able to receive the ranking position as an object property when retrieving a "wine" class object.
This should be easy to do in the backend side but I've seen Cloud Code and it seems it only is able to execute code before or after saving or deleting, not before reading and giving response.
Any way to do this task?. Any workaround?.
Thanks.
I think you would have to write a Cloud function to perform this calculation for a particular wine.
https://www.parse.com/docs/cloud_code_guide#functions
This would be a function you would call manually. You would have to provide the "wine" object or objectId as a parameter and then get have your cloud function return the value you need. Keep in mind there are limitations on cloud functions. Read the documentation about time limits. You also don't want to make too many API calls every time you run this. It sounds like your computation could be fairly heavy if your dataset is large and you aren't caching at least some of the information.