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

Api v2 #14

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft

Conversation

significantotter
Copy link
Contributor

@significantotter significantotter commented Jan 25, 2023

This is a skeleton outline for an easy to maintain, easy to test, self-documenting v2 API written in typescript.

This API runs on its own node App and with its own tsConfig, although making heavy use of the generated prisma schema.

The core of the API is the use of openapi-backend to take an OpenAPI V3 spec and transform it into a self-validating API. I use two tools, prisma-json-schema-generator and json-schema-to-openapi-schema to include a JSONSchema7 spec generation out of the prisma schema, and then convert it to the OpenAPI format for immediate, automatic use in the documentation and auto-built API.

Whenever you implement a new resource, you create 4 files for it, a controller, a schema, a service, and a factory. The service provides the set of operations that can be performed on the resource. The schema defines the resource's path structure in the API, the controller defines the handlers for the api paths, and the factory provides you with a randomized generator for either seeding an environment or running automated tests (which haven't been set up yet). Finally, you do the unfortunate, slightly manual step of setting the boilerplate resource types in resourceTypes.d.ts.

Each of the controller, schema, and service implement an abstract version of themselves, meaning that there's nearly no code that needs to be implemented for a basic implementation of a resource. For more shared API operations, those abstract classes can be modified with extra functionality, which is then activated on their inheriting functions through the methods function which defines what API methods are used for the resource.

In the feat example, I included every api method from the abstract classes, as well as a custom, locally defined method for findByName(). As you can see, the controller, schema, and service for a feat are each under 50 lines of code, and 90% of that is in the custom method's implementation.

All of this is bundled together in the controllerBuilder (which is still a little messy and should probably be broken up into a few files). The controller builder wraps the generated paths from each resource in a single schema object with metadata about the API itself. It attaches the definitions for the resources that were generated by prisma, and it assigns the handlers to the generator. It also defines security tooling, validation, and error messages.

To run this locally, make sure your env's DB URL host is pointing to localhost, not docker internal host, and then run

npm run build
npm run build:openapi-schema
npm run run:api

It takes it a minute to connect to prisma, so your requests may not immediately respond!

"nodemon": "^2.0.2",
"prettier": "2.8.3"
}
"name": "wanderers-guide",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prettier?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still in the dev dependencies. It's just hard to see with the prettier formatting changes and the rebase.

contact: {
email: "[email protected]",
},
license: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to update this to ORC.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ORC isn't available yet unfortunately, but when it is we can look at updating this

@@ -27,7 +27,7 @@ services:
links:
- mysql
env_file:
- dev.env
- .env
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we will need to update the readme with the dev configs for docker

Copy link
Contributor

@fezproof fezproof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if jumping to this very heavy Open API approach is the best approach to start with when migrating this app. It involves a lot of abstraction which can be very hard to maintain, especially by a open team of people that don't have time to up-skill to help support it.
I can see how this approach could help with the API integration side, but you are offloading that effort to the maintainers.
Is there a way that this can be split up into more specific things, avoiding the inheritance and abstraction, and not implementing an API just yet. This seems to be trying to solve a problem before actually defining the problem itself.
There are some great things here, but doing one thing at a time will probably produce a better outcome :)

"sourceMap": true,
"outDir": "./dist",
"rootDir": "./",
"strict": false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should definitely be set to true. If we are building something from scratch, not having strict mode enabled would be a huge mistake as it is so hard to add later


const api = createApi({ prisma, resources: [feats] });

const app = express();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to use express for a completely new thing?
Express hasn't had a significant update in years and is actively slower than the alternatives.
Take a look at https://www.npmjs.com/package/fastify or even consider building this API with serverless architecture in mind.

contact: {
email: "[email protected]",
},
license: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ORC isn't available yet unfortunately, but when it is we can look at updating this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants