Yeah I'm also on the schema first side of the debate.
I think for me it comes down to a few key points:
- APIs are forever, the choice of language/framework is an implementation detail
- Constraining yourself to what can be represented in the specification is better than generating a specification from implementation that may not be capable of expressing the full details
- When working with diverse languages it provides a common ground/language for discussing API changes. Eg: if you have java backend, kotlin android, swift iOS, react/whatever web you can bring everyone together with the spec
- Subjective, but a good spec will include a bunch of documentation and examples that tend to create a lot of noise in the code. I personally prefer to keep this in the spec and the implementation smaller
I think the main counterpoint to this is that you can generate the spec and then take that and change your mind if you later change language/framework etc - it's not a one-way door.
My biggest bug bear is that regardless of spec first or implementation first, you should have something you write once and generate the rest of the glue from (eg: docs, client sdks). Writing each piece manually/independently always leads to drift and bugs.
(I'm working on my own little openapi -> typescript code generator over here https://github.com/mnahkies/openapi-code-generator - eventually plan to support more than typescript, and adding typespec support is something I'm currently considering)
Hey, nice work on openapi-code-generator, its output is very nice. I think you could probably package it up as a TypeSpec emitter without too much difficulty, by emitting OpenAPI and feeding it to your generator. I am doing a similar thing for a Kiota emitter I'm working on. We recently added an API to get the OpenAPI as a JS object which may be of help in this quest:
Thanks for the reference! This is essentially what I had in mind - allow typespec as input and transparently convert to openapi then feed to the existing process.
I suspect there's potential for some loss of information with this approach (I'm relatively new to typespec so not sure) but I plan to do this as a first pass and then consider a more direct approach later if I see gaps worth fixing.
Agreed. If the schema can also generate the service routes, models, serialization, etc, and you just have to maintain the business logic in the service, you get the spec matches the service benefits that way as well. Best of both worlds? People using gRpc seem to be 100% fine with schema first and generating the service stubs.
One of the key things with having the spec is that you can actually describe a lot more than you can with the various attributes and comments in the code. Especially things that are not as much service concerns but potentially client concerns or documentation concerns. You can also encapsulate reusable API patterns so you know different operations are following the same pattern.
The author didn't go into all the details but there are lots of ways in TypeSpec to separate the concerns of different consumers of the spec. There is a lot of opportunity and creative thinking that can be done here.
Yeah also schema-first here. I think this is the “easy vs simple” debate all over again.
Writing code first schema is very easy, but when you start _using_ that api as part of a greater system is where the approach starts falling short.
Schema first allows for great communication between teams - one team requires changes to an api service, they can hash it out with the api, and then go back and implement both the client _and_ server simultaneously.
The great benefit here is the inevitable back-and forth can be done together, as each side might need to adjust the api while they are implementing the client/server as often happens with engineering efforts. And thats a lot easier to do while each side is working on it rather than the usual one side is “done” and moves to another task and needs to go back and modify.
In fact at the time I built quite a nice system of generating typescript types for both client and server - https://github.com/ivank/laminar
I guess because the project tried to introduce strong typing and fp style to node http servers plus a few other ideas stolen from here and there, it tried to do too much and never really got traction.
In an org where the customers are internal teams it makes more sense to sit down together and define a schema first. Then the consumer and provider teams just go away and write the code concurrently without having to waste time talking to each other.
Wondering if you can generate your service stubs and your clients to use for testing from TypeSpec, could it be faster even in the prototyping/early stages to define your spec first? A la gRpc?