Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

How do we use DI with separate client/server services? #148

Closed
dimitrovs opened this issue Aug 14, 2016 · 5 comments
Closed

How do we use DI with separate client/server services? #148

dimitrovs opened this issue Aug 14, 2016 · 5 comments

Comments

@dimitrovs
Copy link

I want to integrate authentication in a Angular Universal app. I found this example: https://gist.github.com/jhades/4d9e1422b020b10acaf616d3ee4a3db7 which shows how to do it with a common Client / Server interface and a Server service no-op implementation. But it's not clear how to actually use these services in the Universal app.

I found this pattern referenced in a few places regarding Angular Universal but no example of a setup that does this. I think it will be very helpful to integrate a mock service with different client/server implementation into the universal-starter project.

@MarkPieszak
Copy link
Member

https://github.com/gdi2290/ng-conf-2016-universal-patterns/tree/master/3-di-demo

^ You can see a small example of it there that Patrick did a while back.

@dimitrovs
Copy link
Author

Thanks, this was a helpful example. What I gather from it is that the pattern works in the following way:

  1. Create 3 classes, one Mock (I would normally use an interface, but TypeScript complains that it "can't find name"), one Server implementation and one Client implementation.
  2. In the constructors we use the Mock class, and call methods on it.
  3. In main.browser.ts we put as part of the bootstrap array: {provide: MockClass, useClass: ClientClass}
  4. In main.node.ts we put again in the bootstrap array: {provide: MockClass, useClass: ServerClass}

Is my understanding correct regarding this pattern?

@MarkPieszak
Copy link
Member

Yes, basically you're giving a "dummy" class, that either client or server then override with their own (in provide) implementation. You just need a base structured class that each correspond with.

We have plenty of documentation we need to add, for now changes keep coming so quickly it's hard to keep up. But it's definitely on the to do list!

@dimitrovs
Copy link
Author

I was able to do it with an interface:

import {CanActivate} from "@angular/router";  
import { OpaqueToken } from '@angular/core';  

export let AUTH_GUARD = new OpaqueToken('auth.guard');   

export interface AuthGuard extends CanActivate {  
}

Then in the router config I just used the AUTH_GUARD. If you are injecting it in a constructor then you can use @Inject(AUTH_GUARD):
{ path: 'about', component: About, canActivate: [AUTH_GUARD] },

And at injection time (main.browser.ts):
{provide: AUTH_GUARD, useClass: ClientAuthGuard}

and main.node.ts:
{provide: AUTH_GUARD, useClass: ServerAuthGuard}

Also, to pass parameters to any one of the two classes, just injecting them in one (or both) constructor(s) works, if we add them to the providers array in the respective main.*.ts file(s). In my case I was able to pass the Express request to the ServerAuthGuard like this:

{provide: CLIENT_REQUEST, useValue: req},

where CLIENT_REQUEST is another OpaqueToken.

@MarkPieszak
Copy link
Member

Ah you're using it to prevent a Component from initializing if it's not authorized? Very nice!
I'll keep a note on this if you don't mind, would be a very good example of showcasing DI in the documentation somewhere. Thanks Stefan.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants