-
Notifications
You must be signed in to change notification settings - Fork 29
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
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
Question: Different I/O for different methods #29
Comments
Hello @glitch452 , Thank you for the question. Essentially, an endpoint currently can hold the only input and output schema. And a routing path can be attached to the only endpoint. I made
The variable behavior of the handler depending on the actual However, the endpoint I/O schema is still the only one, therefore I can offer you two solutions for your objective.
export const routing: Routing = {
v1: {
user: {
get: yourEndpoint1, // method: GET, input schema with id, output schema with properties
create: yourEndpoint2, // method: POST, input schema with properties, output schema with new id
}
}
}; So you will have the following independent paths like this:
You can specify multiple I/O object schemas using Here is an example: export const universalEndpoint = endpointsFactory
.addMiddleware(methodProviderMiddleware)
.build({
methods: ['get', 'post'],
input: z.object({ // for GET
id: z.string()
}).or(z.object({ // for POST
name: z.string(),
age: z.number(),
address: z.string()
})),
output: z.object({ // for GET
name: z.string(),
age: z.number(),
address: z.string()
}).or(z.object({ // for POST
id: z.number()
})),
handler: async ({input, options: {method}}) => {
if (method === 'get' && 'id' in input) {
// fetching the user from DB
return {
name: 'John Doe',
age: 23,
address: 'Baker Street 221B'
};
}
if (method === 'post' && !('id' in input)) {
// saving the user to db
return {
id: 101
};
}
throw createHttpError(400, 'Arguments mismatch with the method used');
}
}); I realize that it's probably not the best solution for you. I'm going to think a little bit on how I could make it more elegant. I hope something of that could help you. And if you have any idea or suggestion, don't hesitate to make a PR. |
@glitch452 I've prepared some improvements that I believe should resolve the issue. import {DependsOnMethod} from 'express-zod-api';
// the route /v1/user has two Endpoints
// which handle a couple of methods each
const routing: Routing = {
v1: {
user: new DependsOnMethod({
get: myEndpointForGetAndDelete,
delete: myEndpointForGetAndDelete,
post: myEndpointForPostAndPatch,
patch: myEndpointForPostAndPatch,
})
}
}; If you have some comments or ideas about this solution, I welcome you to the PR #32 |
Hey, thanks so much for the reply! I'm just getting back to this now. I'll go over it and let you know :) |
I looked it over and, this seems like a great solution. If I understand correctly, it allows a complete endpoint definition for each method on a specific route. That would let someone have specific input and output schemas, which clearly solves this problem, but it should also allow specific middleware or even a specific result handler to be configured for each method, which is great, since that enables maximum flexibility while maintaining the simplicity of the endpoint definitions. What I ended up doing, for now, was something similar to the suggestion 2. I set the input schema to be an empty object with passthrough enabled, then I used the method middleware to determine the method, then I parsed the input separately for each method. This is a little bit of a janky workaround, but it does get the job done! I haven't started working on the OpenApi docs yet, but being able to automatically generate documentation for the endpoints would be really nice, and it looks like this tool can do that too! I would assume that these workarounds would make the documents less helpful though, and defining specific inputs and outputs for each method would allow the docs to also show those details, which would be great! Just to give you some more background info, here's the general way we have our endpoints setup.
So, our routing looks a little weird, but it works! Here's how I set it up for one of our services: const v1_router: Routing = {
courses: {
summaries: courses_summaries, // Special case for a specific return format
query: course_query, // Special case with specific parameters required (returns 1 item)
':id': course,
},
schedules: {
generate: schedules_generate, // Special case that receives post data and does some computation
download: schedule_download_post, // Downloads (csv/ical) an anonymous schedule, which is assembled based on the post data
'': schedules, // Has 'get', 'post' assigned to it
':id': {
'': schedule, // Has 'get', 'patch', 'delete' assigned to it
download: schedule_download_get, // Downloads (csv/ical) a specific schedule that is saved in the Db
},
},
}; Thanks again for getting back to me on this and for actually putting in the work on the PR. I really like how you've architected this library, and your solution does seem to be just as elegant. ... Ps. If I do have some other use cases that come up, and I think it's something I could tackle, I'd totally be willing to create a PR! This one seemed a little involved and I wasn't sure if you were willing to open the tool up to be more generic or if you preferred to keep it more specific. |
the feature released in version |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Hi,
I've started trying to use this module to manage my endpoints since I love the philosophy of how it's setup. I have a question about a use case.
For an endpoint with multiple methods (i.e.
post
andget
) is it possible to have an input and output forpost
that is different than the input and output forget
? Or, I guess a way to attach different endpoint definitions to the same route would also work?The text was updated successfully, but these errors were encountered: