본문 바로가기

카테고리 없음

[Rust] Rocket + Diesel(mysql)

 

 

# 참고 URL : https://cprimozic.net/blog/rust-rocket-cloud-run/

 

Deploying a REST API with Rust, Diesel, Rocket, and MySQL on Google Cloud Run - Casey Primozic's Homepage

 

cprimozic.net

 

 

# terminal 에서 실행 

1
cargo install diesel_cli --no-default-features --features mysql
cs

 ## EROOR

1
2
3
4
error: failed to compile `diesel_cli v1.4.1`, intermediate artifacts can be found at `/tmp/cargo-installl2UFJW`
 
Caused by:
  could not compile `diesel_cli` due to previous error
cs

## EROOR - sol

### 참조 : https://github.com/diesel-rs/diesel/issues/2026

### terminal

1
2
sudo apt install libpq-dev libmysqlclient-dev
cargo install diesel_cli --no-default-features --features mysql
cs

 

 

# Test Query : create table 

1
2
3
4
5
CREATE USER 'rocket'@'%' IDENTIFIED BY 'your_password_here';
 
CREATE DATABASE rocket_app;
 
GRANT ALL PRIVILEGES ON rocket_app.* TO rocket;
cs

 

 

# create project

1
cargo new diesel_demo
cs

 

 

# Cargo.toml 에 입력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[package]
name = "diesel_demo"
version = "0.1.0"
authors = ["user name"]
edition = "2021"
 
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
[dependencies]
# Powerful date and time functionality
chrono = { version = "0.4.6", features = ["serde"] }
 
# For connecting with the MySQL database
diesel = { version = "1.4.2", features = ["chrono"] }
 
# Lazy static initialization
lazy_static = "1.3.0"
 
# Rocket Webserver
rocket = "0.4.0"
rocket_contrib = { version = "0.4.0", features = ["json""diesel_mysql_pool"] }
 
# Serialization/Deserialization
serde_json = "1.0.39"
serde = "1.0.90"
serde_derive = "1.0.90"
cs

 

 

# diesel.toml  생성 후 입력 

1
2
3
4
5
# For documentation on how to configure this file,
# see diesel.rs/guides/configuring-diesel-cli
 
[print_schema]
file = "src/schema.rs"
cs

 

 

 

---------------------------------------------------- ERROR ----------------------------------------------------

# Project의 root directory에서 terminal로 실행

1
$ export DATABASE_URL="mysql://rocket:your_chosen_password@example.com/rocket_app"
cs
1
$ diesel setup # Creates `migrations` directory + `src/schema.rs` file
cs

--ERROR : Creating migrations directory at: /home/user/rust-test/diesel_demo/migrations
Creating database: rocket_app
Can't connect to MySQL server on 'example.com:3306' (101)

1
$ export DATABASE_URL="mysql://rocket:your_chosen_password@localhost/rocket_app"
cs
1
$ diesel setup # Creates `migrations` directory + `src/schema.rs` file
cs

--ERROR : Creating database: rocket_app
Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

 

----- 참고 URL : https://lhr0419.medium.com/cant-connect-to-local-mysql-server-through-socket-var-run-mysqld-mysqld-sock-2-%ED%95%B4%EA%B2%B0%ED%95%B4%EB%B3%B4%EC%95%84%EC%9A%94-1d94a9bc2618

 

 

# 폴더 생성

1
$ sudo mkdir /var/run/mysqld
cs

 

# mysql 재시작 

1
$ sudo service mysql restart
cs

-- ERROR : mysql: unrecognized service

# mysql 재설치

1
$ sudo apt-get --reinstall install mysql-server
cs

# 심볼릭 링크 생성 

1
$ sudo ln -/private/tmp/mysql.sock /var/run/mysqld/mysqld.sock
cs
1
$ export DATABASE_URL="mysql://rocket:your_chosen_password@localhost/rocket_app"
cs
1
$ diesel setup # Creates `migrations` directory + `src/schema.rs` file
cs

--ERROR : Creating database: rocket_app
Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

 

#mysql 중지

1
$ sudo service mysql stop
cs

# mysql 재시작 

1
$ sudo service mysql start
cs

-  * Starting MySQL database server mysqld [fail]

 

# mysql 접속 확인 [ubuntu]

- 참고 URL : https://ujin-dev.tistory.com/15

1
$ sudo /usr/bin/mysql -u root -p
cs

-- ERROR : ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

 

- 참고 URL(1) : https://freestrokes.tistory.com/43

- 참고 URL(2) : https://technote.kr/32

 

해결! 

---------------------------------------------------- ERROR ----------------------------------------------------

 

 

# 해결!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 서비스 종료
$ sudo service mysql stop
 
# 데몬 실행 
$ sudo /usr/bin/mysqld_safe --skip-grant-tables &
 
#var/run/mysqld 경로가 존재하는지 확인해주고 없다면 생성 후 권한 설정
$ sudo mkdir -/var/run/mysqld
$ sudo chown -R mysql:mysql /var/run/mysqld
 
# 다시 MySQL 데몬을 실행
$ mysql -u root mysql
 
#mysql 접속 확인 후 user 확인 
mysql> use mysql;
# 결과 : Database changed
# user 조회 
mysql> select user, host from user;
 
# ctrl + z mysql 나오기 
 
# Mysql 사용자 추가/생성
# 사용자 생성/추가를 위해 mysql에 root로 접속.
$ mysql -u root -p mysql
 
# rocket 생성 
mysql> CREATE USER 'rocket'@'localhost' IDENTIFIED BY 'your_password_here';
 
# rocket_app 데이터베이스 생성
mysql> CREATE DATABASE rocket_app;
 
# 권한 설정 
mysql> GRANT ALL PRIVILEGES ON rocket_app.* TO rocket;
 
### error : ERROR 1410 (42000): You are not allowed to create a user with GRANT
mysql> GRANT ALL PRIVILEGES ON rocket_app.*  TO 'rocket'@'localhost' WITH GRANT OPTION;
 
# diesel에게 데이터 베이스 연결하는 방법 알려주기 
# 프로젝트 root로 접근 
# ../[생성한 프로젝트 명]
# ../diesel_demo
export DATABASE_URL="mysql://rocket:your_chosen_password@localhost/rocket_app"
# 마이그레이션을 시작하기 위한 루트 디렉터리에서 실행 
$ diesel setup # Creates `migrations` directory + `src/schema.rs` file
$ diesel migration generate initialize
# 결과 
# -> Creating migrations/2021-12-02-085626_initialize/up.sql
# -> Creating migrations/2021-12-02-085626_initialize/down.sql
 
cs

 

migrations 생성

 

# up.sql

1
2
3
4
5
6
7
8
9
CREATE TABLE `rocket_app`.`pageviews` (
  `id` BIGINT NOT NULL AUTO_INCREMENT,
  `view_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `url` VARCHAR(2083NOT NULL,
  `user_agent` VARCHAR(2083NOT NULL,
  `referrer` VARCHAR(2083NOT NULL,
  `device_type` TINYINT NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
);
cs

 

# down.sql

1
DROP TABLE `rocket_app`.`pageviews`;
cs

# 마이그레이션 run

1
$ diesel migration run
cs

-- 결과 : Running migration 2021-12-02-085626_initialize

 

# 마이그레이션 단계 테스트 

1
$ diesel migration redo
cs

 

 

# src/schema.rs 자동 생성 

1
2
3
4
5
6
7
8
9
10
11
table! {
    pageviews (id) {
        id -> Bigint,
        view_time -> Datetime,
        url -> Varchar,
        user_agent -> Varchar,
        referrer -> Varchar,
        device_type -> Tinyint,
    }
}
 
cs

 

 

 

# src/main.rs 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#![feature(proc_macro_hygiene, decl_macro)]

extern crate chrono;
#[macro_use]
extern crate diesel;
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
 
pub mod cors;
pub mod models;
pub mod routes;
pub mod schema; // Ignore errors from this for now; it doesn't get created unti later

// This registers your database with Rocket, returning a `Fairing` that can be `.attach`'d to your
// Rocket application to set up a connection pool for it and automatically manage it for you.
#[database("rocket_app")]
pub struct DbConn(diesel::MysqlConnection);

fn main() {
    rocket::ignite()
       .mount("/", routes![ // roustes.rs 파일 생성 후 추가
            routes::index,
            routes::create_page_view,
            routes::list_page_views,
        ])
       .attach(DbConn::fairing())      
       .attach(cors::CorsFairing) // Add this line cors.rs 파일 생성 후 추가
     .launch();
}
cs
 
 
 

 

 

 

# src/models.rs 생성 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use chrono::NaiveDateTime;

use crate::schema::pageviews;

/// This represents a page view pulled from the database, including the auto-generated fields
#[derive(Serialize, Deserialize, Queryable)]
pub struct PageView {
    pub id: i64,
    pub view_time: NaiveDateTime,
    pub url: String,
    pub user_agent: String,
    pub referrer: String,
    pub device_type: i8,
}

/// This represents a page view being inserted into the database, without the auto-generated fields
#[derive(Deserialize, Insertable)]
#[table_name = "pageviews"]
pub struct InsertablePageView {
    pub url: String,
    pub user_agent: String,
    pub referrer: String,
    pub device_type: i8,
}
cs

 

 

 

# src/routes.rs 생성 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
use diesel::{self, prelude::*};

use rocket_contrib::json::Json;

use crate::models::{InsertablePageView, PageView};
use crate::schema;
use crate::DbConn;

#[get("/")]
pub fn index() -> &'static str {
    "Application successfully started!"
}

#[post("/page_view", data = "<page_view>")]
pub fn create_page_view(
    conn: DbConn,
    page_view: Json<InsertablePageView>,
) -> Result<String, String> {
    let inserted_rows = diesel::insert_into(schema::pageviews::table)
        .values(&page_view.0)
        .execute(&conn.0)
        .map_err(|err| -> String {
            println!("Error inserting row: {:?}", err);
            "Error inserting row into database".into()
        })?;

    Ok(format!("Inserted {} row(s).", inserted_rows))
}

#[get("/page_view")]
pub fn list_page_views(conn: DbConn) -> Result<Json<Vec<PageView>>, String> {
    use crate::schema::pageviews::dsl::*;

    pageviews.load(&conn.0).map_err(|err| -> String {
        println!("Error querying page views: {:?}", err);
        "Error querying page views from the database".into()
    }).map(Json)
}
cs

 

# src/cors.rs 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use rocket::fairing::{Fairing, Info, Kind};
use rocket::{http::Method, http::Status, Request, Response};

pub struct CorsFairing;

impl Fairing for CorsFairing {
    fn on_response(&self, request: &Request, response: &mut Response) {
        // Add CORS headers to allow all origins to all outgoing requests
        response.set_header(rocket::http::Header::new(
            "Access-Control-Allow-Origin",
            "*",
        ));

        // Respond to all `OPTIONS` requests with a `204` (no content) status
        if response.status() == Status::NotFound && request.method() == Method::Options {
            response.set_status(Status::NoContent);
        }
    }

    fn info(&self) -> Info {
        Info {
            name: "CORS Fairing",
            kind: Kind::Response,
        }
    }
}
cs

 

 

# 생성된 폴더 구조 

 

 

 

# 로켓에게 알려주기 

1
$ export ROCKET_DATABASES="{ rocket_app = { url = \"mysql://rocket:your_chosen_password@localhost/rocket_app\" } }"
cs

 

 

# 실행 

1
$ cargo run
cs

 

 

- ERROR : error: failed to run custom build command for `pear_codegen v0.1.4`

Caused by:
  process didn't exit successfully: `/home/user/rust-test/diesel_demo/target/debug/build/pear_codegen-6c0aed454a075096/build-script-build` (exit status: 101)
  --- stderr
  Error: Pear requires a 'dev' or 'nightly' version of rustc.
  Installed version: 1.56.1 (2021-11-01)
  Minimum required:  1.31.0-nightly (2018-10-05)
  thread 'main' panicked at 'Aborting compilation due to incompatible compiler.', /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/pear_codegen-0.1.4/build.rs:24:13
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: build failed

 

 

1
$ rustup default nightly
cs

--- 결과 : info: syncing channel updates for 'nightly-x86_64-unknown-linux-gnu'
info: latest update on 2021-12-02, rust version 1.59.0-nightly (48a5999fc 2021-12-01)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
 19.4 MiB /  19.4 MiB (100 %)   2.2 MiB/s in 10s ETA:  0s
info: installing component 'rust-std'
 25.9 MiB /  25.9 MiB (100 %)  12.9 MiB/s in  2s ETA:  0s
info: installing component 'rustc'
 54.5 MiB /  54.5 MiB (100 %)  15.0 MiB/s in  3s ETA:  0s
info: installing component 'rustfmt'
info: default toolchain set to 'nightly-x86_64-unknown-linux-gnu'

  nightly-x86_64-unknown-linux-gnu installed - rustc 1.59.0-nightly (48a5999fc 2021-12-01)

 

 

# 다시 cargo 실행 

1
$ cargo run
cs

 

 

# 실행 결과 

## Get : localhost:8000/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 Blocking waiting for file lock on build directory
   Compiling diesel_demo v0.1.0 (/home/user/rust-test/diesel_demo)
warning: Error finalizing incremental compilation session directory `/home/user/rust-test/diesel_demo/target/debug/incremental/diesel_demo-1nbj1jt6yr20z/s-g4s0295q1h-1pzh0gs-working`: Permission denied (os error 13)
 
warning: `diesel_demo` (bin "diesel_demo") generated 1 warning
    Finished dev [unoptimized + debuginfo] target(s) in 2m 14s
     Running `target/debug/diesel_demo`
🔧 Configured for development.
    => address: localhost
    => port: 8000
    => log: normal
    => workers: 12
    => secret key: generated
    => limits: forms = 32KiB
    => keep-alive: 5s
    => read timeout: 5s
    => write timeout: 5s
    => tls: disabled
    => [extra] databases: { rocket_app = { url = "mysql://rocket:your_chosen_password@localhost/rocket_app" } }
🛰   Mounting /:
    => GET / (index)
    => POST /page_view (create_page_view)
    => GET /page_view (list_page_views)
📡 Fairings:
    => 1 response: CORS Fairing
🚀 Rocket has launched from http://localhost:8000
cs

 

localhost:8000 실행

 

## Post : localhost:8000/page_view

 

## Get: localhost:8000/page_view

 

 

 

 

 

-------------------------------------------------------restart-------------------------------------------------------

 

$ export DATABASE_URL="mysql://rocket:your_chosen_password@localhost/rocket_app"

 

$ export ROCKET_DATABASES="{ rocket_app = { url = \"mysql://rocket:your_chosen_password@localhost/rocket_app\" } }"
cs

-------------------------------------------------------restart-------------------------------------------------------

 

 

 

-------------------------------------------------------restart-------------------------------------------------------

-------------------------------------------------------restart-------------------------------------------------------