Run Scaffold
This tutorial describes how to use the souls g scaffold
command to create a GraphQL CRUD API. If you need to review GraphQL Ruby, we recommend reading this graphql-ruby first.
Run the souls g scaffold_all command
When the migration is finished, db/schema.rb
will be updated.
The souls g scaffold_all
command is based on the type of db/schema.rb
with the files needed for CRUD.
The corresponding test is also automatically generated.
$ souls g scaffold_all
.
.
Created file! : ./app/graphql/types/edges/user_edge.rb
Created file! : ./sig/api/app/graphql/types/edges/user_edge.rbs
Created file! : ./app/graphql/types/connections/user_connection.rb
Created file! : ./sig/api/app/graphql/types/connections/user_connection.rbs
Created file! : ./app/graphql/resolvers/user_search.rb
Created file! : ./sig/api/app/graphql/resolvers/user_search.rbs
Created file! : ./spec/factories/users.rb
Created file! : ./spec/mutations/base/user_spec.rb
Created file! : ./spec/queries/user_spec.rb
Created file! : ./spec/resolvers/user_search_spec.rb
Created file! : ./spec/policies/user_policy_spec.rb
๐ Generated SOULs CRUD Files
11 files were automatically generated based on the database schema.
Please refer to the SOULs guide for details on the files automatically generated by souls g scaffold
.
souls g scaffold $MODEL_NAME
You can perform scaffold
on a single Model.
$ souls g scaffold user
Executing the souls test command
$ souls test
Finished in 0.22436 seconds (files took 1.35 seconds to load)
36 examples, 30 failures
Failed examples:
30 tests have failed out of 36 tests.
Define test data in FactoryBot
Next, a FactoryBot
that generates User
Model test data
apps/api/spec/factories/
Defined in.
The SOULs API / Worker uses Faker, FactoryBot, and Gimei to generate test files.
Faker
https://github.com/faker-ruby/faker
FactoryBot
https://github.com/thoughtbot/factory_bot
Gimei
https://github.com/willnet/gimei
When you actually share the app with the client, convert it to human-friendly data as much as possible.
require "gimei"
FactoryBot.define do
factory :user do
uid { Faker::Internet.password }
username { Gimei.kanji }
screen_name { Faker::Internet.unique.username }
last_name { Gimei.last.hiragana }
first_name { Gimei.first.hiragana }
last_name_kanji { Gimei.last.kanji }
first_name_kanji { Gimei.first.kanji }
last_name_kana { Gimei.last.katakana }
first_name_kana { Gimei.last.katakana }
email { Faker::Internet.unique.email }
tel { Faker::PhoneNumber.subscriber_number(length: 10) }
icon_url { "https://picsum.photos/200" }
birthday { Faker::Date.birthday(min_age: 18, max_age: 65) }
gender { Gimei.male }
lang { "ja" }
category { "user" }
roles_mask { 1 }
is_deleted { false }
end
end
FactoryBot.define do
factory :article do
association :user, factory: :user
title { Faker::Book.unique.title }
body { Faker::Quote.matz }
thumnail_url { Faker::Internet.url }
public_date { Time.now }
association :article_category, factory: :article_category
is_public { false }
just_created { false }
slug { Faker::Internet.password(min_length: 16) }
tags { %w[tag1 tag2 tag3] }
is_deleted { false }
created_at { Time.now }
updated_at { Time.now }
end
end
FactoryBot.define do
factory :article_category do
name { Faker::Books::CultureSeries.culture_ship_class }
tags { %w[tag1 tag2 tag3] }
is_deleted { false }
created_at { Time.now }
updated_at { Time.now }
end
end
FactoryBot.define do
factory :comment do
association :article, factory: :article
from { Faker::Games::SuperMario.character }
body { Faker::JapaneseMedia::StudioGhibli.quote }
is_deleted { false }
created_at { Time.now }
updated_at { Time.now }
end
end
Run the test again
$ souls test
Comment Model ใในใ
Comment ใใผใฟใๆธใ่พผใ
valid Comment Model
ArticleCategory Model ใในใ
ArticleCategory ใใผใฟใๆธใ่พผใ
valid ArticleCategory Model
Finished in 1.3 seconds (files took 1.28 seconds to load)
36 examples, 0 failures
Randomized with seed 43312
All 36 tests were successful.
Next, perform type checking.
$ souls check
Type checking files:
.......................
No type error detected.๐ง
To run tests and type checks at the same time, use the following:
$ souls test --all
In this way, tests are an integral part of the SOULs framework. Immediate detection of errors will greatly reduce overall development time.
Check CRUD API (Registration / Display / Update / Logical Delete / Delete)
Now the CRUD API for the User
table.
SOULs framework provides two native methods for deletion. Logical deletion sets the is_deleted
flag, effectively removing the object while keeping it in the database. Physical deletion removes the object from the database irretrievably.
Data registration, update, logical deletion, and physical deletion are defined in mutation/base
.
app/graphql/mutations/base/
The display of data is defined in queries
, resolvers
.
app/graphql/queries
app/graphql/resolvers
Information about data types
is defined in types.
app/graphql/types
Please refer to the SOULs guide for the details of the files.
Now let's take a look at the API generated by the souls g scaffold
command.
Registration --createUser Mutation
Let's execute the following query to confirm that User
data can be registered.
Sample query
mutation {
createUser(
input: {
uid: "uniq-id"
username: "SOULs"
email: "info@test.com"
}
) {
userEdge {
node {
uid
id
username
email
}
}
}
}
If successful, the following response will be returned:
{
"data": {
"createUser": {
"userEdge": {
"node": {
"uid": "uniq-id",
"id": "VXNlcjo0",
"username": "SOULs",
"email": "info@test.com"
}
}
}
}
}
View --userSearch Resolver
We use a resolver to retrieve registered data.
query {
userSearch(filter: { isDeleted: false }) {
edges {
node {
id
uid
username
email
}
}
nodes {
id
}
pageInfo {
hasNextPage
}
}
}
If successful, the following response will be returned:
{
"data": {
"userSearch": {
"edges": [
{
"node": {
"id": "VXNlcjo0",
"uid": "uniq-id",
"username": "SOULs",
"email": "info@test.com"
}
}
],
"nodes": [
{
"id": "VXNlcjo0"
}
],
"pageInfo": {
"hasNextPage": false
}
}
}
}
We have confirmed that data has been registered successfully.
Update --updateUser Mutation
Next, we can update data using the following query:
mutation {
updateUser(input: {
id: "VXNlcjo0"
username: "SOULs API"
}) {
userEdge {
node {
id
username
email
}
}
}
}
If successful, the following response will be returned.
{
"data": {
"updateUser": {
"userEdge": {
"node": {
"id": "VXNlcjo0",
"username": "SOULs API",
"email": "info@test.com"
}
}
}
}
}
The username
has been successfully updated.
Logical Delete --deleteUser Mutation
SOULs framework delete
sets the is_deleted
flag to true
. In the actual operation of the application, in order to prevent data loss due to incorrect operation by the user, is_deleted
is set to true instead of actual deletion.
Now let's execute the following query:
mutation {
deleteUser(input: { id: "VXNlcjo0" }) {
user {
id
username
email
}
}
}
If successful, the following response will be returned.
{
"data": {
"deleteUser": {
"user": {
"id": "VXNlcjo0",
"username": "SOULs API",
"email": "info@test.com"
}
}
}
}
is_deleted
flag is now true
.
Physical Delete --destroDeleteUser Mutation
In the SOULs framework, destroyDelete
Mutation actually deletes data.
mutation {
destroyDeleteUser(input: { id: "VXNlcjo0" }) {
user {
id
username
email
}
}
}
If successful, the following response will be returned.
{
"data": {
"destroyDeleteUser": {
"user": {
"id": "VXNlcjo0",
"username": "SOULs API",
"email": "info@test.com"
}
}
}
}
Data has been deleted.
Like the User
Model, the Artice
and ArticleCategory
are complete.
Please refer to the documentation for details on the required queries and parameters.
Click DOCS on the right to view the document.