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
Upgrade to Fastify v3 #85
Conversation
Would you mind to include those two examples in the README? |
Also, CI is failing everywhere. Plus, can you drop Node 6 and 8? Thanks. |
@thomheymann are you aware that this work is already done in this PR here: #81? I'm happy to let you contribute to that branch if you'd like to complete the PR but I believe I was waiting to publish it when the first v3 release candidate was released |
Hi Ethan, I wasn't aware of the PR #81 But I think you're going to run into the same typing issues with HTTP2 Fastify instances. |
Alright cool I'm in favor of this pr then. I'll do a proper review now 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good work so far. keep it up!
test/types.test.ts
Outdated
server.register(testPluginWithAsync) | ||
|
||
// Register with HTTP2 | ||
const serverWithHttp2: FastifyInstance< |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't need to specify these generics any longer. Let me know if removing them causes issues and I'll jump in and try and figure out whats up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't need to specify the generics but if I remove them I get HTTP types, not HTTP2 types.
I think we might need to look at the types themselves.
When authoring a plugin, we will not know what generics will be passed into FastifyInstance
so maybe the types need to cater for that?
e.g. FastifyPlugin<Server = http.Server & https.Server & http2.Http2Server>
The other issue I find strange is that server type is determined by fastify options. If https options are passed in, the server is of type https. If http2 boolean is passed in, the server is of that type. Shouldn't the types reflect that mechanism?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not exactly, the server types are supposed to be inferred based on the options object. The generics only exist if you want to extend the types of those servers, request, or responses. See here:
This is how the fastify()
method is defined in the next
types (if you're curious its using discriminant unions and function overloads to achieve it).
Fastify-Plugin should forward the generic properties through to the underlying instance, and it should also enable the user to omit them if they are not decorating those generic parameters
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, the server type is correctly inferred, that's great!
I'm still not clear how the FastifyPlugin
type is supposed to be used though.
Plugins are defined like so:
export const testPlugin: FastifyPlugin = fp(
function (fastify, _options, _next) {
console.log(fastify) // Is now of type `FastifyInstance<Server, IncomingMessage, ServerResponse, FastifyLoggerOptions<Server, IncomingMessage, ServerResponse>>`
},
{},
)
How will TypeScript know what options have been passed into fastify
? The fastify instance hasn't even been created at that point.
Consequently in user land, the following line is failing because of the defaults used by FastifyPlugin
type:
const serverWithHttp2 = fastify({ http2: true });
serverWithHttp2.register(testPlugin) // Argument of type 'FastifyPlugin<{}, Server, IncomingMessage, ServerResponse>' is not assignable to parameter of type 'FastifyPlugin<{}, Http2Server, Http2ServerRequest, Http2ServerResponse>'.ts(2345)
Can you explain how to make this work correctly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm this is a tough challenge. Let me check this out locally and start investigating.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@thomheymann do you want to try making the changes I recommended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to just leave the FastifyPlugin
instance type as the ServerIntersection
by default? It reflects the reality of plugin authors not knowing what exact server type will be used. For those plugins that depend on a specific server or modified request/response objects those should be able to be passed in but most plugins will be generic.
I've had a stab here at this here:
https://www.typescriptlang.org/play/index.html?ssl=113&ssc=2&pln=108&pc=1#
-
I mocked http/https/http2 namespaces as the playground couldn't find dependencies
-
FastifyPlugin
instance type is now union of all server types (its called intersection but it's a union, worst naming in typescript ever):interface FastifyPlugin<Options, Server extends ServerIntersection = ServerIntersection> { ( instance: FastifyInst<ServerIntersection>, opts: Options, next: () => void ): void; }
-
Plugin authors get correct instance type:
// Generic plugin const p4: FastifyPlugin<{}> = (inst, opts, next) => { console.log(inst.serverRaw.type) // "http" | "https" | "http2" | "https2" } // Specific plugin const p3: FastifyPlugin<{}, https.Server> = (inst, opts, next) => { console.log(inst.serverRaw.type) // "https" }
-
Userland Fastify instance type is correctly inferred based on options
-
Userland plugin registration works without typing errors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems a good idea to me but my TS is far from good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this looks good. I'm happy shipping this now and if things change in the future we can of course change it ourselves.
Yeah this is one of those edge cases that is really hard to solve correctly because it wouldn't happen when using TS from the ground up. If I have the opportunity I'll pass this along to the TS team for consideration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR has been updated but will fail until corresponding Fastify PR has been merged in:
fastify/fastify#2183
c7fc869
to
5902a02
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
@Ethan-Arrowood can you take a look? |
5902a02
to
5e3bcf7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀
Need to get this one in first to fix build - Travis is bogged: |
@mcollina This isn't going to work in Node 6 unless Fastify is transpiled and published (atm we're pointing to
|
This branch should target node 10+, we 'll release it as a major. |
ok this can be merged in once Fastify v3 has been released outstanding tasks: |
This PR upgrades
fastify-plugin
to Fastify v3. The only changes were TypeScript related but I also aligned the filenames so that implementation and declaration files are consistent.I have followed the new TypeScript guide here: https://github.com/fastify/fastify/pull/1966/files?short_path=17177d7#diff-17177d7eb9ef1a38f00590c051d2b873
However, I am not sure if the
FastifyPlugin
interface is correct as its requires knowledge of server, request and response types of the fastify instance at build time of the plugin. We don't know what the fastify instance looks like at build time though.@Ethan-Arrowood - Can you have a look at the
test/types.test.ts
? I have added a test for this case so build currently failsExample plugin and usage with new
FastifyPlugin
typeExample plugin with HTTP2 Fastify instance
Yes, we could cast to unknown first and then to HTTP2 version of
FastifyPlugin
but I don't think that's a good type system:Might be missing something, let me know how you want this to work.
Checklist
npm run test
andnpm run benchmark