at my work, we are currently struggling with uuid generation approach in a web application.
We do DDD and our persistent storage is a remote API that we own.
here is simplified exemple of my code:
class HireFooHandler() {
private $repository;
private $mailer;
public function __construct(FooRepository $repository, HiringMailer $mailer, ... ) {
$this->repository = $repository; //behind the repository, there are api calls
$this->mailer = $mailer;
...
}
public function handle(HireFooCommand $command) {
try {
$foo = new Foo($command->uuid, $command->baz, ...);
$this->repository->hire($foo);
$this->mailer->sendHiredMail($foo);
...
} catch(...) {
...
}
}
}
Some of my co worker are not confortable with the app generating and sending the uuid to the api.
They prefer to let the server side handle the uuid generation and if in this exemple "foo" is saved, send back the uuid generated to the app in the response.
The main argument is that, the api will be public too and they dont want the client having to generate the uuid.
On the other hand, from the point of view of my application and coding, as my Entity Foo should not be in an invalid state, to create it, i have to provided the uuid and so generate it from the client side, which i think is ok.
So here i'm, struggling with this and dont know what is the best approach, and where to generate my uuid ? client side ? server side ?
I proposed them to make the api more flexible by adding a uuid optional field in the post endpoint that can be validated. So the Api can received a uuid from the client and if not generate it's own.
But i'm not sure this is a good practice.
If someone have some inputs, i'll be glad to read it :)
You should understand why it is good to have uuid generation on a client-side, the biggest benefit for me is to allow doing async or complex stuff. For example, the client can send a request to a server and without waiting for a response, started to work with generated uuid, this approach allows the client to get a lot of benefit from uuid, as well as your php app when you started using uuid instead of dd, because you are no longer wanting and can send events for example. Also, there is a kind of middle solution, generating the uuid in the controller while creating command. There is more interesting concept: commands never failed.
Related
So I have this Laravel controller and I want to test it.
It is an OAuth client, so a callback is needed to finish the setup.
I want to test the OAuth callback.
The code is something like this:
public function callback(): \Illuminate\Http\RedirectResponse
{
$aCookie = request()->cookie('cookie');
$authCode = request()->get('code')
$connection = OAuthpackage::getConnection();
// Store the credentials in the database
}
To test if the credentials are stored correctly in de database I want to mock the OAuthpackage because it is fine to give it face credentials.
My first thought was to just test the controller by calling that directly. The thing with that is that I don't only need to mock the Oauthpackage but also the request class because I need to face the cookie getting in the code in the GET request.
Now I read on the internet that you probably would not want to mock the request class.
So I thought about just doing the request in the test and then seeing the output.
1 It is just the regular flow
2 I need only one mock
This is what I came up with:
public function testAppCallback()
{
$user = Auth::user();
$connectionFactory = $this->createMock(OAuthPackage::class);
$connectionFactory->method('getConnection')->willReturn(new DummyConenection());
$this->disableCookieEncryption();
$response = $this->withCookies([
'cookie' => 'http://localhost',
])->get('/oauth?code=my_auth_code');
}
The DummyClass just inherits from the real class, but this way I can test its type in the debugger. Turns out that the DummyClass is not being used.
It seems like Laravel boots up a whole new instance as soon as I make a web request and therefore forgets all about the DummyClass.
How should I go about to solve this problem?
I'm using Symfony 4.4 with Redis for the session.
I have some controllers and I wish to update the DB on back ground after to send a reply to user.
So I have written a code like this:
class GetCatController extends AbstractController
{
public function getCatController(LoggerInterface $logger, ManagerRegistry $doctrine, SessionInterface $session, ValidatorInterface $validator)
{
[...]
$replyToSend = new JsonResponse($reply, 200);
$replyToSend->send();
//My back ground activity like to do some query on the db.
[...]
return null;
}
But I have some problems about the sessions.
Is there a better way to create and run background activity sending before the reply to user?
There are two decent ways to do this.
If you are running PHP under php-fpm (not mod_php), you can dispatch & catch an event, kernel.terminate In Symfony pre-4.4, this is called PostResponseEvent (TerminateEvent from 4.4/5.0).
The better choice may be with Symfony Messenger. Here, you would create a message object, with all the information needed to perform the task, and send it to a background queue (Redis is supported as a queue). A worker then consumes that message, and does the task.
I am working on a Laravel app where I am building some API for other websites. But I am trying to make the implementation of my API as easy as possible. My expectation is that the user will only use this tag in the HTML head:
<script src="api.mydomain.com">
Now I have a controller on this URL that provides the source javascript with the content-type header, but before it goes there, the router will first execute my authentication middleware. Let's say it looks something like this:
public static $users = [
'client1.com',
'client2.com',
'client3.com'
];
public function handle(Request $request, Closure $next)
{
$origin = "HERE I NEED THE ORIGIN URL"; // e.g. client4.com
if ( !in_array($origin, self::$users) ) {
abort(401);
}
return $next($request);
}
As you can see from the code, I need to retrieve the $origin variable. So if a website client1.com will try to insert my javascript, it will successfully get the javascript code. If client4.com tries to access it, it will get a 401 error.
I found out methods with $_SERVER['HTTP_REFERER'] or Laravel's $request->server('HTTP_REFERER'), but this data might be spoofed, right?
In the best-case scenario, I would like to retrieve the original domain and when not available (e.g. from a private cURL request), I would like to get the IP address. And of course, I need it to be secure - clients1/2/3 paid for my API, others didn't.
How can I do it? Or is there any better method for origin authentication?
All that referer stuff can be spoofed.
Best way for paid API is to issue API calling key.
You API can display results or error depending if the client has proper API key and is Paid for.
You should also keep logs table for API calls with timestamp and clientID and IP addresses. So from time to time you can check if one of your paid client is sharing his key with others etc from call frequency and IP patterns.
Clean up this logs table from time to time to keep it small and efficient.
So I figured it out by adding headers (thanks for inspiration #jewishmoses) in the middleware handler. My Javascript is available basically to everyone, but it provides only a button, that tries to create a new element with an iframe inside (my app which also works as an API).
Let's say I have an associative array on the server, that I can dynamically fill from any database:
$clients = [
'client1' => 'paying-customer.com',
'client2' => 'also-paying-customer.com',
];
...my route for API is defined as 'api.mydomain.com/{client}' and 'api.mydomain.com/{client}/iframe' for iframed app. This handler takes care of adding headers:
public function handle(Request $request, Closure $next)
{
$client = $request->route('client',null);
$clientSet = $client !== null;
$clientAccepted = isset($clients[$client]);
if ( $clientSet and !$clientAccepted ) {
abort(401);
}
$response = $next($request);
if( $clientSet and isset($response->headers) and $response->headers instanceof ResponseHeaderBag){
$clientDomain = $clients[$client];
$response->headers->add([
'Content-Security-Policy' => "frame-ancestors https://*.$clientDomain/ https://$clientDomain/"
]);
}
return $response;
}
Now what might happen:
client1 successfully imports javascript from api.mydomain.com/client1, which will try to access api.mydomain.com/client1/iframe (also successfully)
client3 unsuccessfully tries to import javascript from api.mydomain.com/client3
client3 successfully imports javascript from api.mydomain.com/client1, which will try to access api.mydomain.com/client1/iframe (refused by headers)
Maybe there is a more elegant way to block loading the javascript, but providing my own app as API (in an iframe) is in my opinion secured enough because I can control who can use it and modern browsers will help me to stop the "thieves". This resource was most helpful to solve my problem.
I am using a rest api to store/retrieve my data which is stored in a postgres database. The api is not laravel, its an external service!
Now i want to create a website with laravel (framework version 7.3.0) and i'm stuck on how to implement the api calls correctly.
For example: i want to have a custom user provider with which users can log-in on the website. But the validation of the provided credentials is done by the api not by laravel.
How do i do that?
Just make a Registration controller and a Login Controller by "php artisan make:controller ControllerName" and write Authentication logics there.
In previous versions of Laravel you had a command like "php artisan make:auth" that will make everything needed to do these operations. But in Laravel 7.0 you need to install a package called laravel/ui.
Run "composer required laravel/ui" to install that package
Then run "php artisan ui bootstrap --auth"
and now, you are able to run "php artisan make:auth"
This command will make whole Registration (Signup) and Login system for you.
and in orer to work with REST, you may need to know REST (Http) verbs. Learn about GET, POST, PUT, PATH, DELETE requests and how to make those request with PHP and Laravel collection methods. Learn about JSON parsing, encoding, and decoding. Then you can work with REST easily. and work without any template codes from other packages.
Thank you so much. I hope this answer give you some new information/thought. Thanks again.
Edit:
This might not be the best way. But this is what I did at that time. I tried curl and guzzle to build the request with session cookie and everything in the header to make it look like a request from a web browser. Couldn't make it work.
I used the web socket's channel id for the browser I want the changes to happen and concatenated it with the other things, then encrypted it with encrypt($string). After that, I used the encrypted string to generate a QR code.
Mobile app (which was already logged in as an authenticated used) scanned it and made a post request with that QR string and other data. Passport took care of the authentication part of this request. After decrypting the QR string I had the web socket's channel id.
Then I broadcasted in that channel with proper event and data. Caught that broadcast in the browser and reloaded that page with JavaScript.
/*... processing other data ...*/
$broadcastService = new BroadcastService();
$broadcastService->trigger($channelId, $eventName, encrypt($$data));
/*... returned response to the mobile app...*/
My BroadcastService :
namespace App\Services;
use Illuminate\Support\Facades\Log;
use Pusher\Pusher;
use Pusher\PusherException;
class BroadcastService {
public $broadcast = null;
public function __construct() {
$config = config('broadcasting.connections.pusher');
try {
$this->broadcast = new Pusher($config['key'], $config['secret'], $config['app_id'], $config['options']);
} catch (PusherException $e) {
Log::info($e->getMessage());
}
}
public function trigger($channel, $event, $data) {
$this->broadcast->trigger($channel, $event, $data);
}
}
In my view :
<script src="{{asset('assets/js/pusher.js')}}"></script>
<script src="{{asset('assets/js/app.js')}}" ></script>
<script>
<?php
use Illuminate\Support\Facades\Cookie;
$channel = 'Channel id';
?>
Echo.channel('{{$channel}}')
.listen('.myEvent' , data => {
// processing data
window.location.reload();
});
</script>
I used Laravel Echo for this.
Again this is not the best way to do it. This is something that just worked for me for that particular feature.
There may be a lot of better ways to do it. If someone knows a better approach, please let me know.
As of my understanding, you are want to implement user creation and authentication over REST. And then retrieve data from the database. Correct me if I'm wrong.
And I'm guessing you already know how to communicate over API using token. You are just stuck with how to implement it with laravel.
You can use Laravel Passport for the authentication part. It has really good documentation.
Also, make use of this medium article. It will help you to go over the step by step process.
The more I read about dependency injection the more I get confused. I know what it is for, that is not the problem. Trying to do some design on paper this is what I came up with and somehow it seems to me I am overlooking something.
First I imagined building an actual server that would accept incoming requests and returns responses to the user.
class Server {
private $responseBuilder;
public function __construct($responseBuilder) {
$this->responseBuilder = $responseBuilder;
}
public function run() {
// create socket, receive request
$response = $this->responsebuilder->build($request);
// send response
}
}
class Response {
private $method;
private $message;
private $url;
// getters & setters
}
class ServerBuilder {
public build() {
// construction logic
return new Server(new ResponseBuilder());
}
}
Since Apache is used to handle server requests we could replace the server with something that just send the response.
$bldr = new ResponseBuilder();
$response = $bldr->build();
// send response some way
Note that ResponseBuilder has direct access to the request ($_SERVER['..'])
and so it has everything it needs to choose the right response.
PHP however allows us to build and send responses inline. So we could have a Controller object for each page or something else that send the response and have a builder for that.
$bldr = new ControllerBuilder();
$controller = $bldr->build();
$controller->run();
class ExampleController implements Controller {
public function run() {
header("HTTP/1.1 404 Not Found");
echo 'sorry, page not found';
}
}
This all makes sense to me. But let's look at the server example again.
It calls $responseBuilder->build() and gets a response back. But this would mean that the builder (or other builders if we split it) is also responsible for anything else that might occur like authenticating a user, writing to the database,... and I can't get my head around the fact that writing to a database would be part of the object graph construction.
It would be like: Send me your request. Oh you want the homepage? I will build you your response and while I'm at it I will also do some things that have nothing to do with building it like logging what I just did and saving some of your data in a cookie and sending a mail to the administrator that you are the first visitor on this page ever, ...
You should decouple them. You have a few assumptions that I think are a bit strange. Let's start with them.
The main purpose of an incoming http request is to give back some html
I have built PHP backends that only return JSON, instead of HTML. I had a really strong border between back and front end. I only used the backend to give me data from the database, or add/edit data in the databse. The front end was just a PHP script that would build the pages any way i wanted.
Since it is the web there is in theory no use for setters since
everything can be injected in the constructor
You could use the constructor, but you don't have too. You can use setters. Dependency injection is actually just turning the flow around.
You are on the right track though. You want some class that is responsible for building your pages. So, make it only responsible for your building your pages, and take out the other responsibilities. Things like logging, authentication etc should be outside of that.
For instance if you want logging, you could have your builder create your page, and your logger could then listen to all the things your builder is doing (with the observer pattern for instance). So if your builder says: "i created the home page", you can log it with your logger, who is actually listening to your builder.
Authentication for instance should happen even before your builder starts. You don't want your builder to go to work if you can already figure out that a user is not supposed to be on a page. You could use a database for that, and whitelist any usertype/pagerequest combination.
Then for data handling, i would create a backend, that only handles requests that are supposed to give back data, or save it. The front end could then communicate to get it's content by pulling it.
I hope this clears up a few things, but I'll be happy to answer more indept questions.