34
loading...
This website collects cookies to deliver better user experience
$ npm i -g @nestjs/cli
$ nest new nestj-api-graphql-code-first
$ cd nestj-api-graphql-code-first
// start the application
$ npm run start:dev
localhost:3000
to verify that hello world is displayed.version: "3"
services:
db:
image: postgres
restart: always
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: pass123
POSTGRES_DB: postgres
$ npm i @nestjs/graphql graphql [email protected]
GraphqlOptions
class for GraphQL settings, as follows:import { GqlOptionsFactory, GqlModuleOptions } from '@nestjs/graphql';
import { Injectable } from '@nestjs/common';
@Injectable()
export class GraphqlOptions implements GqlOptionsFactory {
createGqlOptions(): Promise<GqlModuleOptions> | GqlModuleOptions {
return {
installSubscriptionHandlers: true,
autoSchemaFile: 'src/schema.gql',
};
}
}
schema.gql
file to be generated, you can call it whatever you want, the important thing is to prefix it with *.gql
.GraphQLModule
in AppModule
:@Module({
GraphQLModule.forRootAsync({
useClass: GraphqlOptions,
}),
})
export class AppModule {}
$ npm install --save @nestjs/typeorm typeorm mysql
.env
files (environments)$ npm install --save @nestjs/config
TypeOrmModule
and ConfigModule
in AppModule
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module ({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forRootAsync({
useFactory: () => ({
type: 'postgres',
host: process.env.DATABASE_HOST,
port: +process.env.DATABASE_PORT,
username: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
autoLoadEntities: true,
synchronize: true,
}),
}),
],
})
export class AppModule {}
DATABASE_HOST=localhost
DATABASE_USER=postgres
DATABASE_PASSWORD=pass123
DATABASE_NAME=postgres
DATABASE_PORT=5432
TypeOrmModule
here, make sure Docker is running with docker compose up
..env
matches the one you have in your docker-compose file.users.entity.ts
:import {
Entity,
PrimaryGeneratedColumn,
Column,
} from 'typeorm';
import { Field, ID, ObjectType } from '@nestjs/graphql';
@Entity()
@ObjectType()
export class Users {
@Field(() => ID)
@PrimaryGeneratedColumn()
id: number;
@Field()
@Column()
name: string;
@Field()
@Column()
username: string;
@Field()
@Column()
email: string;
@Field()
@Column({ length: 60 })
password: string;
}
CreateUserInput
:import { Field, InputType } from '@nestjs/graphql';
import { IsEmail, IsNotEmpty, IsString, MaxLength } from 'class-validator';
@InputType()
export class CreateUserInput {
@Field()
@IsString()
readonly name: string;
@Field()
@IsEmail()
readonly email: string;
@Field()
@IsString()
@MaxLength(40)
readonly username: string;
@Field()
@IsNotEmpty()
@IsString()
@MaxLength(60)
password: string;
}
$ npm i @nestjs/mapped-types
CreateUserInput
class:import { InputType, PartialType } from '@nestjs/graphql';
import { CreateUserInput } from './create-user.input';
@InputType()
export class UpdateUserInput extends PartialType(CreateUserInput) {}
main.ts
file as follows:import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
forbidNonWhitelisted: true,
transformOptions: {
enableImplicitConversion: true,
},
}),
);
await app.listen(3000);
}
bootstrap();
$ nest g module users
$ nest g service users
$ nest g resolver users
UsersModule
, UsersService
, and UsersResolver
inside.import { ArgsType, Field, Int } from '@nestjs/graphql';
import { Max, Min } from 'class-validator';
@ArgsType()
export class UsersArgs {
@Field(() => Int)
@Min(0)
offset = 0;
@Field(() => Int)
@Min(1)
@Max(50)
limit = 25;
}
UsersService
:import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import * as bcrypt from 'bcrypt';
import { Repository } from 'typeorm';
import { CreateUserInput } from './dto/create-user.input';
import { UpdateUserInput } from './dto/update-user.input';
import { UsersArgs } from './dto/users.args';
import { Users } from './entities/users.entity';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(Users)
private readonly usersRepository: Repository<Users>,
) {}
public async findAll(usersArgs: UsersArgs): Promise<Users[]>
{
const { limit, offset } = usersArgs;
return this.usersRepository.find({
skip: offset,
take: limit,
});
}
public async findOneById(id: string): Promise<Users> {
const user = await this.usersRepository.findOne(id);
if (!user) {
throw new NotFoundException(`User #${id} not found`);
}
return user;
}
public async create(createUserInput: CreateUserInput): Promise<Users> {
createUserInput.password = bcrypt.hashSync(createUserInput.password, 8);
const user = this.usersRepository.create({ ...createUserInput});
return this.usersRepository.save(user);
}
public async update(
id: string,
updateUserInput: UpdateUserInput,
): Promise<Users> {
updateUserInput.password = bcrypt.hashSync(updateUserInput.password, 8);
const user = await this.usersRepository.preload({
id: +id,
...updateUserInput,
});
if (!user) {
throw new NotFoundException(`User #${id} not found`);
}
return this.usersRepository.save(user);
}
public async remove(id: string): Promise<any> {
const user = await this.findOneById(id);
return this.usersRepository.remove(user);
}
}
import { NotFoundException } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { CreateUserInput, UpdateUserInput, UsersArgs } from './dto';
import { UsersService } from './users.service';
import { Users } from './entities/users.entity';
@Resolver()
export class UsersResolver {
constructor(private readonly usersService: UsersService) {}
@Query(() => [Users])
public async users(@Args() usersArgs: UsersArgs): Promise<Users[]> {
return this.usersService.findAll(usersArgs);
}
@Query(() => Users)
public async user(@Args('id') id: string): Promise<Users> {
const user = await this.usersService.findOneById(id);
if (!user) {
throw new NotFoundException(id);
}
return user;
}
@Mutation(() => Users)
public async createUser(
@Args('createUserInput') createUserInput: CreateUserInput,
): Promise<Users> {
return await this.usersService.create(createUserInput);
}
@Mutation(() => Users)
public async updateUser(
@Args('id') id: string,
@Args('updateUserInput') updateUserInput: UpdateUserInput,
): Promise<Users> {
return await this.usersService.update(id, updateUserInput);
}
@Mutation(() => Users)
public async removeUser(@Args('id') id: string): Promise<any> {
return this.usersService.remove(id);
}
}
UsersModule
our service and the resolver, like this:import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersService } from './users.service';
import { UsersResolver } from './users.resolver';
import { Users } from './entities/users.entity';
@Module({
imports: [TypeOrmModule.forFeature([Users])],
providers: [UsersService, UsersResolver],
})
export class UsersModule {}
GraphQL
to see if everything works, but before we have to verify that starting our application the schema.gql
file is generated, once done, from the browser we go to the address http://localhost:3000/graphql
GraphQL Playground
, a UI that allows us to interact with our database.getUsers
{
users {
id
name
email
username
password
}
}
getUserById
{
user(id: "1") {
id
name
email
username
password
}
}
addUser
mutation {
createUser(createUserInput: {
name: "tony"
email:"[email protected]"
username: "tony_admin"
password: "secret123"
}) {
name
email
username
password
}
}
updateUser
mutation {
updateUser(
updateUserInput: {
name: "tony"
email: "[email protected]"
username: "tony_admin"
password: "secret123"
}
id: "1"
) {
name
email
username
password
}
}
removeUser
mutation {
removeUser(id: "3") {
name
email
username
password
}
}