Replies: 2 comments 3 replies
-
|
Sounds really interesting. Will think on it a bit. I think we should start with the ideal and work backwards. |
Beta Was this translation helpful? Give feedback.
-
|
I'm having to refresh my memory since I only touched on simple-rest for a split second before never really getting to take advantage of it, but it looks like e.g. for ValidatedMethod they avoided monkey-patching by using mixins: const method = new ValidatedMethod({
name: 'method',
mixins: [RestMethodMixin],
validate: ...,
restOptions: {
url: '/my-custom-url',
// any other options
},
run() {
return 5;
}
});Alas, the important part is inside that: https://github.com/stubailo/meteor-rest/blob/devel/packages/rest-method-mixin/rest-method-mixin.js SimpleRest.setMethodOptions(options.name, options.restOptions);... which is used for monkey patching https://github.com/stubailo/meteor-rest/blob/devel/packages/rest/rest.js#L99 Meteor.method = function (name, handler, options) {
if (!SimpleRest._methodOptions[name]) {
SimpleRest.setMethodOptions(name, options);
} else if (options) {
throw Error('Options already passed via setMethodOptions.');
}
// ... more stuff here
}The var insideDefineMutationMethods = false;
var oldDMM = Mongo.Collection.prototype._defineMutationMethods;
Mongo.Collection.prototype._defineMutationMethods = function () {
insideDefineMutationMethods = true;
oldDMM.apply(this, arguments);
insideDefineMutationMethods = false;
};(I think that might be a step too far and it's probably better to just focus on user-declared methods and pub/sub and make things opt-in, otherwise forking simple-rest and getting it to work with Meteor v3 + easy-schema might be simpler) So basically it seems to work how I could imagine, just wrap calls and before registering the method make sure you register the API endpoint + set up all the OpenAPI stuff. Some problems I still haven't found solutions for:
Using jam:method and jam:pub-sub as inspiration, maybe some clever use of adding new properties to globals or otherwise riffing on existing APIs could be used to make it easy to migrate an existing codebase and keep it explicit which code runs in which environment, for example: import { Rest } from 'something:rest'
// or Meteor.methods.rest({ ... })
Rest.methods({
// normal methods just assume post semantics by default
async 'user.incrementViewCount'() { .... },
// wrap in object to add other config
'user.profile.update': {
/* method: 'PATCH',
path: '/user/:id/profile', */
// or use Golang style paths
path: 'PATCH /user/:id/profile',
// or infer from path: https://dev.to/bytimo/useful-types-extract-route-params-with-typescript-5fhn
params: { id: String },
// not required with jam:method at least
body: { name: Match.optional(String) },
/* responses: {
'200': { id: String, name: String },
}, */
// or just infer for simplicity's sake?
response: {
'200': { id: String, name: String },
},
remixInputs: (params, body) => ({ id: Number(params.id), ...body }),
// I'm just stealing this from ValidatedMethod and jam:method
async run({ id, name }) {
const user = await Rest.user()
if (user != ...) { ... }
// some DB operations
return profile
}
}
})
Rest.publish({ ... })I'm seeing a lot of opportunity to make this modular enough to extend/configure for different registration strategies of methods, and same for different kinds of schemas and reduce the coupling for easy-schema etc. E.g. Meteor.methods.rest.patchConfig({
schemaToOpenAPI(schema) {
if (isValibotSchema(schema)) { ... }
if (isJamSchema(schema)) { ... }
},
checkSchema(schema) {
if (isJamSchema(schema)) { ... }
// etc
},
// Oh no, did webapp get updated and it's now Hono under the hood and the maintainer's asleep?
registerEndpoint(options: RestEndpointOptions /* see above example */) {
WebApp.handlers.on(options.method, options.normalizedPath, ...myManualReplacementMiddlewares, ... /* etc */)
},
})
declare 'meteor/something:rest' {
// somehow merge a declaration for handling an arbitrary schema here
}This comment got out of hand, so I might go away and prototype something like After that, it might be a discussion of what things should be contributed directly to easy-schema (vs potential niche bloat), and what's a reasonable way to interop with everything. I'm imagining an API like:
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
This might get out of scope fast.
I'm in the early stages of a migration from Meteor to NestJS, as my team shifts towards an API-centric architecture. Two key selling points of NestJS - can attach it to an existing Express instance (e.g. Meteor's
webapppackage), and the OpenAPI doc generation from the same DTOs that are used for validation.But I was just thinking that this could be made idiomatic for Meteor with the tools available. Your package
jam:easy-schemais already able to generate JSON Schema for MongoDB (draft 4), which is a big chunk of the work IMO.OpenAPI versioning is a bit messy but 3.1 appears to be using draft 7. There's a breaking change in there but it seems to be pretty much
id -> $idand some semantics for numerical ranges.The tricky part is how to integrate this into the ecosystem.
simple:restandmeteor-restare interesting examples of Method & Publication reuse, but perhaps that's out of scope and would require modifications to things likejam:method.The simplest (to implement, and reason about) approach I can think of is essentially wrapping
WebApp.handlers....or anexpressrouter with a function that records the route path, method, metadata, etc, and builds it all into an OpenAPI spec.Something like:
Then later on:
Some additional thoughts:
params, especially if this went to another step and involved reusingjam:methoddefinitions for API endpoints somehow (too far ahead for me to imagine how to integrate that)jam:method, I believe that also supports Zod, so ideally whatever solution this might evolve into should be aligned and accept the same options.simple:restIMO is the ideal, but with more configuration on the method side. E.g. being able to dictate globally how paths should be split up, being able to mark certain methods asGET,PATCH,PUT, being able to give a method a HTTP path that has some path parameters and then transform the path parameters and json body into whatever format your method parameters normally come in, etc.Beta Was this translation helpful? Give feedback.
All reactions