Universal: Can't use/inject REQUEST and RESPONSE in the browser

Created on 4 May 2017  路  23Comments  路  Source: angular/universal

  • I'm submitting a ...
  • [x] bug report

  • What modules are related to this Issue?

  • [x] express-engine

  • Do you want to request a feature or report a bug?
    I think it's a bug

  • What is the current behavior?
    It's not working as expected. The documentation states the following:

Using the Request and Response
..
If your app runs on the client side too, you will have to provide your own versions of these in the client app.

So I checked the source code of the express engine. The REQUEST and RESPONSE are provided for the dependency injection here: https://github.com/angular/universal/blob/master/modules/ng-express-engine/src/main.ts#L129

I tried to inject (a stub for) the REQUEST in the browser bootstrap file like this:

import 'zone.js/dist/zone';
import 'reflect-metadata';
import 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { CompilerOptions } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/dist/src/tokens';
import { BrowserAppModule } from './app/browser-app.module';

const compilerOptions: CompilerOptions = {
  providers: [
    {
      provide: REQUEST,
      useValue: {}
    },
    {
      provide: RESPONSE,
      useValue: {}
    }
  ]
};

platformBrowserDynamic().bootstrapModule(BrowserAppModule, compilerOptions);

as this mostly resembles how the bootstrapping is done in the express engine. But this doesn't work, but it does compile and build. I can get full access to the REQUEST on the server, but in the browser I get this error:
ERROR Error: No provider for InjectionToken REQUEST!

I tried the same providers in the root Module. Same result.

  • If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem by creating a github repo.

Inject the REQUEST like this, anywhere in the application:
constructor(@Inject(REQUEST) private REQUEST: any) {} and run the application. It will work on the server side but emit an error in the browser ( see stacktrace below )

  • What is the expected behavior?

That I can inject the REQUEST ( and/or RESPONSE ) also in the client side code. The values should just be mocked as empty or filled in where possible, like for example the document.cookies

  • Please tell us about your environment:

  • Angular version: 4.1

  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX ]
  • Language: [ TypeScript 2.2 ]
  • OS: Mac OS X
  • Platform: NodeJs
express-engine

Most helpful comment

@vikerman still need to validate.. will try to do it in the upcoming days
edit: JIT works, AOT works, wicked :) thanks a lot! @MarkPieszak @FrozenPandaz @vikerman

All 23 comments

@FrozenPandaz I think you are the best one to take a look at it please .. ( also according to my chat with @manekinekko ) Thanks a lot in advance!

Move those into your browser-app.module (the REQUEST/RESPONSE providers) and you should be all set. Also for REQUEST you could just pass back cookie: document.cookie since the browser has access to those, instead of an empty {}. https://github.com/MarkPieszak/aspnetcore-angular2-universal/blob/master/Client/app/browser-app.module.ts#L56-L57

Hope that helps!

@MarkPieszak your solution doesn't work in my case. The same error keeps popping up.. Am I missing something? As I said I tried this before, only did not do it with the factory pattern..

I've updated the example repo I created and more specifically here: https://github.com/samvloeberghs/ng-universal-demo/blob/master/src/app/browser-app.module.ts

hi guys, sorry about the push, but this is completely blocking my development..
As you said before it should be possible, but the example repo that I made ( which is a fresh clone + import of the request ) doesn't work out..

@samvloeberghs and @MarkPieszak, I have the same problem.. In my case I'm trying to access the cookies on the server side (on client side I use ng2-cookies).
I was using this way on angular 2:
server.ts

res.render('../dist/index',` {
    req: req,
    res: res,
    cookies: req.cookies
  });

then in server.module.ts

function getCookies() {
  return Zone.current.get('req').cookies;
}
...
{ provide: 'Cookies', useFactory: getCookies },
...

any-component.ts

constructor(@Inject('Cookies') private cookies)
...

But it doesn't seems to work anymore neither..

And I just tried the new InjectionToken<string>('REQUEST'); but I got nothing on the server.
Also get the same error as @samvloeberghs (No provider for InjectionToken REQUEST!) when reproducing.

Any hint we could explore ?

I haven't used the express engine in a little while but that's strange since they're definitely being passed in here : https://github.com/angular/universal/blob/master/modules/ng-express-engine/src/main.ts#L129

@frozenpanda have you ran into this?

I read again the initial issues description by @samvloeberghs and I realize now that I have the oposite problem.. Providing REQUEST in the browser.module.ts as suggested by @MarkPieszak DO work for me. However on the server-side I still got the No provider for InjectionToken REQUEST! error...

Indeed it's strange since it is well provided by the ng-express-engine... Still investigating..

@FrozenPandaz on a fresh clone of your repo ng-universal-demo, I reproduce the same behavior. I get the Server Side error No provider for InjectionToken REQUEST!, but get the provided REQUEST on client side.

Sorry about this, while there seems to be many issues regarding the request and response tokens, i do not think this is one of them. I'm able to use them without AoT here

https://github.com/FrozenPandaz/ng-universal-demo/tree/request

Adding another implementation as a provider in your browser.app.module should do the trick..

(Build is acting up right now because of something related to AoT)

I'm gonna try out your solution tonight.. But if it's not working with AoT it's pretty useless..
edit: verified that it works in a JIT build, AOT still fails. The solution provided in https://github.com/angular/universal/issues/713 I'd also rather avoid..

Ouf I finally got it ! Thanks to your last update of the readme of the ngExpressEngine @FrozenPandaz !

So far I was creating a file request.ts with..

import { InjectionToken } from '@angular/core';
export const REQUEST = new InjectionToken('REQUEST');

.. then adding the REQUEST provider to browser modules, and injecting the REQUEST wherever I needed.

However with this I had a No provider for InjectionToken REQUEST on the server side, even if the ngExpressEngine should set the providers here https://github.com/angular/universal/blob/master/modules/ng-express-engine/src/main.ts#L129 as you pointed out @MarkPieszak.

After reading the update of the readme, I used the InjectionToken from import { REQUEST } from '@nguniversal/express-engine/tokens'; instead of my own requests.ts file. And it now works !

The problem seems to come from not using the same InjectionToken variable that the one set in the provider. Which make sens..
I probably got confused because I used to set providers using a string ({ provide: 'example', useFactory: getexample },) instead of a InjectionToken.

Does it make sens ? I hope I've been clear enough in the explanation !

Thanks for your help !

still doesn't work with AOT on my side.. Can't do more than provide the example repo.. run it and see it failing :)

Yep not working in AOT.. and this solution doesnt work for me either https://github.com/angular/universal/issues/713
Still No provider for REQUEST

it seems so strange tough, as using different providers for server and browser seems to be working fine, if imports don't come from a library. So my gut feeling says that the problems reside in the express engine module. If I would have the time to play around with it I would to see what it requires to get it to work, but have too much commitments at the moment..

Is this resolved after adding the ngc compilation?

@vikerman still need to validate.. will try to do it in the upcoming days
edit: JIT works, AOT works, wicked :) thanks a lot! @MarkPieszak @FrozenPandaz @vikerman

we update our project and have that very same issue

@phil123456 Did you update your project taking in account this breaking change ? https://github.com/angular/universal/blob/master/CHANGELOG.md#500-beta6-2018-02-28

@samvloeberghs I was just trying to running your Universal Test (https://github.com/samvloeberghs/ng-universal-demo) and I get that no Provider for InjectionToken Request error. Any chance you would have a moment to update with the working version? Would be much appreciated, thanks!

@sjsnider I haven't update it in years.. You can best checkout this updated project, where my original demo was also based upon.

Thanks, I got it working, just had to slightly change the import of the REQUEST to import { REQUEST } from '@nguniversal/express-engine/tokens'; and then inject the REQUEST optionally,

  constructor(
    @Optional()
    @Inject(REQUEST)
    private request: any){}

Thanks for the great start!

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings