LogoLogo
Navigation
Advanced Javascript
Advanced Javascript
  • 😆Attribute Starts With Selector [name^="value"] (ok)
  • 🥹 Tìm hiểu về Map và Set trong javascript (ok)
  • 🫢 The Array.from() method returns an array from any iterable object. (ok)
  • 😍localeCompare() method compares two strings return sort order -1, 1,0 (for before, after, or equal)
  • 😍JavaScript Array some() method returns true (and stops) if the function returns true() (ok)
  • Add key value pair to all objects in array (ok)
  • 🥸Làm một sider tuyệt đẹp "Timed-Cards-Opening"
  • 🥸Scroll animations! How to add a flowing path like the Lusion site with SVG and Javascript (ok)
  • Chia sẽ code plugin tạo thời gian chờ tải cho nút download
  • 😛jQuery 1.9 .live,.delegate,.on is not a function (ok)
  • 😁Importing CSS Breakpoints Into JavaScript (ok)
  • The matchMedia() method returns a MediaQueryList with the results from the query. (ok)
  • Collect nhiều sách pdf (ok)
  • 😁Check device Agent chrome, firefox ... (ok)
  • === START Three.js and TypeScript ===
  • Setup Development Environment (ok)
  • === END Three.js and TypeScript ===
  • === START THREE.JS ===
  • 🥳Fundamentals - three.js manual
    • Light trong Three.js
  • == Start Nguyên tắc cơ bản ===
  • Nguyên tắc cơ bản
  • Thiết kế đáp ứng
  • nguyên thủy
  • 😅Điều chỉnh camera (ok)
  • 😅Điều chỉnh scale
  • 🥲Xử lý màn hình HD-DPI
  • 😃So sánh Mesh với Object3D
  • 😅Trục AxesHelper
  • 😅Tạo GridHelper
  • 😆MeshBasic, MeshLambert, MeshPhong, MeshToon, MeshStandard, MeshPhysical, Shader, RawShader
  • == End Nguyên tắc cơ bản ===
  • 🥰Bài viết mẫu thự hành tọa độ, quay (ok)
  • Giới thiệu HTML5 Canvas
  • Bài 1: Làm quen với môi trường 3D của ThreeJS
  • Bài 2: Dịch chuyển đối tượng 3D - Controls
  • Bài 3: makeup
  • Bài 4: Models loader
  • 😁Những trang học three.js
  • Source Code Example
  • === END THREE.JS ===
  • === START WebGL ===
  • 😇Trang học WebGL && Shador
  • 😅Tìm hiểu về OpenGL ES 2.0
  • Tìm hiểu về WebGL phần 1: thư viện đồ họa web.
  • Tìm hiểu WebGL Phần 2: Đi sâu vào cách code WebGL appication
  • Tìm hiểu WebGL Phần 3: Đi sau vào cách code WebGL appication - các ví dụ
  • Tìm hiểu WebGL Phần 4: Các ví dụ.
  • === END WebGL ===
  • 😃Getting started with systemjs full (ok)
  • Đọc thêm bài này Mô-đun ECMAScript và khả năng tương thích trình duyệt (ok)
  • 😖Thư viện chặn truy cập vào Devtool (ok)
  • === START JAVASCRIPT Vanila ===
  • 😄Làm cách nào để ngăn sự kiện onclick của cha mẹ kích hoạt khi nhấp vào con parent, child ? (ok)
  • 😁Bootstrap 5 - multi item carousel (ok)
  • Three dots ( … ) in JavaScript
  • "... Three Dots" đã thay đổi javascript như thếnào ?
  • Array-like objects, Chuyển đối tượng arguments thành array (ok)
  • 😇Making a short alias for document.querySelectorAll (ok)
  • JavasScript Siblings (ok)
  • JavaScript Modules Full (ok)
  • JavaScript select Element (ok)
  • === END JAVASCRIPT Vanila ===
  • Sử dụng async, await, bất đồng bộ lấy dữ liệu Pagination, sử dụng Deferred 👌 phần 2 (ok)
  • how to use multiple ternary operator in javascript, ?:, ?? (ok)
  • 😅[DATETIMEPICKER] jQuery Plugin Date and Time Picke Full (ok)
  • === START tutorial HYPERAPP ==
  • [HYPERAPP] Hyperapp - JavaScript micro-framework chỉ 1kB (ok)
  • [HYPERAPP] hyperapp-tutorial-step-1 (ok)
  • [HYPERAPP] hyperapp-tutorial-step-2 (ok)
  • [HYPERAPP] hyperapp-tutorial-step-3 (ok)
  • [HYPERAPP] hyperapp-tutorial-step-4 (ok)
  • === END tutorial HYPERAPP ==
  • Free and Open Source Web Builder Framework
  • 😁How to recursively fetch data from paginated API then combine into one array (ok)
  • 😆Create a form with dom with nested tags, Wrapping a set of DOM elements using JavaScript (ok)
  • 😇Array find, Tìm phần tử đầu tiên thỏa mãn điều kiện (ok)
  • 😁Array find, Tìm phần tử cuối cùng thỏa mãn điều kiện (ok)
  • Cách tích hợp bộ lọc select chọn nhanh Tỉnh, Thành & Quận, Huyện, districts, provinces (ok)
  • object with methods, you can simply call a method from the object returned. (ok)
  • Portfolio, Filter, Gallery, Tabmenu (ok)
  • JavaScript chạy bất đồng bộ như thế nào?, Microtask ,Macrotask, queueMicrotask bài viết hay (ok)
  • 😋Learn prototypejs 😒😒😒
  • === START JavaScript chuyên sâu ===
  • [JavaScript chuyên sâu] Higher order function trong JavaScript - phần 1 (ok)
  • [JavaScript chuyên sâu] - Higher order function - phần 2: closure, currying, callback
  • [JavaScript chuyên sâu] - So sánh Constructor Function và Factory Function
  • [JavaScript chuyên sâu] - 5 vai trò của Function: function, object, property, callback, constructor
  • [JavaScript chuyên sâu] : Đồng bộ và bất đồng bộ của JavaScript - phần 1: Callback
  • [JavaScript chuyên sâu]: Từ hàm IIFE tới Module Pattern
    • 😍IIFE=>Immediately Invoked Function Expression=>khởi tạo function & chạy ngay, import, export như nào
  • Tìm hiểu về Higher-Order Functions trong JavaScript
  • === END JavaScript chuyên sâu ===
  • QR-Card (ok)
  • === START DATATABLE ===
  • [DATATABLE] bộ lọc sử dụng các thẻ bên trong td matter.vn (ok)
  • 😁[DATATABLE] JQuery Datatables Editor - Alternative to the official one (ok)
  • Example: Datatables Add Edit Delete with Ajax, PHP & MySQL (ok)
  • [DATATABLE] fixedColumns, DataTable, Left and right fixed columns (ok)
  • [DATATABLE] Sử dụng thư viện dataTables.bootstrap.min.js && dataTables.bootstrap.min.js (ok)
  • [DATATABLE] DataTables.net with DataTableQueryBuilder sample input filter (ok)
  • [DATATABLE] How to use Tabledit plugin with jQuery Datatable in PHP Ajax (ok)
  • [DATATABLE] DataTables Custom Filter Demo (ok)
  • [DATATABLE] Datatable multiple checkbox demo (ok)
  • [DATATABLE] HTML5 export buttons (ok)
  • [DATATABLE] CodePen Home DataTable 2 Card view (ok)
  • [DATATABLE] DataTables - Column Search (ok)
  • [DATATABLE] CodePen Home dataTables conditional row and cell styling (ok)
  • [DATATABLE] DataTables example of styling Excel export(ok)
  • === END DATATABLE ===
  • 😅Bất ngờ về sử dụng Window History full 1 (ok)
  • 😁Bất ngờ về sử dụng Window History full 2, window.history.scrollRestoration,history.replaceState(ok)
  • workingHoursBetweenTimes, tính giờ làm việc, giờ làm thêm (ok)
  • 😅addDataToArray, cộng mảng đối tượng với điều kiện key == (ok)
  • You can get the number of days in a specified month (ok)
  • Lấy giá trị khác nhau đầu tiên, cuối trong một mảng Object (ok)
  • swiperjs.com (ok)
    • Swiper Slider (ok)
  • Một số cách viết ngắn gọn code trong JS phần 1 (ok)
  • Một số cách viết ngắn gọn code trong JS phần 2 (ok)
  • literal javascript, php (ok)
  • Bài toán kinh điển sử dụng three dots lấy tất cả các key của object, key same, plus (ok)
  • convert object to array javascript (ok)
  • ==== Start Google Sheet ====
  • Kintone width Appscript (ok)
  • [GOOGLE-SHEETS] Buttons in Google Sheets
  • [GOOGLE-SHEETS] thực hiện chuyển dữ liệu sang bản khác (ok)
  • [GOOGLE-SHEETS] method getRange (ok)
  • [GOOGLE-SHEETS] method getRange (ok)
  • Bài 1: Khai Báo Biến và Đọc Ghi Ô – Dải Ô (Cell / Range)
  • Bài 2: Các Hàm Lấy Giá Trị và Đặt Giá Trị Dải Ô getRange – getValues – setValues
  • Bài 3: Copy và Di Chuyển Dải Ô Sang Sheet khác
  • Bài 4: Vòng Lặp For
  • Bài 5: Di chuyển dòng từ Sheet này sang Sheet khác
  • [Help] – Chuyển Cột Sang Hàng (bỏ ô trống) (ok)
  • Bài 6: Câu lệnh điều kiện IF (ok)
  • Bài 7: Giới thiệu các Trigger App Script – onEdit onOpen
  • [Help] – Form nhập liệu đơn giản
  • Bài 8: Hộp thoại Dialog / Popup
  • Bài 9: Ghi công thức Google Sheet vào ô
  • Bài 10: Đọc Ghi Mảng (Array) App Script
  • Bài 11: Tạo xác thực dữ liệu phụ thuộc
  • Lấy Email người dùng đang hoạt động trên Google Sheet – getActiveUser
  • Bài 12: Liên kết Google Form – Sheet – Apps Script
  • [Series Email] Bài 1: Gửi Email bằng Apps Script cơ bản
  • [Series Email] Bài 2: Gửi Email Đính Kèm File – Hình Ảnh
  • [Series Email] Bài 3: Gửi Email Cho Danh Sách Nhập Vào Từ Google Sheet
  • Addon Email All in One | Email AI1 | RA MẮT BẢN THỬ NGHIỆM
  • [Series Email] Bài 4: Gửi Email Bcc Cho Danh Sách Nhập Vào Từ Google Sheet
  • [Series Email] Bài 5: Tạo Hộp Thoại Xem Email Trước Khi Gửi
  • [Series Email] Bài 6: Gửi Email Theo Template Cho Sẵn
  • [Series Email] Bài 7: Gửi Email Xác Nhận Điền Form (Email Confirmation)
  • [Series Email] Bài 8: Hẹn Giờ Gửi Email
  • SpreadsheetApp
  • Giới hạn các Service trong Apps Script
  • [CF] Lọc dải ô bao gồm dải ô khác
  • Cách lưu trữ trong Google Apps Script – PropertiesService
  • [CF] Custom Function Google Sheets là gì và Cách ‘cài đặt’
  • [CF] Tìm Ô – Có Giá Trị – Cuối Cùng Trong Cột – Google Sheets
  • [CF] Đếm số lần xuất hiện kí tự trong dải ô Google Sheets
  • [CF] Lọc dải ô không bao gồm
  • ==== End Google Sheet ====
  • [REDUCE] JavaScript Array reduce()
  • Merge object and split array by size, Trộn object và tách array theo size (ok)
  • Đặt điều kiện mới load js (ok)
  • Calculate working days between two dates in Javascript excepts holidays (ok)
  • Remove everything after a certain character remove replace (ok)
  • CodePen Home Image zoom on hover - auto run - view full (ok)
  • ======== Start Slider Revolution =======
  • How to start (ok)
  • Revolution Lightbox tham khảo
  • Mẫu và thực viện để thực hành (ok)
  • Tài liệu Slider Revolution Jquery 2.0 (ok)
  • Tài liệu Slider Revolution Jquery 4.1.2 (ok)
  • ======== End Slider Revolution =======
  • jQuery click / toggle between two functions (ok)
  • [TEXT ANIMATION] làm hiệu ứng chữ dòng trên xuất hiện trước rồi mới đến dòng dưới (ok)
  • Phát hiện phần tử xuất hiện ở màn hình, Detect element appearing on screen, view (ok)
  • what does !function in Javascript mean? (ok)
  • [WEBPACK] Một cách phân biệt khi bundle ra es5 hay es6 một ví dụ sử dụng webpack (ok)
  • Javascript Self Invoking Functions (ok)
  • ====== Start Convert ES5 class to ES6 class ====
  • VS Code tips: Convert ES5 class to ES6 class code action (ok)
  • ====== End Convert ES5 class to ES6 class ====
  • Get Substring between two characters using javascript (ok)
  • add Html Table rows data into JSON array Object (ok)
  • lightGallery, lightgalleryjs, Lightbox (ok)
  • same height (ok)
  • Hình ảnh :(
  • ============ Start serialize =============
  • jQuery serialize() Method (ok)
  • serialize width php mysql (ok)
  • serialize, serializeObject, serializeArray (ok)
  • How to access jQuery serialized data? (ok)
  • ============ End serialize =============
  • Sử dụng addQueryVar để thêm vào đường dẫn ajax (ok)
  • Cách tích hợp captcha style2.track360.xyz (ok)
  • Simple JavaScript Captcha Example (Client Side Captcha)
  • 😍Đoạn mã sử dụng translate.google.com (ok)
  • ========== Start [MultiLang] ===========
  • [MultiLang] MultiLang.js (ok)
  • [MultiLang] Localizing JavaScript apps with jQuery.i18n (ok) (full)
  • [MultiLang] jQuery i18n những điều nên biết (ok)
  • [MultiLang] How to Create a Multilingual Application using JavaScript
  • [MultiLang] Build multiple language website using jQuery and JSON based methods (ok)
  • [MultiLang] Switch Different Languages On The Webpage - jQuery multilang (ok)
  • [MultiLang] jquery-multilang (ok)
  • ========== End [MultiLang] ===========
  • [MINICOLORS] jquery.minicolors (ok)
  • jQuery - addClass ACTIVE--> set timeout --> cycle (ok)(online.vinmec.com)
  • WP Mapbox GL JS Settings key (ok)
  • Xử lý ảnh thiếu thuộc tính title, alt trên style2.track360.xyz (ok)
  • Register your schema (ok)
  • ========= Start Learn Graphql Website =======
  • 1. Query and Mutation types
  • ========= End Learn Graphql Website =======
  • [GRAPHQL] Tạo Database với Mysql (ok)
  • KẾT NỐI VỚI MYSQL – NODEJS – 05
  • 😍Quick start graphql (ok)
  • Hướng dẫn bắt đầu GraphQL với Node.js (Phần 1)
  • Hướng dẫn bắt đầu GraphQL với Node.js (Phần 2)
  • Cách bắt đầu với ứng dụng GraphQL, React, Apollo Client và Apollo Server
  • [Fullstack] Xây dựng forum bằng GraphQL, React, Apollo và Prisma - Part 1 (Application Introduction
  • 😍[Fullstack] Xây dựng forum bằng GraphQL, React, Apollo và Prisma - Part 2 (Backend - Project Setup a
  • [Fullstack] Xây dựng forum bằng GraphQL, React, Apollo và Prisma - Part 3 (Backend - Simple Mutation
  • [Fullstack] Xây dựng forum bằng GraphQL, React, Apollo và Prisma - Part 4 (Backend - Connect to Data
  • 😍Prisma Crud Full
    • 🥰Sử dụng kết hợp prisma.io với wordpress như nào?
    • [ERROR] gặp lỗi TypeError: Do not know how to serialize a BigInt (ok)
    • 😍Migrate MongoDB to MySQL using Prism Key Differences (ok)
  • Setting Up Prisma with MySQL: A Step-by-Step Guid
  • Tìm hiểu GraphQL, Xây dựng 1 GraphQL server với prisma
  • 🥹Đã có bài viết về sqlite, sqlite3 đầy đủ (ok)
  • 😍Querying Sequelize Full link sequelize.org (ok)
  • 😁Sqlite Sequelize Example (ok)
  • 😍CRUD with React and GraphQL Mysql (ok)
  • 😍A GraphQL Sqlite, sequelize Full (ok)
  • GraphQL in practice - Part 1: Xây dựng GraphQL server với Apollo Server, ExpressJS và MongoDB
  • GraphQL in practice - Part 2: Tạo ứng dụng GraphQL với Apollo Client và React
  • GraphQL in practice - Part 2: Tạo ứng dụng GraphQL với Apollo Client và React
  • TÌm hiểu về GraphQL
  • Cùng tìm hiểu về GraphQL
  • Simple Guidance For You In GraphQL
  • [GRAPHQL] Get started with Apollo Server (ok)
  • [GRAPHQL] Schema basics (ok)
  • [GRAPHQL] Subscriptions (ok)
  • [GRAPHQL] Unions and interfaces (ok)
  • Tham khảo: https://www.howtographql.com
  • Tìm hiểu GraphQL: Các khái niệm cơ bản (ok)
  • GraphQL Và Ưu Điểm Nổi Bật So Với Rest API?
  • Xây dựng server GraphQL với NodeJS (ok)
  • Tìm hiểu GraphQL
  • Xây dựng GraphQL server với Node.js
  • Ví dụ Tạo Restfull API - CRUD đơn giản với NodeJS, GraphQL (ok)
  • Sequelize with Node, Express & Mysql and it’s setup (ok)
  • Sequelize in Nodejs Part I
  • Sequelize in Nodejs Part II
  • Videos NodeJS + MySQL Database
  • NodeJS – Lưu trữ dữ liệu trên MySQL với Sequelize
  • Exploring The Node.js With MySQL Example Using Sequelize & Express
  • Tạo model, migration, seeds với Sequelize
  • Sử dụng passport với sequelize và MySQL
  • Tạo model, migration, seeds với Sequelize
  • GraphQL là gì? Bắt đầu với GraphQL
  • Xây dựng API sử dụng Laravel và GraphQL
  • How To Connect To MySql Database Using Sequlize In Express (Node) Application
  • Node.js MySQL Tutorial
  • Node.js Rest APIs example with Express, Sequelize & MySQL
  • Getting Started with Node, Express and Mysql Using Sequelize
  • [GRAPHQL] GraphQL – Công nghệ mới cho web developer
  • GraphQL là gì? Tìm hiểu về GraphQL (ok)
  • [GRAPHQL] Cùng tìm hiểu về GraphQL
  • Điều gì ẩn chứa bên trong $.event???
  • ===== Start Put JavaScript Design Patterns Into Practice (Videos) ========
  • 2.1. The Factory Pattern (ok)
  • 3.1. The Publisher-Subscriber Pattern (ok)
  • 3.2. The Strategy Pattern (ok)
  • Rời phần thử khỏi mảng sử dụng filter (ok)
  • 3.3. The Observer Pattern (ok)
  • 3.4. The Chain of Responsibility Pattern (ok)
  • 3.5. The Mediator Pattern (ok)
  • 3.6. The Iterator Pattern (ok)
  • ===== End Put JavaScript Design Patterns Into Practice (Videos) ========
  • ========== Start RequireJS Tutorial =======
    • Sử dụng RequireJS và AMD để module hóa code JavaScript (ok)
  • 😍Trình duyệt không có require, nhưng Node.js thì có. Với Browserify để trình duyệt cũng có (ok)
  • Sử dụng Bower để quản lý các thư viện code trong Laravel (ok)
  • RequireJS - Environment Setup (ok)
  • RequireJS - Configuration (ok)
  • RequireJS - AMD Modules (ok)
  • RequireJS - Defining Function (cách sử dụng require rất lạ) (ok)
  • RequireJS - Optimizer (ok)
  • ========== End RequireJS Tutorial =======
  • ========== Start jQuery Ui ======
  • Jquery Datepicker select multiple date ranges in one calender, button Reset (ok)
  • Tạo chức năng tự động hoàn tất nhập liệu với thư viện jQuery UI Autocomplete (Phần 1) (ok)
  • Draggable Widget, Droppable Widget (ok)
  • jQuery drag and drop (kéo thả bằng jQuery)
  • jQuery drag full (ok)
  • jQuery drop full (ok)
  • jQuery Resizable full (ok)
  • Tablesorter full (ok)
  • Live search through table rows (ok)
  • Loại bỏ một số cột không tìm kiếm trong Tablesorter (ok)
  • jQuery Sortable full, tablesorter (ok)
  • jQuery Selectable full (ok)
  • jQuery UI Sortable Tutorial - Save Positions With Ajax & PHP & MySQL (ok)
  • jQuery Drag and Drop TODO List with PHP MySQL (ok)
  • ========== End jQuery Ui ======
  • [TUTORIAL] TRÍCH XUẤT THÔNG TIN TỪ WEBSITE VỚI HTML AGLITITY PACK
  • ======== Start handlebars js =======
  • Sử dụng handlebars js
  • Handlebars nhỏ nhưng có võ
  • ======== End handlebars js =======
  • ==== Start JavaScript Tutorial ====
  • JavaScript Introduction
  • What is JavaScript
  • JavaScript Essentials
  • JavaScript Variables
  • JavaScript Operators
  • JavaScript Conditionals
  • JavaScript Loops
  • JavaScript Built-in Types
  • JavaScript Objects
  • JS Advanced Objects
  • JavaScript Arrays
  • JavaScript Functions
  • JavaScript Function Objects
  • JavaScript JSON
  • JavaScript Regular Expressions
  • Bôi màu cho một ký tự đặc biệt và chuỗi @EsportsArcadia Regular Expression (ok)
  • JavaScript Reference
  • ==== End JavaScript Tutorial ====
  • 🧐===== Start JavaScript Design Patterns ==
  • JavaScript Design Patterns
  • JavaScript Design Patterns – Explained with Examples
  • Js design pattern doFactory master (ok)
  • Chapter 5: jQuery Patterns
  • JavaScript Design Patterns (ok)
  • Abstract Factory (ok)
  • Builder (ok)
  • Factory Method (ok)
  • Prototype (ok)
  • Singleton (ok)
  • Adapter ( ok)
  • Bridge (ok)
  • Composite (ok)
  • Decorator (ok)
  • Facade (ok)
  • Flyweight (ok)
  • Proxy (ok)
  • Chain of Responsibility (ok)
  • Command (ok)
  • Interpreter (ok)
  • Iterator (ok)
  • Mediator (ok)
  • Memento (ok)
  • Observer (ok)
  • State (ok)
  • Strategy (ok)
  • Template Method (ok)
  • Visitor (ok)
  • ===== End JavaScript Design Patterns ==
  • ======== Start Backbone.js Tutorial Videos ======
  • Backbone.js Tutorial - 1 - Installation.mp4 (ok)
  • Backbone.js Tutorial - 2 - Introduction to Models (ok)
  • Backbone.js Tutorial - 3 - Model Attributes (ok)
  • Backbone.js Tutorial - 4 - Model Change Events ( ok)
  • Backbone.js Tutorial - 6 - Introduction to Views (ok)
  • Backbone.js Tutorial - 7 - (Views) Differerence between el and $el (ok)
  • Backbone.js Tutorial - 8 - (Views) Creating New HTML Elements (ok)
  • Backbone.js Tutorial - 9 - (Views) Using the Render Function (ok)
  • Backbone.js Tutorial - 10 - (Views) Events (ok)
  • Backbone.js Tutorial - 11 - Introduction to Collections (ok)
  • Backbone.js Tutorial - 12 - (Collections) Adding and Removing Elements (ok)
  • Backbone.js Tutorial - 13 - (Collections) Modifying Elements
  • Backbone.js Tutorial - 14 - (Collections) Events (ok)
  • ======== End Backbone.js Tutorial Videos ======
  • ====== Start Learn backbone.js tutorial from scratch for beginners =====
  • Backbone :)
  • 1. Learn backbone.js tutorial from scratch(Part 2) Features and Working Principle of backbone.js
  • 2. Learn backbone.js tutorial from scratch for beginners(Part 4) About el and $el in Backbone.js
  • 3. Learn backbone.js tutorial from scratch for beginners(Part 5) Underscore Templates in Backbone.js
  • 4. Learn backbone.js tutorial from scratch for beginners (Part 7) Delegate Events in backbone.js
  • 5. Learn backbone.js tutorial from scratch for beginners(Part 8) Introduction of models in backbone.
  • 6. Learn backbone.js tutorial from scratch for beginners(Part 9) Pass Model data to backbone.js View
  • 7. Learn backbone.js tutorial from scratch for beginners(Part 10) Model data to underscore.js templ
  • 8. Learn backbone.js tutorial from scratch for beginners(Part 11) Head back to underscore.js symbol
  • 9. Learn backbone.js tutorial from scratch for beginners(Part 12) Model Events in backbone.js
  • 10. Learn backbone.js tutorial from scratch for beginners(Part 13) Model Validation in backbone.js
  • 11. Learn backbone.js tutorial from scratch for beginners(Part 14) Model Change Events in backbone.j
  • 12. Learn backbone.js tutorial from scratch for beginners(Part 15) More Model Events and listenTo ev
  • 13. Learn backbone.js tutorial from scratch for beginners(Part 16) Model Inheritance in backbone.js
  • 14. Learn backbone.js tutorial from scratch for beginners(Part 17) Collection in backbone js
  • 15. Learn backbone.js tutorial from scratch for beginners(Part 18) Collection Events in backbone.js
  • 16. Learn backbone.js tutorial from scratch for beginners(Part 19) Collection to underscore.js templ
  • 17. Learn backbone.js tutorial from scratch for beginners(Part 20) Underscore js Methods in backbone
  • 18. Learn backbone.js tutorial from scratch for beginners(Part 21) Routing in backbone.js
  • 19. Learn backbone.js tutorial from scratch for beginners(Part 22) Parameterized Routing in backbone
  • 20. Learn backbone.js tutorial from scratch for beginners(Part 23) Handlebars templates in backb
  • ====== End Learn backbone.js tutorial from scratch for beginners =====
  • Giới thiệu Backbone.js (ok)
  • Backbone.localStorage thay thế Backbone.sync lưu vào window.localStorage thay vì vào máy chủ (ok)
  • Một ví dụ full LocalStorage với BackBoneJS (ok)
  • ========== Start Backbonejs Php Mysql =============
  • Full code backbonejs php mysql (ok)
  • Giao diện html để thực hành từ đầu (ok)
  • Xây dựng giao diện (ok)
  • Thực hiện chức năng crud add (ok)
  • Phân tích để tạo giao diên http://localhost/gulp/#crud/new 1.0
  • Phân tích để tạo giao diên http://localhost/gulp/#crud/new 1.1
  • Phân tích để tạo giao diên http://localhost/create/#crud/index 2.0
  • Chức năng thêm dữ liệu http://localhost/create/#crud/new (ok)
  • Lấy dữ liệu ra trang http://localhost/create/#crud/index (ok)
  • Chức năng cập nhật dữ liệu http://localhost/create/#crud/1/edit (ok)
  • ========== End Backbonejs Php Mysql =============
  • JQuery-Template (ok)
  • Learning JavaScript Design Patterns P.1 (ok)
  • Learning JavaScript Design Patterns P.2 (ok)
  • Learning JavaScript Design Patterns P.3 (ok)
  • Singleton design pattern PHP (ok)
  • Singleton Pattern javascript (ok)
  • Factory Pattern (ok)
  • Decorator Pattern (ok)
  • Creational Pattern (ok)
  • Constructor Pattern (ok)
  • Singleton Pattern (ok)
  • Module Pattern (ok)
  • Factory pattern (ok)
  • Built-in Object Factory (ok)
  • Iterator (ok)
  • Bridge Pattern (ok)
  • Composite Pattern (ok)
  • Một số Design Patterns có thể sử dụng trong Javascript – Phần 1 (ok)
  • Chém gió về JavaScript Design Pattern - Part 1(ok)
  • Chém Gió Về JavaScript Design Pattern Phần 2
  • Chém gió về JavaScript Design Pattern - Part 3
  • 4 Design Patterns trong Javascript mà bạn nên biết
  • Design Pattern trong JavaScript (ok)
  • Lebab chuyển mã ES5 của bạn thành ES6 / ES7. Nó hoàn toàn ngược lại với những gì Babel làm (ok)
  • Turn your ES5 code into readable ES6 (ok)
  • Thuộc tính :selected quá tuyệt cho sự lựa chọn (ok)
  • jQuery I want to add an active class to the linked ID of an anchor tag style2.track360.xyz (ok)
  • Keep URL unaffected when anchor link is clicked (ok)
  • [UI SLIDER] Ui slider with text box input (ok)
  • [SELECT2] version Select2 3.5.3 nhìn trực quan hơn (ok)
  • [SELECT2] keypress select2, enter key press keycode yp.vn (ok)
  • [SELECT2] Select2 Bootstrap Theme (ok)
  • [SELECT2] tags (ok)
  • [SELECT2] tokenSeparators (ok)
  • [SELECT2] click change value (ok)
  • [SELECT2] jQuery $.ajax options (ok)
  • [SELECT2] Full Options (ok)
  • [SELECT2] value placeholder (ok)
  • [SELECT2] Can thiệp vào templateResult (ok)
  • [SELECT2] làm lá cờ gắn trước text kiểu kool ngầu (ok)
  • [SELECT2] cam thiệp vào templateSelection (ok)
  • [SELECT2] thêm thẻ bọc vào lựa chọn ví dụ thẻ <strong/> (ok)
  • [SELECT2] opening when a result is selected (ok)
  • [SELECT2] Full Adapters hay (ok)
  • [SELECT2] Kiểu dữ liệu trả về cho giao diện dùng html & json (ok)
  • [SELECT2] sử dụng ngôn ngữ, i18n, language (ok)
  • [SELECT2] dropdownParent (ok)
  • [SELECT2] Hiểu submit trong javascript và nâng cấp sử dụng select 2, autocomplate (ok)
  • [SELECT2] Common problems Select2 does not function properly when I use it inside a Bootstrap modal
  • [SELECT2] Full Events (ok)
  • [SELECT2] lấy dữ liệu của wp, wordpress để thực hành (ok)
  • [JSONPLACEHOLDER SELECT2] Full Sử dụng website jsonplaceholder.typicode.com để thực hành (ok)
  • Sử dụng fetch trên console.log để get api test (ok)
  • jQuery.naturalWidth / jQuery.naturalHeight images natural Width Height Native Width (ok)
  • [SUBMIT ] form submit jquery (ok)
  • Tạo file package.json bằng lệnh (ok)
  • [TYPESCRIPT] tạo file tsconfig.json bằng lệnh (ok)
  • [TYPESCRIPT] cài đặt package chạy trực tiếp ts, tsx, ts-node (ok)
  • Object for Three Dots, Array for Three Dots (ok)
  • Cách giải thích Private Constructors & Singletons quá tuyệt (ok)
  • [TYPESCRIPT] Một số scripts hay được sử dụng trong typescripts (ok)
  • [TYPESCRIPT] A practical guide to TypeScript decorators exmaple (ok)
  • Object.getOwnPropertyDescriptor() (ok)
  • JavaScript — Property Descriptor && PropertyDescriptor (ok)
  • [TYPESCRIPT] Employing “Namespaces” in TypeScript to encapsulate your data
  • 😅[TYPESCRIPT] Một ví dụ sử dụng TypeScript Namespaces, xuất file use on browser (ok)
  • [NODEJS] object hóa một file trong javascript Nodejs - require, exports and module.exports
  • [TYPECRIPT] Omit type when extending an interface Cách loại trừ các thuộc tính khỏi giao diện (ok)
  • How TO - List Grid View (ok)
  • Javascript module, import, export, dễ ẹc, nhưng có thể bạn vẫn chưa biết
  • [BABEL] Giải thích gói babel (ok)
  • Cấu hình Webpack và Babel 7 cho React (ok)
  • ----------------- Start Kế thừa Prototype ngang và dọc -------------------
  • Kế thừa Prototype ngang và dọc
  • class, super, constructor (ok)
  • Kế thừa ngang giữa function (ok)
  • Ví dụ về kế thừa prototype ngang theo function constructor. Liên quan đến hàm call(), sẽ có bài chi
  • Kế thừa ngang giữa 2 object
  • Muốn tạo một class, object có tên k hác khi console.log?? (ok)
  • Ví dụ về Function constructor và object instance (ok)
  • Tất cả đều từ Function
  • ----------------- End Kế thừa Prototype ngang và dọc -----------
  • Easy Responsive Tabs to Accordion (ok)Demos
  • [ERROR] unable to read package/javascript (ok)
  • ------------Start Json-----------------
  • Cách để truyền dữ liệu dạng boolean trong Postman (ok)
  • ------------ End Json-----------------
  • ---------- start JSONP ---------------------
  • Cross-Domain Ajax Requests
  • 1. JSONP (JSON with padding)
  • 2. CORSCross-origin resource sharing (CORS) là một cơ chế đặc biệt cho phép resource đặt tại một do
  • 3. Proxy
  • JSONP là gì và tại sao nó được tạo ra? (ok)
  • 4. Javascript – Tạo script động và kĩ thuật JSONP (ok)
  • ----------- End JSONP --------------
  • Destructuring Assignment in ES6
  • Cơ chế bất đồng bộ trong javascript (ok)
  • jQuery.inArray()
  • website check call stack (ok)
  • Bài 6: Template Literals trong ES6 (ok)
  • ES6 Arrow Functions (ok)
  • Lập trình TypeScript (ok)
  • Uncaught ReferenceError: exports is not defined in filed generated by Typescript (ok)
  • Cách hoạt động của các module loader? (ok) một ví dụ kinh điển :)
  • RequireJS Cho Người Mới Bắt Đầu (ok) quá tuyệt
  • Tiny loaders tương tự REQUIREJS (Ok)
  • Javascript Module Loader – From the basic (ok)
  • ES6 Modules and CommonJS (Oke) Một ví dụ quý hơn vàng :(((
  • CommonJS là một module pattern hỗ trợ cho tất cả các phiên bản Node.js. Với CommonJS, JavaScript obj
  • ------------------------Start webpack ----------------------
  • [WEBPACK] Làm một ví dụ compile scss, sass bằng WEBPACK full (ok)
  • Webpack từ A đến Á: Webpack watch mode (ok)
  • Webpack từ A đến Á: Webpack dev server (ok)
  • Webpack từ A đến Á: Webpack output hash digest (ok)
  • Webpack từ A đến Á: Webpack multiple entry points (ok)
  • Webpack từ A đến Á: Webpack multiple file types per entry (ok)
  • Webpack từ A đến Á: Webpack import export module (ok)
  • Webpack từ A đến Á: Webpack source map (ok)
  • Webpack từ A đến Á: Webpack import jQuery (ok)
  • Webpack từ A đến Á: Webpack import jQuery - Bootstrap (ok)
  • Webpack từ A đến Á: Webpack import jQuery - Materialize
  • Webpack từ A đến Á: Code Splitting (ok)
  • Webpack từ A đến Á: Code Splitting (ok)
  • Webpack từ A đến Á: Webpack resolve alias - extensions
  • Config alias chuẩn trong webpack (ok)
  • Webpack từ A đến Á: Webpack Babel Loader (ok)
  • Webpack từ A đến Á: Webpack Eslint Loader (ok)
  • Webpack từ A đến Á: Webpack Url Loader (ok)
  • Webpack từ A đến Á: Webpack File Loader (ok)
  • Webpack từ A đến Á: Webpack Style Loader (ok)
  • Webpack từ A đến Á: Webpack Sass Loader (ok)
  • Webpack từ A đến Á: Html Webpack Plugin (ok)
  • Option chunks Html Webpack Plugin (ok)
  • Webpack từ A đến Á: Clean Webpack Plugin (ok)
  • What is the difference between @babel/core and babel-core? (ok)
  • [WEBPACK] 2. Webpack : Khởi Tạo Project (nghiepuit)
  • [WEBPACK] 3. Webpack : Apply Babel Cho Project (nghiepuit)
  • [WEBPACK] 4. Webpack : CSS Loader (nghiepuit)
  • plugin @babel/plugin-proposal-class-properties
  • [WEBPACK] 5. Webpack : Tạo Project ReactJS (
  • [WEBPACK] 7. Webpack : File Loader - Tích Hợp Bootstrap
  • [WEBPACK] 8. Webpack : Tích Hợp Jquery, React, Redux Devtools (nghiepuit)
  • [WEBPACK] 9. Webpack : Vendor Caching
  • [WEBPACK] 10. Webpack : CommonsChunkPlugin
  • [WEBPACK] 10. Webpack : CommonsChunkPlugin (ok)
  • [WEBPACK] Webpack series (ep3) - code splitting - chia code trong webpack (ok)
  • Compile SASS with Webpack into a CSS file (ok)
  • [WEBPACK] 11. Webpack : Optimize Khi Bundle template (ok)
  • [WEBPACK] 12. Webpack : Clean Project (ok)
  • [WEBPACK] 12+. Webpack : webpack-dev-server
  • [WEBPACK] Plugin HtmlWebpackPlugin (ok)
  • HashRouter vs BrowserRouter
  • [WEBPACK] Webpack giúp kết nối các module lại với nhau ( (ok)
  • [WEBPACK] Chú ý: @babel/preset-env dùng cho những gói cũ thay vì khai báo mới babel-preset-env (ok)
  • [WEBPACK]
  • [WEBPACK] webpack-dev-server (ok)
  • [WEBPACK] liên kết với trang Webpack (ok)
  • [WEBPACK] Webpack output hash digest (ok)
  • [WEBPACK] Webpack multiple file types per entry
  • [WEBPACK] Webpack import export module (ok)
  • [WEBPACK] Webpack source map (ok)
  • Simple use jQuery with TypeScript (ok)
  • [WEBPACK] Webpack import jQuery (ok)
  • [WEBPACK] Webpack import jQuery - Bootstrap (ok)
  • [WEBPACK] Webpack import jQuery - Materialize
  • [WEBPACK] Webpack từ A đến Á: Code Splitting
  • [WEBPACK] Webpack từ A đến Á: Webpack resolve alias - extensions
  • [WEBPACK] Config alias chuẩn trong webpack
  • [WEBPACK] Webpack từ A đến Á: Webpack Babel Loader
  • [WEBPACK] Webpack từ A đến Á: Webpack Eslint Loader
  • [WEBPACK] Webpack từ A đến Á: Webpack Url Loader (ok)
  • [WEBPACK] Webpack từ A đến Á: Webpack File Loader
  • [WEBPACK] Webpack từ A đến Á: Webpack Style Loader (ok)
  • [WEBPACK] Webpack từ A đến Á: Webpack Css Loader
  • [WEBPACK] Webpack từ A đến Á: Webpack Sass Loader
  • [WEBPACK] [SPITEST] Teach you how to use webpack to generate css sprites
  • Page learn webpack good
  • Remove unused CSS styles from Bootstrap using PurgeCSS (ok)
  • [WEBPACK] Webpack cho người mới bắt đầu (ok)
  • [WEBPACK] cấu hình output (ok)
  • [WEBPACK] Dùng webpack để sử dụng từ khóa import, export (ok)
  • [WEBPACK] Từ cơ bản đến nâng cao
  • [WEBPACK] Tăng Tốc Độ và Tối Ưu Hoá Website Bằng CSS Sprites (ok)
  • ------------------------ End webpack ----------------------
  • How to convert unordered list into nicely styled <select> dropdown using jquery? (ok)
  • 😆Lazy loading images using event handlers 1
  • 😄Layload ajax && background 2
  • jQuery Lazy 3
  • jQuery lazyload 4
  • Config lazySizesConfig lazysizes.min.js lazysizes(ok)
  • Lazy loading images using event handlers (ok)
  • GIỚI THIỆU THƯ VIỆN LAZYSIZES.JS ĐỂ LAZY LOAD ẢNH (PHẦN 1)
  • GIỚI THIỆU THƯ VIỆN LAZYSIZES.JS ĐỂ LAZY LOAD ẢNH (PHẦN 2)
  • GIỚI THIỆU THƯ VIỆN LAZYSIZES.JS ĐỂ LAZY LOAD ẢNH (PHẦN 3)
  • Native lazy-loading for the web (ok)
  • Tầm quan trọng của thuộc tính sizes, srcset trong thẻ img (ok)
  • Thực hành lazysizes.min.js
  • Check image img exits vieclam123.vn (ok)
  • Nestable - Drag & drop hierarchical list with mouse and touch compatibility (ok)
  • Cấu hình tawk chat web500.vn ( ok)
  • Cùng tìm hiểu plugin Jquery Validation
  • Tìm hiểu về Jquery Validation (Phần 1) (ok)
  • Tìm hiểu về Jquery Validation (Phần 2) (ok)
  • Tìm hiểu về hộp thoại Sweet alert 2
  • Multi-table,Multi table (ok)
  • SweetAlert2 getHtmlContainer (ok)
  • AJAX request preConfirm (ok)
  • sử dụng php kết hợp Sweetalert2 (ok)
  • Một ví dụ tuyệt vời Ajax SweetAlert for Live Data Deleting Rows in with PHP~MySQL~Ajax (ok)
  • SweetAlert makes popup messages easy and pretty (page learn) (kiể cũ)
  • sweetalert bản chuẩn (ok)
  • AJAX requests (ok)
  • sweetalert2 bản chuẩn (ok) cái này dùng hay hơn sweetalert (ok)
  • Toast (ok)
  • Email (ok)
  • jQuery trigger() Method
  • jQuery one() Method (ok)
Powered by GitBook

Navigation

  • Lionel

@Copyright 2023

On this page
  • Example 1 (https://github.com/gitlucaslima/zaros-crud)
  • — Step 1 getUsers
  • — Step 2 getUserById
  • — Step 3 createUser
  • — Step 4 updateUser
  • — Step 5 deleteUser
  • Practice 1
  • Example 2
  • graphql-example
  • Getting Started
  • Information
  • Demo
  • GraphQL vs. REST: Why Drop REST?
  • How to Start with GraphQL
  • What’s Next?

A GraphQL Sqlite, sequelize Full (ok)

https://sequelize.org/docs/v7/category/querying/

PreviousCRUD with React and GraphQL Mysql (ok)NextGraphQL in practice - Part 1: Xây dựng GraphQL server với Apollo Server, ExpressJS và MongoDB

Last updated 19 days ago

Example 1 ()

— Step 1 getUsers

package.json

{
  "name": "sequelize",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "dev": "nodemon src/server.ts"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "express": "^4.21.2",
    "mysql2": "^3.12.0",
    "sequelize": "^6.37.5"
  },
  "devDependencies": {
    "@types/dotenv": "^6.1.1",
    "@types/express": "^5.0.0",
    "@types/node": "^22.10.7",
    "dotenv": "^16.4.7",
    "nodemon": "^3.1.9",
    "ts-node": "^10.9.2",
    "typescript": "^5.7.3"
  }
}

.env

DB_NAME="database_test"
DB_USER="root"
DB_PASS=""
DB_HOST="localhost"

src\server.ts

import app from './app';
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Servidor rodando na porta ${PORT}`);
  console.log(`Documentação disponível em http://localhost:${PORT}/api/docs`);
});

src\app.ts

import express from 'express';
import userRoutes from './routes/userRoutes';
import sequelize from './config/database';
const app = express();
app.use(express.json());
app.use('/api', userRoutes);
sequelize.sync()
  .then(() => {
    console.log('DB Connected');
  })
  .catch((error: any) => {
    console.error('Erro ao conectar ao banco de dados:', error);
  });
export default app;

src\routes\userRoutes.ts

import { Router } from 'express';
import { getUsers } from '../controllers/userController';
const router = Router();
router.get('/users', getUsers);
export default router;

src\controllers\userController.ts

import { Request, Response } from 'express';
import User from '../models/user';
import { buildUserFilters } from './Filters/UserFilters';
import { UserDTO } from './Interfaces/getUserInterface';
import { UserQueryParams } from './Interfaces/UserQueryParams';
import { mapUserToDTO } from '../mappers/userMapper';
import { Mapper } from '../mappers/mapper';
export const getUsers = async (req: Request, res: Response): Promise<void> => {
  try {
    const filters = buildUserFilters(req.query as UserQueryParams);
    const users = await User.findAll({ where: filters });
    const userDTOs: UserDTO[] = Mapper.toDTOArray(users, mapUserToDTO);
    res.status(200).json(userDTOs);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuários', details: (error as Error).message });
  }
}

src\controllers\Filters\UserFilters.ts

import { Op } from 'sequelize';
import { UserQueryParams } from '../Interfaces/UserQueryParams';
export const buildUserFilters = ({ nome, idadeMin, idadeMax, email }: UserQueryParams) => {
  const filters: any = {};
  if (nome) {
    filters.nome = { [Op.like]: `%${nome}%` };
  }
  // Filtro por faixa de idade, se definido
  const minAge = idadeMin ? parseInt(idadeMin, 10) : undefined;
  const maxAge = idadeMax ? parseInt(idadeMax, 10) : undefined;
  if (minAge !== undefined || maxAge !== undefined) {
    filters.idade = {};
    if (minAge !== undefined) filters.idade[Op.gte] = minAge;
    if (maxAge !== undefined) filters.idade[Op.lte] = maxAge;
  }
  // Filtro por email
  if (email) { // Corrigido aqui
    filters.email = { [Op.like]: `%${email}%` };
  }
  return filters;
}

src\controllers\Interfaces\getUserInterface.ts

export interface UserDTO {
  id: string;
  nome: string;
  email: string;
  idade: number | undefined;
  ativo: boolean | undefined;
}

src\controllers\Interfaces\UserQueryParams.ts

export interface UserQueryParams {
  nome?: string;
  email?: string;
  idadeMin?: string;
  idadeMax?: string;
}

src\mappers\mapper.ts

export class Mapper {
  static toDTO<T, U>(entity: T, mapperFunction: (entity: T) => U): U {
    return mapperFunction(entity);
  }
  static toDTOArray<T, U>(entities: T[], mapperFunction: (entity: T) => U): U[] {
    return entities.map(mapperFunction);
  }
}

src\mappers\userMapper.ts

import User from "../models/user";
import { UserDTO } from "../controllers/Interfaces/getUserInterface";
export const mapUserToDTO = (user: User): UserDTO => ({
  id: user.id,
  nome: user.nome,
  email: user.email,
  idade: user.idade,
  ativo: user.ativo,
});

src\models\user.ts

import { DataTypes, Model } from 'sequelize';
import sequelize from '../config/database';
class User extends Model {
  public id!: string;
  public nome!: string;
  public email!: string;
  public idade?: number;
  public ativo!: boolean;
}
User.init({
  id: {
    type: DataTypes.UUID,
    defaultValue: DataTypes.UUIDV4,
    primaryKey: true,
    unique: true,
  },
  nome: {
    type: DataTypes.STRING,
    allowNull: false,
    validate: {
      len: [3, 255],
    },
  },
  email: {
    type: DataTypes.STRING,
    allowNull: false,
    unique: true,
    validate: {
      isEmail: true,
    },
  },
  idade: {
    type: DataTypes.INTEGER.UNSIGNED,
    allowNull: true,
  },
  ativo: {
    type: DataTypes.BOOLEAN,
    defaultValue: true,
  },
}, {
  sequelize,
  modelName: 'User',
  tableName: 'users',
  timestamps: true,
});
export default User;

src\config\database.ts

import { Sequelize } from 'sequelize';
import dotenv from 'dotenv';
dotenv.config();
const sequelize = new Sequelize(process.env.DB_NAME!, process.env.DB_USER!, process.env.DB_PASS!, {
  host: process.env.DB_HOST,
  dialect: 'mysql'
});
export default sequelize;

— Step 2 getUserById

src\routes\userRoutes.ts

import { Router } from 'express';
import { getUsers, getUserById } from '../controllers/userController';
const router = Router();
router.get('/users', getUsers);
router.get('/users/:id', getUserById);
export default router;

src\controllers\userController.ts

import { Request, Response } from 'express';
import User from '../models/user';
import { buildUserFilters } from './Filters/UserFilters';
import { UserDTO } from './Interfaces/getUserInterface';
import { UserQueryParams } from './Interfaces/UserQueryParams';
import { mapUserToDTO } from '../mappers/userMapper';
import { Mapper } from '../mappers/mapper';
export const getUsers = async (req: Request, res: Response): Promise<void> => {
  try {
    const filters = buildUserFilters(req.query as UserQueryParams);
    const users = await User.findAll({ where: filters });
    const userDTOs: UserDTO[] = Mapper.toDTOArray(users, mapUserToDTO);
    res.status(200).json(userDTOs);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuários', details: (error as Error).message });
  }
}
export const getUserById = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const user = await User.findByPk(id);
    if (!user) {
      res.status(404).json({ message: 'Usuário não encontrado' });
      return;
    }
    const userDTO: UserDTO = Mapper.toDTO(user, mapUserToDTO);
    res.status(200).json(userDTO);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuário', details: (error as Error).message });
  }
};

— Step 3 createUser

src\controllers\userController.ts

import { Request, Response } from 'express';
import User from '../models/user';
import { buildUserFilters } from './Filters/UserFilters';
import { UserDTO } from './Interfaces/getUserInterface';
import { UserQueryParams } from './Interfaces/UserQueryParams';
import { mapUserToDTO } from '../mappers/userMapper';
import { Mapper } from '../mappers/mapper';
export const getUsers = async (req: Request, res: Response): Promise<void> => {
  try {
    const filters = buildUserFilters(req.query as UserQueryParams);
    const users = await User.findAll({ where: filters });
    const userDTOs: UserDTO[] = Mapper.toDTOArray(users, mapUserToDTO);
    res.status(200).json(userDTOs);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuários', details: (error as Error).message });
  }
}
export const getUserById = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const user = await User.findByPk(id);
    if (!user) {
      res.status(404).json({ message: 'Usuário não encontrado' });
      return;
    }
    const userDTO: UserDTO = Mapper.toDTO(user, mapUserToDTO);
    res.status(200).json(userDTO);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuário', details: (error as Error).message });
  }
};
export const createUser = async (req: Request, res: Response): Promise<void> => {
  try {
    const { nome, email, idade, ativo } = req.body;
    const user = await User.create({ nome, email, idade, ativo });
    const userDTO: UserDTO = Mapper.toDTO(user, mapUserToDTO);
    res.status(201).json(userDTO);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao criar usuário', details: (error as Error).message });
  }
};

src\routes\userRoutes.ts

import { Router } from 'express';
import { getUsers, getUserById, createUser } from '../controllers/userController';
const router = Router();
router.get('/users', getUsers);
router.get('/users/:id', getUserById);
router.post('/users', createUser);
export default router;

— Step 4 updateUser

src\routes\userRoutes.ts

import { Router } from 'express';
import { getUsers, getUserById, createUser, updateUser } from '../controllers/userController';
const router = Router();
router.get('/users', getUsers);
router.get('/users/:id', getUserById);
router.post('/users', createUser);
router.put('/users/:id', updateUser);
export default router;

src\controllers\userController.ts

import { Request, Response } from 'express';
import User from '../models/user';
import { buildUserFilters } from './Filters/UserFilters';
import { UserDTO } from './Interfaces/getUserInterface';
import { UserQueryParams } from './Interfaces/UserQueryParams';
import { mapUserToDTO } from '../mappers/userMapper';
import { Mapper } from '../mappers/mapper';
export const getUsers = async (req: Request, res: Response): Promise<void> => {
  try {
    const filters = buildUserFilters(req.query as UserQueryParams);
    const users = await User.findAll({ where: filters });
    const userDTOs: UserDTO[] = Mapper.toDTOArray(users, mapUserToDTO);
    res.status(200).json(userDTOs);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuários', details: (error as Error).message });
  }
}
export const getUserById = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const user = await User.findByPk(id);
    if (!user) {
      res.status(404).json({ message: 'Usuário não encontrado' });
      return;
    }
    const userDTO: UserDTO = Mapper.toDTO(user, mapUserToDTO);
    res.status(200).json(userDTO);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuário', details: (error as Error).message });
  }
};
export const createUser = async (req: Request, res: Response): Promise<void> => {
  try {
    const { nome, email, idade, ativo } = req.body;
    const user = await User.create({ nome, email, idade, ativo });
    const userDTO: UserDTO = Mapper.toDTO(user, mapUserToDTO);
    res.status(201).json(userDTO);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao criar usuário', details: (error as Error).message });
  }
};
export const updateUser = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const { nome, email, idade, ativo } = req.body;
    const user = await User.findByPk(id);
    if (!user) {
      res.status(404).json({ message: 'Usuário não encontrado' });
      return;
    }
    const userDTO: UserDTO = Mapper.toDTO(await user.update({ nome, email, idade, ativo }), mapUserToDTO);
    res.status(200).json(userDTO);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao atualizar usuário', details: (error as Error).message });
  }
};

— Step 5 deleteUser

src\routes\userRoutes.ts

import { Router } from 'express';
import { getUsers, getUserById, createUser, updateUser, deleteUser } from '../controllers/userController';
const router = Router();
router.get('/users', getUsers);
router.get('/users/:id', getUserById);
router.post('/users', createUser);
router.put('/users/:id', updateUser);
router.delete('/users/:id', deleteUser);
export default router;

src\controllers\userController.ts

import { Request, Response } from 'express';
import User from '../models/user';
import { buildUserFilters } from './Filters/UserFilters';
import { UserDTO } from './Interfaces/getUserInterface';
import { UserQueryParams } from './Interfaces/UserQueryParams';
import { mapUserToDTO } from '../mappers/userMapper';
import { Mapper } from '../mappers/mapper';
export const getUsers = async (req: Request, res: Response): Promise<void> => {
  try {
    const filters = buildUserFilters(req.query as UserQueryParams);
    const users = await User.findAll({ where: filters });
    const userDTOs: UserDTO[] = Mapper.toDTOArray(users, mapUserToDTO);
    res.status(200).json(userDTOs);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuários', details: (error as Error).message });
  }
}
export const getUserById = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const user = await User.findByPk(id);
    if (!user) {
      res.status(404).json({ message: 'User not found' });
      return;
    }
    const userDTO: UserDTO = Mapper.toDTO(user, mapUserToDTO);
    res.status(200).json(userDTO);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuário', details: (error as Error).message });
  }
};
export const createUser = async (req: Request, res: Response): Promise<void> => {
  try {
    const { nome, email, idade, ativo } = req.body;
    const user = await User.create({ nome, email, idade, ativo });
    const userDTO: UserDTO = Mapper.toDTO(user, mapUserToDTO);
    res.status(201).json(userDTO);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao criar usuário', details: (error as Error).message });
  }
};
export const updateUser = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const { nome, email, idade, ativo } = req.body;
    const user = await User.findByPk(id);
    if (!user) {
      res.status(404).json({ message: 'User not found' });
      return;
    }
    const userDTO: UserDTO = Mapper.toDTO(await user.update({ nome, email, idade, ativo }), mapUserToDTO);
    res.status(200).json(userDTO);
  } catch (error) {
    res.status(500).json({ message: 'Error updating user', details: (error as Error).message });
  }
};
export const deleteUser = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const user = await User.findByPk(id);
    if (!user) {
      res.status(404).json({ message: 'User not found' });
      return;
    }
    await user.destroy();
    res.status(204).send();
  } catch (error) {
    res.status(500).json({ message: 'Error deleting user', details: (error as Error).message });
  }
};

Practice 1

package.json

{
  "name": "sequelize",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "dev": "nodemon src/server.ts"
  },
  "dependencies": {
    "@types/dotenv": "^8.2.3",
    "@types/express": "^5.0.0",
    "@types/node": "^22.10.7",
    "dotenv": "^16.4.7",
    "express": "^4.21.2",
    "mysql2": "^3.12.0",
    "nodemon": "^3.1.9",
    "sequelize": "^6.37.5",
    "ts-node": "^10.9.2",
    "typescript": "^5.7.3"
  }
}

src\server.ts

import app from "./app";
const PORT = process.env.PORT || 3000;
app.listen(PORT,()=> {
  console.log(`http://localhost:${PORT}/api`);
})

src\app.ts

import express from "express";
import userRouter from "./routes/userRoutes";
const app = express();
app.use(express.json());
app.use("/api",userRouter);
export default app;

src\routes\userRoutes.ts

import { Router } from "express";
import { getUserById, getUsers, createUser, updateUser } from "../controllers/userController";
const userRouter = Router();
userRouter.get("/users", getUsers);
userRouter.get("/users/:id", getUserById);
userRouter.post("/create", createUser);
userRouter.put("/update/:id", updateUser);
export default userRouter;

src\models\userModel.ts

import { DataTypes, Model } from "sequelize";
import sequelize from "../config/database";
class User extends Model {
  public id!: string;
  public nome!: string;
  public email!: string;
  public idade?: number;
  public ativo!: boolean;
}
User.init(
  {
    id: {
      type: DataTypes.UUID,
      primaryKey: true,
      unique: true
    },
    nome: {
      type: DataTypes.STRING
    },
    email: {
      type: DataTypes.STRING,
      unique: true
    },
    idade: {
      type: DataTypes.NUMBER
    },
    ativo: {
      type: DataTypes.BOOLEAN
    }
  },
  {
    sequelize,
    tableName: "users"
  }
);
export default User;

src\controllers\userController.ts

import { Request, Response } from "express";
import User from "../models/userModel";
export const getUsers = async (req: Request, res: Response): Promise<void> => {
  try {
    const users = await User.findAll();
    res.send(users);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuários', details: (error as Error).message });
  }
}
export const getUserById = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const user = await User.findByPk(id);
    res.send(user);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuários', details: (error as Error).message });
  }
}
export const createUser = async (req: Request, res: Response): Promise<void> => {
  try {
    const { nome, email, idade, ativo } = req.body;
    const user = await User.create({nome,email,idade,ativo});
    res.send(user);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuários', details: (error as Error).message });
  }
}
export const updateUser = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const { nome, email, idade, ativo } = req.body;
    const user = await User.findByPk(id);
    const userUp = await user?.update({ nome, email, idade, ativo })
    res.send(userUp);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar usuários', details: (error as Error).message });
  }
}

src\config\database.ts

import { Sequelize } from "sequelize";
const sequelize = new Sequelize(
  "database_test",
  "root",
  "",
  {
    host: "localhost",
    dialect: "mysql"
  }
);
export default sequelize;

Example 2

Giống với Laravel cũng có những thuật ngữ phải nhớ

The A.hasOne(B) association means that a One - To - One relationship exists between A and B, with the foreign key being defined in the target model(B).
The A.belongsTo(B) association means that a One - To - One relationship exists between A and B, with the foreign key being defined in the source model(A).
The A.hasMany(B) association means that a One - To - Many relationship exists between A and B, with the foreign key being defined in the target model(B).
These three calls will cause Sequelize to automatically add foreign keys to the appropriate models(unless they are already present).
The A.belongsToMany(B, { through: 'C' }) association means that a Many - To - Many relationship exists between A and B, using table C as junction table, which will have the foreign keys(aId and bId, for example).Sequelize will automatically create this model C(unless it already exists) and define the appropriate foreign keys on it.

package.json

{
  "name": "graphql-example",
  "version": "1.0.0",
  "description": "GraphQL Example project for Toptal blog article",
  "main": "index.js",
  "repository": "ssh://git@github.com/amaurymartiny/graphql-example",
  "author": "Amaury Martiny <amaury.martiny@gmail.com>",
  "license": "MIT",
  "semistandard": {
    "env": "node"
  },
  "scripts": {
    "start": "babel-node index.js",
    "dev": "nodemon --exec babel-node index.js",
    "lint": "semistandard --fix"
  },
  "dependencies": {
    "@apollo/server": "^4.11.3",
    "@graphql-tools/schema": "^10.0.16",
    "apollo-server-express": "^3.13.0",
    "babel-cli": "^6.26.0",
    "babel-preset-es2015": "^6.24.1",
    "body-parser": "^1.20.3",
    "cors": "^2.8.5",
    "express": "^4.21.2",
    "graphql": "^16.10.0",
    "graphql-server-express": "^1.4.1",
    "graphql-tools": "^9.0.11",
    "http": "^0.0.1-security",
    "nodemon": "^3.1.9",
    "path": "^0.12.7",
    "semistandard": "^17.0.0",
    "sequelize": "^6.37.5",
    "sqlite3": "^5.1.7"
  }
}

Operation.sql

query {
  # users {
  #   id,
  #   firstname
  # }
  # user(id: 2) {
  #   firstname
  # }
}
# query getUserWithProjects {
#   user(id: 2) {
#     firstname
#     lastname
#     projects {
#       name
#       tasks {
#         description
#       }
#     }
#   }
#  }
mutation {
  # createUser(input:{email: "lionel2@gmail.com",firstname: "lionel 2",lastname: "pham2"}) {
  #   email,
  #   firstname,
  #   lastname
  # },
  # updateUser(id:3,input: {firstname: "Lionel 1.3 Edit",lastname:"Pham 1.3 Edit", email: "lionel1.1@gmail.com"}) {
  #   firstname,
  #   lastname,
  #   email
  # },
  # removeUser(id: 10) {
  #   email
  # }
  # createProject(input: {name: "Project 2",UserId:1}) {
  #   name
  # }
  # updateProject(id:6,input: {name: "Project 2.2",UserId: 1}) {
  #   name
  # }
  # removeProject(id: 5) {
  #   name
  # }
  # createTask(input: {description: "Task 1",ProjectId: 1}) {
  #   description
  # }
  # updateTask(id: 9,input: {description: "Task 1 Edit",ProjectId: 1}) {
  #   description
  # }
  # removeTask(id: 9) {
  #   description
  # }
}

index.js

import express from 'express';
import { ApolloServer } from '@apollo/server';
import bodyParser from 'body-parser';
import cors from 'cors';
// import { graphqlExpress, graphiqlExpress } from 'graphql-server-express';
// import { makeExecutableSchema } from 'graphql-tools';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { expressMiddleware } from '@apollo/server/express4';
import routes from './rest/routes';
import typeDefs from './graphql/typeDefs';
import resolvers from './graphql/resolvers';
import http from 'http';
const app = express();
const httpServer = http.createServer(app);
// Middlewares
app.use(bodyParser.json());
// Mount REST on /api
app.use('/api', routes);
// Mount GraphQL on /graphql
// const schema = makeExecutableSchema({
//   typeDefs,
//   resolvers: resolvers()
// });
const server = new ApolloServer({
  typeDefs,
  resolvers: resolvers()
});
 async function test() {
  await server.start();
  // app.use('/graphql', graphqlExpress({ schema }));
  // app.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' }));
  // app.listen(3000, () => console.log('Express app listening on localhost:3000'));
  app.use(
    cors(),
    bodyParser.json(),
    expressMiddleware(server),
  );
  await new Promise((resolve) => httpServer.listen({ port: 3000 }, resolve));
  console.log(`🚀 Server ready at http://localhost:3000`);
}
test();

rest\routes\user.routes.js

import express from 'express';
import userController from '../controllers/user.controller';

const router = express.Router(); // eslint-disable-line new-cap

router.route('/')
  /** GET /api/users - Get list of users */
  .get(userController.list);

router.route('/:userId')
  /** GET /api/users/:userId - Get user */
  .get(userController.get);

router.route('/:userId/projects')
  /** GET /api/users/:userId/projects - List projects of user */
  .get(userController.listProjects);

/** Load user when API with userId route parameter is hit */
router.param('userId', userController.load);

export default router;

rest\routes\task.routes.js

import express from 'express';
import taskController from '../controllers/task.controller';
const router = express.Router(); // eslint-disable-line new-cap
router.route('/')
  /** GET /api/tasks - Get list of tasks */
  .get(taskController.list);
router.route('/:taskId')
  /** GET /api/tasks/:taskId - Get task */
  .get(taskController.get);
/** Load task when API with taskId route parameter is hit */
router.param('taskId', taskController.load);
export default router;

rest\routes\project.routes.js

import express from 'express';
import projectController from '../controllers/project.controller';

const router = express.Router(); // eslint-disable-line new-cap

router.route('/')
  /** GET /api/projects - Get list of projects */
  .get(projectController.list);

router.route('/:projectId')
  /** GET /api/projects/:projectId - Get project */
  .get(projectController.get);

/** Load project when API with projectId route parameter is hit */
router.param('projectId', projectController.load);

export default router;

rest\routes\index.js

import express from 'express';
import userRoutes from './user.routes';
import projectRoutes from './project.routes';
import taskRoutes from './task.routes';
const router = express.Router(); // eslint-disable-line new-cap
router.use('/users', userRoutes);
router.use('/projects', projectRoutes);
router.use('/tasks', taskRoutes);
export default router;

rest\controllers\project.controller.js

import sequelize from '../../models';
const Project = sequelize.models.Project;
/**
 * Load Project and append to req.
 */
function load (req, res, next, id) {
  Project.findOne({ id })
    .then((Project) => {
      req.Project = Project; // eslint-disable-line no-param-reassign
      return next();
    })
    .catch(e => next(e));
}
/**
 * Get Project list.
 * @property {number} req.query.skip - Number of Projects to be skipped.
 * @property {number} req.query.limit - Limit number of Projects to be returned.
 * @returns {Project[]}
 */
function list (req, res, next) {
  Project.findAll()
    .then(Projects => res.json(Projects))
    .catch(e => next(e));
}
/**
 * Get Project
 * @returns {Project}
 */
function get (req, res) {
  return res.json(req.Project);
}
export default { load, get, list };

rest\controllers\task.controller.js

import sequelize from '../../models';
const Task = sequelize.models.Task;
/**
 * Load Task and append to req.
 */
function load (req, res, next, id) {
  Task.findOne({ id })
    .then((Task) => {
      req.Task = Task; // eslint-disable-line no-param-reassign
      return next();
    })
    .catch(e => next(e));
}
/**
 * Get Task list.
 * @property {number} req.query.skip - Number of Tasks to be skipped.
 * @property {number} req.query.limit - Limit number of Tasks to be returned.
 * @returns {Task[]}
 */
function list (req, res, next) {
  Task.findAll()
    .then(Tasks => res.json(Tasks))
    .catch(e => next(e));
}
/**
 * Get Task
 * @returns {Task}
 */
function get (req, res) {
  return res.json(req.Task);
}
export default { load, get, list };

rest\controllers\user.controller.js

import sequelize from '../../models';
const User = sequelize.models.User;
/**
 * Load user and append to req.
 */
function load(req, res, next, id) {
  User.findByPk(id)
    .then((user) => {
      req.user = user;
      return next();
    })
    .catch(e => next(e));
}
/**
 * Get user list.
 * @property {number} req.query.skip - Number of users to be skipped.
 * @property {number} req.query.limit - Limit number of users to be returned.
 * @returns {User[]}
 */
function list(req, res, next) {
  User.findAll()
    .then(users => res.json(users))
    .catch(e => next(e));
}
/**
 * Get user
 * @returns {User}
 */
function get(req, res) {
  return res.json(req.user);
}
/**
 * List projects of user
 * @returns {Projects[]}
 */
function listProjects(req, res, next) {
  req.user.getProjects()
    .then(projects => res.json(projects))
    .catch(e => next(e));
}
export default { load, get, list, listProjects };

models\user.model.js

import {Sequelize} from 'sequelize';
export default function (sequelize) {
  const User = sequelize.define('User', {
    firstname: Sequelize.STRING,
    lastname: Sequelize.STRING,
    email: Sequelize.STRING
  }, {
    createdAt: false,
    updatedAt: false
  });
  User.associate = (models) => {
    User.hasMany(models.Project);
  };
}

models\task.model.js

import {Sequelize} from 'sequelize';
export default function (sequelize) {
  const Task = sequelize.define('Task', {
    description: Sequelize.STRING
  }, {
    createdAt: false,
    updatedAt: false
  });
  Task.associate = (models) => {
    Task.belongsTo(models.Project);
  };
}

models\seed.js

// Add some data in the database
export default function (sequelize) {
  const models = sequelize.models;

  models.User.create({
    firstname: 'John',
    lastname: 'Doe',
    email: 'john.doe@example.com'
  })
  .then((user) => models.Project.create({
    name: 'Migrate from REST to GraphQL',
    UserId: user.id
  }))
  .then((project) => {
    models.Task.create({
      description: 'Read tutorial',
      ProjectId: project.id
    });
    models.Task.create({
      description: 'Start coding',
      ProjectId: project.id
    });
    return Promise.resolve(project);
  })
  .then((project) => models.Project.create({
    name: 'Create a blog',
    UserId: project.UserId
  }))
  .then((project) => {
    models.Task.create({
      description: 'Write draft of article',
      ProjectId: project.id
    });
    models.Task.create({
      description: 'Set up blog platform',
      ProjectId: project.id
    });
    return Promise.resolve();
  })
  .then(() => models.User.create({
    firstname: 'Alicia',
    lastname: 'Smith',
    email: 'alicia.smith@example.com'
  }))
  .then((user) => models.Project.create({
    name: 'Email Marketing Campaign',
    UserId: user.id
  }))
  .then((project) => {
    models.Task.create({
      description: 'Get list of users',
      ProjectId: project.id
    });
    models.Task.create({
      description: 'Write email template',
      ProjectId: project.id
    });
    return Promise.resolve(project);
  })
  .then((project) => models.Project.create({
    name: 'Hire new developer',
    UserId: project.UserId
  }))
  .then((project) => {
    models.Task.create({
      description: 'Find candidates',
      ProjectId: project.id
    });
    models.Task.create({
      description: 'Prepare interview',
      ProjectId: project.id
    });
    return Promise.resolve();
  });
}

models\project.model.js

import {Sequelize} from 'sequelize';
export default function (sequelize) {
  const Project = sequelize.define('Project', {
    name: Sequelize.STRING
  }, {
    createdAt: false,
    updatedAt: false
  });
  Project.associate = (models) => {
    Project.belongsTo(models.User);
    Project.hasMany(models.Task);
  };
}

models\index.js

import { Sequelize } from 'sequelize';
import User from './user.model';
import Project from './project.model';
import Task from './task.model';
import seed from './seed'; // eslint-disable-line
import path from 'path';
const sequelize = new Sequelize(
  "db",
  process.env.USER,
  process.env.PASSWORD,
  {
    host: "0.0.0.0",
    dialect: 'sqlite',
    pool: {
      max: 5,
      min: 0,
      idle: 10000
    },
    storage: path.resolve('db', 'db.sqlite'),
    logging: false
  }
);
sequelize.authenticate()
.then(() => {
  console.log('Connection has been established successfully.');
})
.catch(err => {
  console.error('Unable to connect to the database:', err);
});
User(sequelize);
Project(sequelize);
Task(sequelize);
// Set up data relationships
const models = sequelize.models;
Object.keys(models).forEach(name => {
  if ('associate' in models[name]) {
    models[name].associate(models);
  }
});
sequelize.sync();
// Uncomment the line if you want to rerun DB seed
// sequelize.sync({ force: true }).then(() => seed(sequelize));
export default sequelize;

graphql\typeDefs.js

const typeDefinitions = `
type User {
  id: ID!
  firstname: String
  lastname: String
  email: String
  projects: [Project]
}

input UserInput {
  firstname: String
  lastname: String
  email: String
}

type Project {
  id: ID!
  name: String
  tasks: [Task]
}

input ProjectInput {
  name: String
  UserId: ID!
}

type Task {
  id: ID!
  description: String
  ProjectId: ID!
}

input TaskInput {
  description: String
  ProjectId: ID!
}

# The schema allows the following queries:
type RootQuery {
  user(id: ID): User
  users: [User]
  project(id: ID!): Project
  projects: [Project]
  task(id: ID!): Task
  tasks: [Task]
}

# The schema allows the following mutations:
type RootMutation {
  createUser(input: UserInput!): User
  updateUser(id: ID!, input: UserInput!): User
  removeUser(id: ID!): User
  createProject(input: ProjectInput!): Project
  updateProject(id: ID!, input: ProjectInput!): Project
  removeProject(id: ID!): Project
  createTask(input: TaskInput!): Task
  updateTask(id: ID!, input: TaskInput!): Task
  removeTask(id: ID!): Task
}

# We need to tell the server which types represent the root query.
# We call them RootQuery and RootMutation by convention.
schema {
  query: RootQuery
  mutation: RootMutation
}
`;

export default typeDefinitions;

graphql\resolvers.js

import sequelize from '../models';
export default function resolvers() {
  const models = sequelize.models;
  return {
    RootQuery: {
      user(root, { id }) {
        return models.User.findByPk(id);
      },
      users(root) {
        return models.User.findAll({});
      },
    },
    RootMutation: {
      createUser (root, { input }) {
        return models.User.create(input);    
      },
      updateUser (root, { id, input }) {
        models.User.update(input, {where: { id } });
        return models.User.findByPk(id);
      },
      removeUser (root, { id }) {
        return models.User.destroy({where: { id } });
      },
      createProject(root, { input }) {
        return models.Project.create(input);   
      },
      updateProject(root, {id, input}) {
        models.Project.update(input, {where: { id } });
        return models.Project.findByPk(id);
      },
      removeProject(root,{id}) {
        return models.Project.destroy({where: { id } });
      },
      createTask(root,{input}) {
        return models.Task.create(input);   
      },
      updateTask(root, {id,input}) {
        models.Task.update(input, {where: { id } });
        return models.Task.findByPk(id);
      },
      removeTask(root, {id}) {
        return models.Task.destroy({where: { id } });
      }
    },
    User: {
      projects(user) {
        return user.getProjects();
      }
    },
    Project: {
      tasks(project) {
        return project.getTasks();
      }
    }
  };
}

C:\Users\Administrator\Desktop\graphql-example\db\db.sqlite

graphql-example

Getting Started

git clone https://github.com/amaurymartiny/graphql-example
cd graphql-example
npm install
npm run dev

Information

  • The models folder contains the three models: User, Project and Task. They are created using the sequelize ORM.

  • The rest folder contains the logic to create the associated /api/users, /api/projects and /api/tasks endpoints.

  • The graphql folder contains the schema and resolvers for GraphQL.

  • db.sqlite contains the database.

  • index.js starts the Express server.

Demo

This example project is hosted on Heroku.

  • The rest endpoints can be viewed here

The aim of this article is to help you make an easy transition from REST to GraphQL, whether you’ve already made your mind for GraphQL or you’re just willing to give it a try. No prior knowledge of GraphQL is needed, but some familiarity with REST APIs is required to understand the article.

The first part of the article will start by giving three reasons why I personally think GraphQL is superior to REST. The second part is a tutorial on how to add a GraphQL endpoint on your back-end.

GraphQL vs. REST: Why Drop REST?

Reason 1: Network Performance

Say you have a user resource on the back-end with first name, last name, email, and 10 other fields. On the client, you generally only need a couple of those.

Making a REST call on the /users endpoint gives you back all the fields of the user, and the client only uses the ones it needs. There is clearly some data transfer waste, which might be a consideration on mobile clients.

GraphQL by default fetches the smallest data possible. If you only need first and last names of your users, you specify that in your query.

On the left pane of the interface is the query. Here, we are fetching all the users—we would do GET /users with REST—and only getting their first and last names.

Query

query {
  users {
    firstname
    lastname
  }
}

Result

{
  "data": {
    "users": [
      {
        "firstname": "John",
        "lastname": "Doe"
      },
      {
        "firstname": "Alicia",
        "lastname": "Smith"
      }
    ]
  }
}

If we wanted to get the emails as well, adding an “email” line below “lastname” would do the trick.

  • &status=active to filter active users

  • &sort=createdAat to sort the users by their creation date

  • &sortDirection=desc because you obviously need it

  • &include=projects to include the users’ projects

These query parameters are patches added to the REST API to imitate a query language. GraphQL is above all a query language, which makes requests concise and precise from the beginning.

Reason 2: The “Include vs. Endpoint” Design Choice

Let’s imagine we want to build a simple project management tool. We have three resources: users, projects, and tasks. We also define the following relationships between the resources:

Here are some of the endpoints we expose to the world:

Endpoint
Description

GET /users

List all users

GET /users/:id

Get the single user with id :id

GET /users/:id/projects

Get all projects of one user

The endpoints are simple, easily readable, and well-organized.

Things get trickier when our requests get more complex. Let’s take the GET /users/:id/projects endpoint: Say I want to show only the projects’ titles on the home page, but projects+tasks on the dashboard, without making multiple REST calls. I would call:

  • GET /users/:id/projects for the home page.

  • GET /users/:id/projects?include=tasks (for example) on the dashboard page so that the back-end appends all related tasks.

GraphQL uses the include approach everywhere. This makes the syntax to fetch relationships powerful and consistent.

Here’s an example of fetching all projects and tasks from the user with id 1.

Query

{
  user(id: 1) {
    projects {
      name
      tasks {
        description
      }
    }
  }
}

Result

{
  "data": {
    "user": {
      "projects": [
        {
          "name": "Migrate from REST to GraphQL",
          "tasks": [
            {
              "description": "Read tutorial"
            },
            {
              "description": "Start coding"
            }
          ]
        },
        {
          "name": "Create a blog",
          "tasks": [
            {
              "description": "Write draft of article"
            },
            {
              "description": "Set up blog platform"
            }
          ]
        }
      ]
    }
  }
}

As you can see, the query syntax is easily readable. If we wanted to go deeper and include tasks, comments, pictures, and authors, we wouldn’t think twice about how to organize our API. GraphQL makes it easy to fetch complex objects.

Reason 3: Managing Different Types of Clients

When building a back-end, we always start by trying to make the API as widely usable by all clients as possible. Yet clients always want to call less and fetch more. With deep includes, partial resources, and filtering, requests made by web and mobile clients may differ a lot one from another.

GraphQL gives more power to the client. If the client needs complex requests, it will build the corresponding queries itself. Each client can consume the same API differently.

How to Start with GraphQL

In most debates about “GraphQL vs. REST” today, people think that they must choose either one of the two. This is simply not true.

Modern applications generally use several different services, which expose several APIs. We could actually think of GraphQL as a gateway or a wrapper to all these services. All clients would hit the GraphQL endpoint, and this endpoint would hit the database layer, an external service like ElasticSearch or Sendgrid, or other REST endpoints.

A second way of using both is to have a separate /graphql endpoint on your REST API. This is especially useful if you already have numerous clients hitting your REST API, but you want to try GraphQL without compromising the existing infrastructure. And this is the solution we are exploring today.

* Note: After publication, Heroku stopped offering free hosting, and the demos are no longer available.

Do note that GraphQL can be installed on any type of back-end and database, using any programming language. The technologies used here are chosen for the sake of simplicity and readability.

Our goal is to create a /graphql endpoint without removing the REST endpoints. The GraphQL endpoint will hit the database ORM directly to fetch data, so that it is totally independant from the REST logic.

Types

The data model is represented in GraphQL by types, which are strongly typed. There should be a 1-to-1 mapping between your models and GraphQL types. Our User type would be:

type User {
  id: ID! # The "!" means required
  firstname: String
  lastname: String
  email: String
  projects: [Project] # Project is another GraphQL type
}

Queries

Queries define what queries you can run on your GraphQL API. By convention, there should be a RootQuery, which contains all the existing queries. I also pointed out the REST equivalent of each query:

type RootQuery {
  user(id: ID): User           # Corresponds to GET /api/users/:id
  users: [User]                # Corresponds to GET /api/users
  project(id: ID!): Project    # Corresponds to GET /api/projects/:id
  projects: [Project]          # Corresponds to GET /api/projects
  task(id: ID!): Task          # Corresponds to GET /api/tasks/:id
  tasks: [Task]                # Corresponds to GET /api/tasks
}

Mutations

If queries are GET requests, mutations can be seen as POST/PATCH/PUT/DELETE requests (although really they are synchronized versions of queries).

By convention, we put all our mutations in a RootMutation:

type RootMutation {
  createUser(input: UserInput!): User             # Corresponds to POST /api/users
  updateUser(id: ID!, input: UserInput!): User    # Corresponds to PATCH /api/users
  removeUser(id: ID!): User                       # Corresponds to DELETE /api/users

  createProject(input: ProjectInput!): Project
  updateProject(id: ID!, input: ProjectInput!): Project
  removeProject(id: ID!): Project
  
  createTask(input: TaskInput!): Task
  updateTask(id: ID!, input: TaskInput!): Task
  removeTask(id: ID!): Task
}

Note that we introduced new types here, called UserInput, ProjectInput, and TaskInput. This is a common practice with REST too, to create an input data model for creating and updating resources. Here, our UserInput type is our User type without the id and projects fields, and notice the keyword input instead of type:

input UserInput {
  firstname: String
  lastname: String
  email: String
}

Schema

With types, queries and mutations, we define the GraphQL schema, which is what the GraphQL endpoint exposes to the world:

schema {
  query: RootQuery
  mutation: RootMutation
}

This schema is strongly typed and is what allowed us to have those handy autocompletes in GraphiQL*.

* Note: After publication, Heroku stopped offering free hosting, and the demos for this article are no longer available.

Resolvers

Now that we have the public schema, it is time to tell GraphQL what to do when each of these queries/mutations is requested. Resolvers do the hard work; they can, for example:

  • Hit an internal REST endpoint

  • Call a microservice

  • Hit the database layer to do CRUD operations

const models = sequelize.models;

RootQuery: {
  user (root, { id }, context) {
    return models.User.findById(id, context);
  },
  users (root, args, context) {
    return models.User.findAll({}, context);
  },
  // Resolvers for Project and Task go here
},
    
/* For reminder, our RootQuery type was:
type RootQuery {
  user(id: ID): User
  users: [User]
 
  # Other queries
}

This means, if the user(id: ID!) query is requested on GraphQL, then we return User.findById(), which is a Sequelize ORM function, from the database.

What about joining other models in the request? Well, we need to define more resolvers:

User: {
  projects (user) {
    return user.getProjects(); // getProjects is a function managed by Sequelize ORM
  }
},
    
/* For reminder, our User type was:
type User {
  projects: [Project] # We defined a resolver above for this field
  # ...other fields
}
*/

So when we request the projects field in a User type in GraphQL, this join will be appended to the database query.

And finally, resolvers for mutations:

RootMutation: {
  createUser (root, { input }, context) {
    return models.User.create(input, context);    
  },
  updateUser (root, { id, input }, context) {
    return models.User.update(input, { ...context, where: { id } });
  },
  removeUser (root, { id }, context) {
    return models.User.destroy(input, { ...context, where: { id } });
  },
  // ... Resolvers for Project and Task go here
}

You can play around with this here. For the sake of keeping the data on the server clean, I disabled the resolvers for mutations, which means that the mutations will not do any create, update or delete operations in the database (and thus return null on the interface).

Query

query getUserWithProjects {
  user(id: 2) {
    firstname
    lastname
    projects {
      name
      tasks {
        description
      }
    }
  }
}

mutation createProject {
  createProject(input: {name: "New Project", UserId: 2}) {
    id
    name
  }
}

Result

{
  "data": {
    "user": {
      "firstname": "Alicia",
      "lastname": "Smith",
      "projects": [
        {
          "name": "Email Marketing Campaign",
          "tasks": [
            {
              "description": "Get list of users"
            },
            {
              "description": "Write email template"
            }
          ]
        },
        {
          "name": "Hire new developer",
          "tasks": [
            {
              "description": "Find candidates"
            },
            {
              "description": "Prepare interview"
            }
          ]
        }
      ]
    }
  }
}

Putting Everything Together

With a well-defined schema and resolvers on what to do on each query of the schema, we can mount a /graphql endpoint on our back-end:

// Mount GraphQL on /graphql
const schema = makeExecutableSchema({
  typeDefs, // Our RootQuery and RootMutation schema
  resolvers: resolvers() // Our resolvers
});
app.use('/graphql', graphqlExpress({ schema }));

And we can have a nice-looking GraphiQL interface* on our back-end. To make a request without GraphiQL, simply copy the URL of the request (i.e., https://host/graphql?query=query%20%7B%0A%20%20user(id%3A%202)%20%7B%0A%20%20%20%20firstname%0A%20%20%20%20lastname%0A%20%20%20%20projects%20%7B%0A%20%20%20%20%20%20name%0A%20%20%20%20%20%20tasks%20%7B%0A%20%20%20%20%20%20%20%20description%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D*), and run it with cURL, AJAX, or directly in the browser. Of course, there are some GraphQL clients to help you build these queries. See below for some examples.

* Note: After publication, Heroku stopped offering free hosting, and the demos are no longer available.

What’s Next?

This article’s aim is to give you a taste of what GraphQL looks like and show you that it’s definitely possible to try GraphQL without throwing away your REST infrastructure. The best way to know if GraphQL suits your needs is to try it yourself. I hope that this article will make you take the dive.

Below are some other useful resources:

Server-side Tool
Description

The reference implementation of GraphQL. You can use it with express-graphql to create a server.

Ruby, PHP, etc.

Client-side Tool
Description

A framework for connecting React with GraphQL.

In conclusion, I believe that GraphQL is more than hype. It won’t replace REST tomorrow just yet, but it does offer a performant solution to a genuine problem. It is relatively new, and best practices are still developing, but it is definitely a technology that we will hear about in the next couple of years.

GraphQL Example project for Toptal blog article:

You should be able to see the app running at .

The GraphQL endpoint is , and a GraphiQL interface is mounted .

You might have heard about the new kid around the block: GraphQL. If not, GraphQL is, in a word, a new way to fetch , an alternative to REST. It started as an internal project at Facebook, and since it was open sourced, it has gained .

If you are still hesitating on whether or not GraphQL is suited for your needs, a quite extensive and objective overview of “REST vs. GraphQL” is given . However, for my top three reasons to use GraphQL, read on.

The interface below is called GraphiQL, which is like an API explorer for GraphQL. I created a small project for the purpose of this article. The code is hosted , and we’ll dive into it in the second part.

Some REST back-ends do offer options like /users?fields=firstname,lastname to return partial resources. For what it’s worth, . However, it is not implemented by default, and it makes the request barely readable, especially when you toss in other query parameters:

It’s common practice to add query parameters ?include=... to make this work, and is even recommended by the specification. Query parameters like ?include=tasks are still readable, but before long, we will end up with ?include=tasks,tasks.owner,tasks.comments,tasks.comments.author.

In this case, would be it wiser to create a /projects endpoint to do this? Something like /projects?userId=:id&include=tasks, as we would have one level of relationship less to include? Or, actually, a /tasks?userId=:id endpoint might work too. This can be a difficult design choice, if we have a many-to-many relationship.

With REST, there are a couple of solutions. We can create a custom endpoint (i.e., an alias endpoint, e.g., /mobile_user), a custom representation (Content-Type: application/vnd.rest-app-example.com+v1+mobile+json), or even a client-specific API (like ). All three of them require extra effort from the back-end development team.

As said earlier, I will illustrate this tutorial with a small example project, available . It is a simplified project management tool, with users, projects, and tasks.

The technologies used for this project are Node.js and Express for the web server, SQLite as the relational database, and Sequelize as an ORM. The three models—user, project, and task—are defined in the folder. The REST endpoints /api/users*, /api/projects* and /api/tasks* are exposed to the world, and are defined in the folder.

We are choosing the third option in our example app. Let’s have a look at our :

It may take some time to rewrite all types, queries, and resolvers for your existing app. However, a lot of tools exist to help you. For instance, that translate a SQL schema to a GraphQL schema, including resolvers!

There are a lot of features we haven’t discussed about in this article, such as real-time updates, server-side batching, authentication, authorization, client-side caching, file uploading, etc. An excellent resource to learn about these features is .

An all-in-one GraphQL server created by the .

.

A GraphQL client with bindings for , , and .

😍
https://www.toptal.com/api-development/graphql-vs-rest-tutorial#utilize-unreal-developers-today
http://localhost:3000
http://graphql-example.herokuapp.com/api/users
http://graphql-example.herokuapp.com/api/projects
http://graphql-example.herokuapp.com/api/tasks
http://graphql-example.herokuapp.com/graphql
here
APIs
a lot of traction
here
on GitHub
Google recommends it
JSON API
even more complicated
Netflix once did
on GitHub
models
rest
resolvers file
there
are
tools
How to GraphQL
graphql-js
graphql-server
Apollo team
Implementations for other platforms
Relay
apollo-client
React
Angular 2
other front-end frameworks
https://github.com/gitlucaslima/zaros-crud
Relationships between resources
GraphQL vs. REST - A GraphQL Tutorial
Comparisons of GraphQL vs. REST endpoints
64KB
zaros-crud-main.zip
archive
2KB
users.sql
20KB
db.sqlite
41KB
graphql-example-master.zip
archive
62KB
full code.zip
archive