Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add request context to server service interface. #13

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

ddunkin
Copy link
Contributor

@ddunkin ddunkin commented Dec 19, 2018

The request context contains the express request and response. This allows the server implementation to validate the authorization, for example.

I'm interested in other ideas to address this issue. Seems like we rely on thread-local storage and/or per-request instances of the service implementation with ASP.NET, neither of which are idiomatic for node.js/express.

@ddunkin ddunkin requested a review from ejball December 19, 2018 16:29
@ddunkin
Copy link
Contributor Author

ddunkin commented Dec 19, 2018

cc @sportnak

@sportnak
Copy link

We probably shouldn't be passing the Response object through. Calling res.send() multiple times will error and the current implementation would swallow that.

@sportnak
Copy link

I'm currently doing [http(from: header)] authorization: string; to get the authorization in the request, and then each request gets the http clients I need using that authorization.

The request context contains the express request and response. This allows the server implementation to validate the authorization, for example.
@ddunkin
Copy link
Contributor Author

ddunkin commented Feb 21, 2019

Authentication is a cross-cutting concern that shouldn't need to be attached to every request, and especially not as a specific implementation of authentication. For example, I have a service that uses an API key in a header other than Authorization.

I passed the Response object so that the service implementation could send headers.

Another use case for this kind of API is distributed tracing. You might want some middleware that reads trace headers from the request, propagates them to dependencies, and adds them to responses.

This API isn't easily composable. E.g. how could I add an authentication middleware and a tracing middleware to all service calls? Is there a better way?

@ejball
Copy link
Contributor

ejball commented Feb 21, 2019

we rely on per-request instances of the service implementation with ASP.NET

Is there any way we can do something like this with Express? I don't know Express very well, but instead of calling createApp with a service, it could be called with a function that creates a service from the current request/response?

export function createApp(createService) {
  ...
  app.get('/widgets', function (req, res, next) {
    const request = {};
    ...
    return createService(req, res).getWidgets(request)
    ...

@sportnak
Copy link

If I'm tracking correctly, we do this in the ChmsAPI to pass authentication. We instantiate a new http client with the authorization headers from the request.

https://git/Logos/ChmsApi/blob/master/src/chmsService.ts#L285

If the req.header function were passed into the request object, it'd be easier to grab those at will in an implementation. As far as other middleware, what I think you're talking about is tracing requests that propagate information to other services not directly related to the actual request. If so, we could do something like this and add more app.use statements?

https://git/Logos/ChmsApi/blob/master/server.ts#L18

Let me know if I'm missing something here.

@ejball
Copy link
Contributor

ejball commented Feb 21, 2019

As @ddunkin mentioned, having an authorization property on each method request is not how Facility was intended to be used.

In my example, createService would be responsible for passing the authorization information from the Express request to the per-request ChmsService instance.

@sportnak
Copy link

having an authorization property on each method request is not how Facility was intended to be used.

Right, I was thinking that headers could be passed in as part of the request object that goes down to the service. In that way, you can use different headers in different requests. This could be done in the createService function described above to limit what's passed in, but I'm not sure it makes sense for every user of Facility to have to implement something like that. It would make sense as an option for some other weird properties, but I think when I'm building an express app, I expect all the headers to be available.

@ejball
Copy link
Contributor

ejball commented Feb 21, 2019

I still feel strongly that the interface should be the same for the client and the server, which is one of the core architectural principles of Facility. The ideal service interface implementation is entirely abstracted from the web service framework. I'm not yet convinced that my suggestion would be an undue burden on implementors.

@ddunkin
Copy link
Contributor Author

ddunkin commented Feb 22, 2019

Like that? 32cb5b8

@ejball
Copy link
Contributor

ejball commented Feb 22, 2019

I love it!

@sportnak
Copy link

Yeah this makes sense. Pretty similar to how we're using it now, and the interface is the same for client and server still. 👍

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

Successfully merging this pull request may close these issues.

3 participants