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

How to add A custom reponse object type? #4456

Closed
ghost opened this issue Nov 5, 2020 · 24 comments
Closed

How to add A custom reponse object type? #4456

ghost opened this issue Nov 5, 2020 · 24 comments

Comments

@ghost
Copy link

ghost commented Nov 5, 2020

How can I makemy response object of a custom type?

@dougwilson
Copy link
Contributor

Currently the request and response objects are from Node.js and subclasses to be Express. You can change this, and I can provide an example, but just need more information about what you are trying to do, exactly, so I can provide an example for you.

@ghost
Copy link
Author

ghost commented Nov 6, 2020

I guess the issue is, I have a router and when ever it calls a get request. I want the object to be of a custom type. The reason for that is because if I leave it as its default type, it will assume some properties of req are undefined, when they can't be. I guess another solution would be to use extend the router, but apparently that isn't possible in express 4.17.1

@dougwilson
Copy link
Contributor

What makes it not possible to extend the router? You can subclass it, and pass any type of request and response objects in to it. I can provide an example, but just need more information about what you are trying to do, exactly, so I can provide an example for you.

@ghost
Copy link
Author

ghost commented Nov 6, 2020

Oh, I was looking at this issue #2768 which said that the router cannot be subclassed.

@dougwilson
Copy link
Contributor

That answer may have been correct 5 years ago, but things change. I can better answer your question and/or provide an example, but just need more information about what you are trying to do, exactly.

@ghost
Copy link
Author

ghost commented Nov 6, 2020

const element = express.Router(); element.get('/property/:propertyName', (req:CustomType, res, next) => { if (req.sessionRequest) { req.sessionRequest.urlVariables.propertyName = req.params.propertyName; } return sessionEndpointExceptionHandler( defaultSessionEndpointLogic, COMMANDS.GET_ELEMENT_PROPERTY, )(req, res, next); });

Here is one of my routes what I would want is the request param of this route to be of a custom type so I can avoid unnecessary null checks, that's all. So in this case if req was a custom type, the if(req.sessionRequest) would not be needed.

@dougwilson
Copy link
Contributor

That sounds like a feature Express offers right out of the box. Can you share how you envisioning setting up that value that would be in (req.sessionRequest) and I can provide an example for how to make that happen in Express?

@ghost
Copy link
Author

ghost commented Nov 6, 2020

That sounds like a feature Express offers right out of the box. Can you share how you envisioning setting up that value that would be in (req.sessionRequest) and I can provide an example for how to make that happen in Express?

I'm sorry, I don't quite understand what exactly you want

@dougwilson
Copy link
Contributor

You said you want req.sessionRequest to be set to some object such that is would never be null thus to avoid null checks, right? Well, can you share how you would accomplish that, like what would req.sessionRequest be in that case, and how would it get the right values you want it to have?

@ghost
Copy link
Author

ghost commented Nov 6, 2020

Ah, yes of course. So, currently in the request object, sessionRequest is an optional paramater. If I change it to my custom object, it is guaranteed to exist, thus sparing me the null checks.

@dougwilson
Copy link
Contributor

Right. So I'm saying, can you post the implementation for how you are setting the value in your custom object? Here is an example for how to do this in Express generically, but if you can provide your method, I can update my example to be more specific:

Object.defineProperty(app.request, 'sessionRequest', {
  get: () => { /* return your type here */ }
})

@ghost
Copy link
Author

ghost commented Nov 6, 2020

Oh, I meant I wanted to set req to a customObject. In this case I would want(req:Pluma.Request). This would cause the session request to be surely defined and avoid null checks. I am sorry if I was unclear earlier, also thanks for the swift responses. So either way, all I am concerned is that the req.sessionrequest not be null

@dougwilson
Copy link
Contributor

Gotcha. So how are you constructing that custom object? Are you doing something like var customObject = new PlumaRequest(req) ?

@ghost
Copy link
Author

ghost commented Nov 6, 2020

const customObject: Pluma.Request = {
urlVariables: req.params,
parameters: req.body,
command: '',
};

@dougwilson
Copy link
Contributor

Ah. So you need your request object to be some kind of subclass of our request, or you cannot pass it into the router. This is because it won't have enough information there to actual perform the routing.

@ghost
Copy link
Author

ghost commented Nov 6, 2020

Right. So I'm saying, can you post the implementation for how you are setting the value in your custom object? Here is an example for how to do this in Express generically, but if you can provide your method, I can update my example to be more specific:

Object.defineProperty(app.request, 'sessionRequest', {
  get: () => { /* return your type here */ }
})

I can't use the above method as I am using a router for my many routes. Also, I should have mentioned this object is my custom object and it does sublcass request. const customObject: Pluma.Request = {
urlVariables: req.params,
parameters: req.body,
command: '',
};

@dougwilson
Copy link
Contributor

There is no method to provide a request object that is not a subclass of the HTTP request object. This is because the router needs the things like HTTP method and URL in order to route the request, so those have to be there in your object.

@ghost
Copy link
Author

ghost commented Nov 6, 2020

Yes, I forgot to mention, my object is a sublcass of the request object

@dougwilson
Copy link
Contributor

Gotcha. So if you have a class that is a subclass of the Express request object, a very straight-forward way to make all the request objects in your app is to do the following:

app.request = PlumaRequest.prototype

@ghost
Copy link
Author

ghost commented Nov 6, 2020

That's the issue here. I don't want all request objects to be of type PlumaRequest. I want only the request objects on a certain router to be of type. For example I have

const element = express.Router();

I want all the get routes of the element router to have the request as being typed PlumaRequest. Is that possible?

@dougwilson
Copy link
Contributor

Ah, ok, I apologize; that wasn't clear to me before. There are many different methods. For example, you can create a subclass of the router itself which changes the objects to be your type of request, but the easiest method is simply an anonymous function at the use time:

app.use((req, res, next) => element(new PlumaRequest(req), res, next))

@ghost
Copy link
Author

ghost commented Nov 6, 2020

Oh ,thanks I think it would suit my needs better if I could do it by extending the express router. If you could provide a small example that would be ideal. Also, thanks for the quick responses and you patience, I'm a bit new to coding.

@dougwilson
Copy link
Contributor

dougwilson commented Nov 6, 2020

So express.Router is a standard constructor, so you would extend it like you would any other object. Here is an example:

function PlumaRouter () {
  express.Router.call(this)

  // do whatever init you want to do here
}
utils.inherits(PlumaRouter, express.Router)

// your methods and such here
// you probably want to override handle if you are wanting to change the request type
PlumaRouter.prototype.handle = function (req, res, done) {
  express.Router.protototype.handle.call(this, new PlumaRequest(req), res, done)
}

// and later:
app.use(plumaRouter.handle.bind(this))
// or
app.use((req, res, next) => plumaRouter.handle(req, res, next))

But if you want the nice app.use(plumaRouter), then you need to make your subclass be that puesdo javascript type. This is not specific to the Express router, just any class you want to make in javascript where the instance is a function instead of an object.

function PlumaRouter () {
  function plumaRouter (req, res, next) {
    plumaRouter.handle(req, res, next)
  }
  Object.setPrototypeOf(plumaRouter, this)

  // do whatever init you want to do here, but not on "this", on "plumaRouter"
  return plumaRouter
}
utils.inherits(PlumaRouter, express.Router)

// your methods and such here
// you probably want to override handle if you are wanting to change the request type
PlumaRouter.prototype.handle = function (req, res, done) {
  express.Router.protototype.handle.call(this, new PlumaRequest(req), res, done)
}

// and later:
app.use(plumaRouter)

@ghost
Copy link
Author

ghost commented Nov 6, 2020

Thanks so much!

@ghost ghost closed this as completed Nov 6, 2020
@ghost ghost reopened this Nov 6, 2020
@ghost ghost closed this as completed Nov 6, 2020
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant