There are many advantages to GraphQL but predictability is one of the best.
Send a GraphQL query to your API and get exactly what you need, nothing more and nothing less. GraphQL queries always return predictable results.
is one of the most popular libraries to build a GraphQL API today. It works well with Node and React. We will be using it. We will also use to define our schema with TypeScript classes.
From now, we are building our app. So let's remove the migration until we need it. We'll keep one for reference.
sequelize.sync({ force: true }) will automatically create the required tables for you.
Don't forget to change it to force: false when you got live.
001_example.ts
import { QueryInterface } from "sequelize";
module.exports = {
// change the database schema
async up(query: QueryInterface) {
// add migration here
},
// revert in case it goes wrong
async down(query: QueryInterface) {
// revert
}
};
Move from models to entities
The vast majority of GraphQL queries and mutations are to interact with the database.
To avoid repeating ourselves, we will define your models and GraphQL schema with the same files.
Rename models to entities to reflect the semantic of our files.
~/packages/api/src
$ mv models entities
Change sequelize.ts import path import * as models from "./entities";.
// ...
import { setLinkEntity } from "../containers";
// ...
class Link extends Model<Link> {
// ...
}
setLinkEntity(Link);
export { Link };
and use it in our resolver
Pagination
Results should always be paginated for performance reasons. It's good practice to add it at the beginning.
We are going to create 2 helpers in routers/GrapqhQL.
The first one, PaginatedResponse.ts, generate a new class with to attributes:
items the data returned. In this case, it will be Link.
total the amount of items available to query.
hasMore will be true if you can request more items.
PaginatedResponse.ts
import { ClassType, ObjectType, Field, Int } from "type-graphql";
export function PaginatedResponse<TItem>(TItemClass: ClassType<TItem>) {
// `isAbstract` decorator option is mandatory to prevent registering in schema
@ObjectType({ isAbstract: true })
abstract class PaginatedResponseClass {
// here we use the runtime argument
@Field(type => [TItemClass])
// and here the generic type
items: TItem[];
@Field(type => Int)
total: number;
@Field(type => Boolean)
hasMore: Boolean;
}
return PaginatedResponseClass;
}
The second one, PaginatedArgs.ts, adds query arguments: