Exposing a model without any routes - api-platform.com

I'm trying to do pretty much what is explained in https://api-platform.com/docs/core/operations/#expose-a-model-without-any-routes. To stick to that example, I have:
An API resource Place with full CRUD functionality
Another model Weather that represents the weather of a place
and I want to have a GET /places/{id}/weather endpoint to get the weather of a specific place.
The solutions that I came up with and the problems I see in them
Having an API Platform independent controller/route that handles this
The route is not showing up in the OpenAPI documentation (could implement this myself of course)
I don't benefit from the built-in serialization features and have to implement this myself
Making Weather a resource and creating it via custom Controller as done in https://api-platform.com/docs/core/operations/#expose-a-model-without-any-routes
Weather needs an ID to work (right?)
Referencing a non-existant Controller and removing endpoints from the OpenAPI documentation but NOT their routes feels very hacky to me
Making Weather a subresource
A weather property/reference in my Place resource is incorrect / not needed
Weather needs an ID again which is not wanted
Making Weather a dedicated API resource and using a custom Controller or DataProvider with the places ID
I'm kind of misusing the Place ID for Weather
Making Weather a custom representation / output / DTO of Place with a custom route and a custom Controller
Weather is not a Place
I currently went with the last solution because I could get rid of the ID in Weather and only needed a text adaption in the OpenAPI documentation. The annotation that I'm using in Place is looking like the following
* #ApiResource(
* itemOperations={
* "get",
* "delete",
* "put",
* "patch",
* "get_weather"={
* "method"="GET",
* "path"="/places/{id}/weather",
* "controller"=WeatherController::class,
* "output"=Weather::class
* }
* },
* )
But there must be a better solution for this, right? Am I overlooking something?

Related

how to implement Single Responsibility in laravel

I am so confused about how to implement and how to follow SRP (single responsibility principle ) in a Laravel controller.
Suppose we have a controller which we have to do these things:
e.g
public function StorePost() {
// check user login()
//check number of current user Post count =>which must be less than 10
//store post
//send an email to user which your post has saved
//return =>api:json /web : redirect
}
I know that I can implement some DB queries in the repository but I don't know how to implement others of my logic code to achieve SRP
Also, I know there is a Heyman package to achieve these but I want to implement it by myself.
SRP in this context basically means each class and method should only be responsible for a single behaviour/feature. A rule of thumb is a class or method should change for one reason only, if it changes for multiple reasons, it needs to be broken down into smaller parts.
Your storePost method should not bother with checking the user login, that should be handled elsewhere before invoking storePost. storePost shouldnt change if the auth mechanism changes like switching from api token to json web token or something else. Laravel does this in the middleware level with the auth middleware.
Checking the users post count, this can be checked in the validation stage. storePost shouldn't change if we add more validation logic. In Laravel you can use FormValidation for this
For storing the post, the controller doesn't need to know how to call the DB, you can use the active record style using the model class or maybe create a service or repository class if your use case requires that. storePost shouldn't change if we decide to change DB vendor like going NoSQL.
For sending email, again the controller doesnt need to know how to send the email like what the subject/body recipients are. storePost shouldnt change if we need to change the email layout. Laravel has Notification for that
For serialising the response to json, the controller doesnt need to know how to format the response. if we decide to update how our json looks, storePost shouldnt change. Laravel has API Resources for that
So, ultimately in this example, the responsibility of the controller method is basically to glue all these together. It basically does what you wrote down, it only responsible for maintaining the step by step behavior, everything else is delegated to someone else. if the behavior change, like adding new behavior e.g notify all follower, storePost will change.

laravel middleware setting $request attribute, does it affect performance

In one of my middleware I have used something like this
$user = [
'name' => 'noob',
'phone' => '87548154'
]; /* which actually comes from redis cache */
$request->attributes->set('user', $user);
and in the controller i use it like
$request->get('user')['name']
OR
$request->get('user')['phone']
As this seems very flexible, I would like to attach more data into the $user array.
In the laravel docs its written above the get() method of Request class is
* Gets a "parameter" value from any bag.
* This method is mainly useful for libraries that want to provide some flexibility. If you don't need the
* flexibility in controllers, it is better to explicitly get request parameters from the appropriate
* public property instead (attributes, query, request).
* Order of precedence: PATH (routing placeholders or custom attributes), GET, BODY
My question is, is it going to be a good idea? because the most frequently used data is already attached in the middleware. So that I dont have to write extra codes in the controller methods again and again. Will it affect on performance for a high traffic server?
I personnally never work this way. You can access the current user from anywhere using the Auth facade as following :
\Auth::user()
It enable you to never send it when unnecessary and still use it from anywhere (controllers, models, blades or everything else).
Then to access your properties :
\Auth::user()->phone
and so on...

Magento - Separate contact forms

I'm working on a website where the client needs to have multiple separate contact forms (one for contact, one for "request a quote", another couple for stuff like that).
I've already managed to create another contact form with additional fields, but it was the contact one, so the fields were only name, email, subject and message.
Now I've got the "skeleton" of the others, but my question is: is there a way to take advantage of the "Contact" backend to send emails? Or do I need to have another controller to manage them?
If so, can you show me some links or piece of code to start off with?
Thanks in advance.
To do what you want, a custom controller is necessary to pass the POST data.
If you examine \app\code\core\Mage\Contacts\controllers\IndexController.php on line ~62 you'll find postAction() which is called by indexAction() - the default action of the controller.
This is the method that is collecting the passed POST parameters and using the core/email_template model to send off the e-mail. I'd use this code as a reference for your controller.
Be sure you put it all in your own module as always with functionality additions.
To know what you can and cannot pass to the core/email_template model, take a look at \app\code\core\Mage\Core\Model\Email\Template.php. It's got loads of documentation in there for you.
Heck, it's even got example code!
// Loading of template
$emailTemplate = Mage::getModel('core/email_template')
->load(Mage::getStoreConfig('path_to_email_template_id_config'));
$variables = array(
'someObject' => Mage::getSingleton('some_model')
'someString' => 'Some string value'
);
$emailTemplate->send('some#domain.com', 'Name Of User', $variables);
In particular take a look at line ~371, where it passes the variables you set to the layout-specified e-mail template.
/**
* Send mail to recipient
*
* #param array|string $email E-mail(s)
* #param array|string|null $name receiver name(s)
* #param array $variables template variables
* #return boolean
**/
public function send($email, $name = null, array $variables = array())
Magento is doing the same thing that you'd do with any contact form on a plain old PHP form processor. It just delegates everything out to models like the one above so you don't have to do so much work re-inventing the wheel, as it were. Just a new controller to accept the parameters in the POST data.
Feel free to follow up and I'll update the answer to help you where I can!
Here's a concise list of things you'll need to make this happen:
A custom controller to accept the form(s) POST data and pass it to the core/email_template model.
A custom form in the front-end pointing to your controller URL (already done!)
A custom e-mail template for the core/email_template to use to display the data in the e-mail the recipient sees.

Safely save data to django model using AJAX

I have a model say TestModel as follows:
class TestModel(models.Model):
name = models.CharField()
description = models.TextField()
Now I can use a ModelForm to save data to this model. However, say I want to use Ajax and send a url as follows savethis?name=ABC&desc=SomeRandomDescription to a view that handles it as follows:
def savethis(request):
if request.GET['name'] and request.GET['desc']:
name = request.GET['name']
desc = request.GET['desc']
test = TestModel(name=name, description=desc)
test.save
return HttpResponse('Ok')
else:
return HttpResponse('Fail')
What's to stop someone from running a script that can easily hit this url with valid data and thus save data to my model? How do I ensure that incoming data is sent only from the right source?
One option is sending the data as JSON in a Post request but even that's not too hard to emualte.
Seems that you have stumbled upon the great security flaw that is Cross-site Scripting attacks. They are several ways you can get around it, but going into all of them in one answer would be fruitless. I suggest you Google the term and do some poking around, and you will find several different methods on how to protect your site better.
Django has a security page dedicated to talking about how to protect your site.

In an API Blueprint document, can I combine a model with headers?

The “model” facility seems intended to reduce duplication — when specifying the requests and responses to various methods on a resource, the same body will frequently be specified multiple times. So one can define a “model” and then “refer” to it within various request and response “payload” sections.
So I’ve defined a model like so:
### An Event
* Model (application/vnd.document+json)
{
"_type": "document",
...
}
and I can then refer to it in various places:
* Response 200
[An Event][]
which works great; the output includes the entire model body in place of the cross-reference.
However, I can’t figure out how to combine this reference with a request or response header.
I’ve tried various formats along these lines:
* Request
* Headers
If-Match: some-etag-value
* Body
[An Event][]
or
* Request
* Headers
If-Match: some-etag-value
[An Event][]
with no luck.
Is there any way to do this?
There is currently no way to alter referenced model's payload. Neither it's planned in any of API Blueprint Milestones.
Feel free to add it to the milestones and propose its syntax, if you will. Before doing so please consider any potential synergy with planned API Blueprint Object Traits.

Resources