I am trying to create a backend server with Aqueduct in dart. I am trying to create a resource controller that will deal with account issues.
routing code is like this;
router
.route("/$apiEntryPointUrl/account/:operation").link(() => AccountController(context, authServer));
When I try to test routers path variables like this;
#Operation.post("asdf")
Future<Response> test() async {
return Response.ok("testsuccess");
}
#Operation.post("operation")
Future<Response> test5() async {
return Response.ok("bugsuccess");
}
#Operation.post("test3")
Future<Response> test2() async {
return Response.ok("testsucces3333s");
}
When I add Operation.post("operation") as path variable, anything I pass into variable goes to this function. If I do a post request to like /account/tes2 it invokes test5() function. Is this normal? Am I missing some basics?
Actually yes, that's normal and intended. If you specify something like this: '/account/:operation' or '/account/:id' in your router then you end up with a kinda wild card, which is in these example cases 'operation' or 'id'.
The operator ':' acts as a wild card operation. This means in fact an api call to a route like '/account/tes2' will call the wild card route automatically.
Related
I'd like to extend the Future class and give it more functionality while keeping the functionality of the await keyword. As I understand it, Futures can't be extended directly in Dart, but perhaps there is another way to achieve what I want?
The class I'm trying to create is effectively a mechanism for interacting with an API. The server is RPC-like in the sense that its' API can be bi-directional while the request is open (messages can go back and forth between server and client until the request is considered resolved).
To make the client library more usable, I'm trying to create a Request class that has all the goodness of a normal Future, but also the ability to use a when() or on() function which effectively listens for updates during the resolution of the future.
Some sudo code of usage:
Request(args)
.when('SomeEvent', (event) => print('An update: $event'))
.then((response) => print('The final response: $response'))
.onError((err) => print('Some error: $err'));
// This also needs to work:
final response = await Request(args);
So far I have something like this, but the await keyword doesn't work:
class Request {
final Completer _completer = Completer();
Request(args) {
/* Setup and make some request to an API and respond/update using response|error|update */
}
Future<dynamic> then(fn) async {
// Should this actually return a Request?
return _completer.future.then(fn);
}
Future<dynamic> onError(fn) async {
// Should this actually return a Request?
return _completer.future.onError(fn);
}
Request when(String eventName, Function fn) {
/* attach a listener/stream which fires fn on update */
return this;
}
void _response(res) {
_completer.complete(res);
}
void _error(err) {
_completer.completeError(err);
}
void _update(upd) {
/* Some update from the request is given */
}
}
Is what I'm attempting impossible in Dart?
I'd recommend not extending the Future interface, but instead let your Request class have a future instead of being a future.
Then you can do await request.result and request.when(...), without having to re-implement the entire Future API.
If you insist on making Request be a Future, all you need is to add implements Future<Object?> to the class ... and then actually implement the entire Future API. No need to do onError (that's an extension method which works on any Future, including your Request), but you need to implement then, catchError, whenComplete, asStream and timeout correctly and totally (support all the arguments and have the correct type).
Then you'll be able to use your class with await.
If you do that, you can make those functions return Request too, if you make Request generic (class Request<T> implements Future<T>), because .then<int>(...) needs to return a Future<int>. You'd need a strategy for forwarding the when/on events to the new futures then.
It's much easier not to do that, and just expose the internal future by itself, separately from the progress callbacks.
See also CancelableOperation.
Motivation: I need to set the threadKey for a DelegatingSessionFactory before I route to an Sftp outbound gateway and unset the threadKey afterwards.
Depending on a tenant I need to use a different Sftp user account. The user accounts are a matter of configuration in my application.yml, I do not want to write separate routes for each new tenant.
public IntegrationFlow aDynamicSftpFlow() {
f -> f
.handle(tenantSessionDefine()) // how can I use a lambda instead?
.handle(Sftp.outboundGateway(delegatingSessionFactory, ...))
.handle(...) // undefine sftp session
}
Setting the threadKey requires a Message<?>, not just payload and headers. So I use a bean because it takes a message:
public class TenantSessionDefine {
private DelegatingSessionFactory delegatingSessionFactory;
public TenantSessionDefine(DelegatingSessionFactory delegatingSessionFactory) {
this.delegatingSessionFactory = delegatingSessionFactory;
}
public Message<?> defineSession(Message<?> message) {
return delegatingSessionFactory.setThreadKey(message, message.getHeaders()
.get("tenantId", String.class));
// used by SessionFactoryLocator
}
}
I would like to write that as a lambda, as in
.handle(message -> delegatingSessionFactory.setThreadKey(message,
message.getPayload().getTenant())
but that is not so easy. The lambda that can be used with handle() which takes a Message<T> ends the flow because it is a void function (MessageHandler functional interface). The other lambda is a GenericHandler, which does not end the flow, but it takes payload and headers, not a message.
This is just an example, every now and then I wish I could use handle() with a message in a lambda without ending the flow. How can I do that?
Update
The DelegatingSessionFactory is not a particularly well suited example. Since setting and clearing the thread key should happen before and after the sftp invocation, an advice fits better than defining a handler before and after the call.
Got it. The javadoc for handle() says
Use handle(Class, GenericHandler) if you need to access the entire message.
The Class parameter must be Message.class:
.handle(Message.class,
(message, headers) -> sftpSessionFactory
.setThreadKey(message, headers.get("tenantId")))
I'm trying to test a controller made with Symfony 4 with PHPUnit.
I'm using https://github.com/lexik/LexikJWTAuthenticationBundle to manage JWT.
This controllers should return a 200 if a valid JWT is given, a 401/403 otherwise.
The first part with the 401 response is easy: I just don't send any token
<?php
namespace App\Tests\Controller;
Class GraphQLControllerTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTestCase {
function test_token(){
$client = static::createClient();
$client->request('GET', '/graphql');
// Check 401 response
$response = $client->getResponse();
$this->assertSame(401, $response->getStatusCode());
$this->assertSame('"Not authenticated"', $response->getContent());
}
}
The next part is tricky: how do I get my JWT encoder service in my test_token method in order to generate some tokens to test 200 and 403 responses?
If I were in a controller I could use Symfony autowiring or make a public alias of lexik_jwt_authentication.encoder to be used like this:
$this->container->get('lexik_jwt_authentication.encoder')
Loading manually the service in my test like this bellow seems inefficient as some of the arguments of the constructor are some objects, and some arguments of their own constructor are objects, and ...
new Lexik\Bundle\JWTAuthenticationBundle\Encoder\DefaultEncoder([some objects here])
This is what is nice with autowiring: you just get the service you want ready to be used.
=> What's the best way to get this service in my test?
Thanks!
It's now possible with Symfony 4.1 to load a private service within a test using the KernelTestCase
I have my middleware and inside it I am trying to reach the current url of the page. so I did something like that:
$url = Request::url();
and I used:
use App\Http\Requests;
use Illuminate\Http\Request;
but I keep getting the following error:
Non-static method Illuminate\Http\Request::url() should not be called statically, assuming $this from incompatible context
any ideas?
You can access the url from the Request Object:
public function handle($request, Closure $next)
{
$url = $request->url();
...
}
Request object has also fullUrl() and path() methods. Choose the one that fit your needs
In Laravel 5 the request is already passed into the handle() function
class MyMiddleware {
public function handle($request, Closure $next)
{
$url = $request->url();
// Do stuff here
return $next($request);
}
}
Laravel 5 tries to move away from facades (e.g: Calls such as Request::url()) in favour of using dependency injection, so you may notice some functions and such cannot be accessed the same as you did in 4.
Heres quite a nice explanation of dependency injection in Laravel 5 https://mattstauffer.co/blog/laravel-5.0-method-injection
This is my unit test for create function :
public function testCreate() {
$this->routeMatch->setMatchedRouteName('restful');
$this->request->setMethod('POST')
->setContent('name=A');
$result = $this->controller->dispatch($this->request);
$response = $this->controller->getResponse();
$this->assertEquals(403, $response->getStatusCode());
$this->assertArrayHasKey('id', $result);
}
And this is my function :
public function create($data) {
if (empty($data)) {
$this->response->setStatusCode(400);
return;
}
for ($i = 0; $i < count(self::$ideas); $i++) {
if (self::$ideas[$i]['name'] == $data['name']) {
$this->response->setStatusCode(404);
return;
}
}
//#todo: secure the API
self::$index++;
$tmpArray = array('id'=>self::$index, 'name'=>$data['name']);
$this->response->setStatusCode(403);
}
But it seems that the $data is always blank. Am I wrong at the part writing unit test ?
When I try to use curl POST with -d, the $data has value as what I post through curl. I'm a quite confused what is wrong here ?
Thanks for reading and looking forward to your answer :)
Answer
I've came up with my successful unit test http://pastebin.com/fwFe0Mi3
For more information, I use this module to implement restful controller
If you take a look at \Zend\Mvc\Controller\AbstractRestfulController method processPostData you will notice that the method create in your controller is given an array of the post params from the request object.
If you look at \Zend\Http\Request the $postParams property is populated by the setPost method.
Now the child class \Zend\Http\PhpEnvironment\Request (used by ZF2 when you are requesting something) that extends \Zend\Http\Request (above) on instantiation (__contruct method) calls the setPost method (above) giving it the $_POST array.
This means that eventually ZF2 internally feeds your controller's create method with the $_POST contents and not by parsing the request body.
Now to your code.
I don't think dispatch will do anything without you having set up the event framework first. Instead you can call the controllers execute method providing it with an MvcEvent. The MvcEvent needs to have the request you instantiated set.
Secondly, as described above you need to call the request's setPost and give it an array for the create method to work properly. (On the other hand PUT reads the data from the request body)
Try doing that and if you are still having trouble I will try and give you an example soon.