タイトル詐欺です
僕が超偏見と独断で最近キテる or 流行りそうな予感な言語4つを選びました✋
使用言語
- Python
- Nim
- Go
- Kotlin
概要
今回は独断と偏見で4つの言語(Python, Nim, Go, Kotlin)の軽量フレームワーク(順にflask,jester,echo,spark)を用いて簡単なAPIを作成し、その手軽さを比較してみました
環境
Python 3.6.4
Nim 0.19.2
Go 1.11.4
Kotlin 1.3.21
MySQL 5.7.25
MySQLクライアント
Python: PyMySQL
Nim: db_mysql
Go: go-sql-driver/mysql
Kotlin: kotlin.jdbc
今回はなんとなくORMではなく純粋なMySQLクライアントを使用しました
注意
ド素人エンジニアなのでところどころ間違ったことを記している可能性があります.遠慮なくご指摘いただけるとありがたいです!
データの用意
簡単なデータ処理を行えるように以下のようなデータを用意しました
tasksテーブル
id | name | created_at |
---|---|---|
1 | aaaa | 2019-04-06 23:40:56 |
Python(flask)
Flaskを用いて簡単なAPIを作成します
手軽さ
★★★★★
3分くらいでAPI叩けるようになります
始め方
pythonが入っている前提でお話します
まずはflaskをインストールします
pip install flask
適当なファイルを作成します
mkdir flask_sample
cd flask_sample
touch server.py
ルーティングを定義します
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == '__main__':
app.debug = True
app.run(host='0.0.0.0')
python server.py
デフォルトが5000番ポートみたいなのでアクセスすればブラウザにHelloWorldが表示されます
http://127.0.0.1:5000/
DB操作
PyMySQLを使用してデータベースに接続し操作を行います
ルーティングをtasks/[taskId]
にして指定したIDのデータを取得して返します
pip install PyMySQL
server.py
を以下のように変更
from flask import Flask, jsonify
import pymysql.cursors
app = Flask(__name__)
def getDBConnection():
return pymysql.connect(
host='host',
port=port, # 文字列ではなくint
user='user',
passwd='pass',
db='db',
cursorclass=pymysql.cursors.DictCursor
)
@app.route("/tasks/<int:taskId>")
def hello(taskId):
task = getTask(taskId)
return jsonify(task)
def getTask(taskId):
conn = getDBConnection()
try:
with conn.cursor() as cursor:
# Read a single record
sql = "SELECT * FROM `tasks` WHERE id = %s"
cursor.execute(sql, (taskId,))
result = cursor.fetchone()
return result
finally:
conn.close()
return result
if __name__ == '__main__':
app.debug = True
app.run(host='0.0.0.0') # 127.0.0.1 だとpostmanから叩けません多分…
http://localhost:5000/tasks/1
でjsonが帰ってくるはずです
Nim(jester)
Nimはpythonライクに書けるコンパイラ言語です
処理速度がめちゃ早いらしい
Nim言語感想&概説
至高の言語、Nimを始めるエンジニアへ
jester を使います
手軽さ
★★★☆☆
こちらも5分くらいでAPIサーバーが立ちます
がNimの手軽さを考慮して★3つ
始め方
webフレームワークjester
のインストール
nimble install jester
適当なファイルを作成
touch server.nim
中身
import jester
routes:
get "/":
resp "Hello world!"
実行
nim c -r server.nim
http://localhost.5000
でHello world!
が表示されます!これまた早い!
DB操作
db_mysqlを使用してデータベースに接続し操作を行います
ルーティングをtasks/[taskId]
にして指定したIDのデータを取得して返します
Nimは型定義もできますが、var
を使用すれば型推論してくれます
import jester, random, strutils, asyncdispatch, json, db_mysql, times
proc getDBConnection(): DbConn =
open("host:port", "user", "pass", "db")
proc getTask(taskId: int): Row =
var dbConn: DbConn = getDBConnection()
var task: Row = dbConn.getRow(sql "SELECT * FROM tasks WHERE id = " & $taskId)
result = task # resultが返り値になります
routes:
get "/tasks/@id":
var task: Row = getTask(parseInt(@"id"))
var data = %*{"id": task[0], "name": task[1], "created_at": task[2]}
resp $data, "application/json"
http://localhost:5000/tasks/1
でjsonが帰ってくるはずです
Go(echo)
入門手軽さ
★★★★☆
こちらも超軽量フレームワークなので一瞬で立てれます
goのプロジェクト作成とかとか少し面倒?なので4つ
始め方
僕はgvmでgoのバージョンを管理しているのでバージョンを指定してGOPATHに入ります
gvm use 1.11.4
cd $GOPATH/src
mkdir go_api
cd go_api
今回はechoを使用します
go get -u github.com/labstack/echo/...
ファイルを作成
touch server.go
package main
import (
"net/http"
"github.com/labstack/echo"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":1323"))
}
実行します
go run main.go server.go 21:26:02
____ __
/ __/___/ / ___
/ _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.0.0
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
O\
⇨ http server started on [::]:1323
http://localhost:1323
でHello, World!が表示されます
DB操作
今回はgo-sql-driver/mysqlを使用します
goはデータを構造体で定義してそこにマッピングしていくことでができます
構造体を定義する際にjsonで返す時のキーも指定できます
go get github.com/go-sql-driver/mysql
package main
import (
"database/sql"
"fmt"
"log"
"net/http"
"strconv"
"time"
_ "github.com/go-sql-driver/mysql"
"github.com/labstack/echo"
)
type Task struct {
ID int `json:"id"`
Name string `json:"name"`
CreatedAt *time.Time `json:"created_at"`
}
func main() {
e := echo.New()
e.GET("/tasks/:id", getTask)
e.Logger.Fatal(e.Start(":1323"))
}
func getDBConnection() *sql.DB {
db, err := sql.Open("mysql", "username:pasword@tcp(host:port)/dbname?parseTime=true") //parseTime=trueがないとtime.Timeがうまくparseできない
if err != nil {
panic(err.Error())
}
return db
}
func getTask(c echo.Context) error {
id, _ := strconv.Atoi(c.Param("id")) // c.Param("id")でクエリパラメータ取得
task := selectTask(id)
return c.JSON(http.StatusOK, task) // 200とjsonを返す
}
func selectTask(id int) Task {
db := getDBConnection() // db接続
defer db.Close() // 最後にCloseする宣言
task := Task{} // 構造体の初期化
// select文の発行と構造体のそれぞれのメンバーにマッピング
if err := db.QueryRow("SELECT * FROM tasks WHERE id = ?", id).Scan(&task.ID, &task.Name, &task.CreatedAt); err != nil {
log.Fatal(err)
}
return task
}
http://localhost:1323/tasks/1
でjsonが帰ってくるはずです
Kotlin(spark)
入門手軽さ
★☆☆☆☆
gradle+sparkでやってますが、HelloWorldを表示させるのも一苦労でした
IDEに頼らずコマンドライン縛りでやったら
2〜3時間かかりました…
が、以下コピペで10分くらいで立ち上げれます
mavenに挫折してgradleにしました
始め方
gradleプロジェクトを作成します
使用バージョンは以下です
$ gradle -v
------------------------------------------------------------
Gradle 5.3.1
------------------------------------------------------------
Build time: 2019-03-28 09:09:23 UTC
Revision: f2fae6ba563cfb772c8bc35d31e43c59a5b620c3
Kotlin: 1.3.21
Groovy: 2.5.4
Ant: Apache Ant(TM) version 1.9.13 compiled on July 10 2018
JVM: 1.8.0_161 (Oracle Corporation 25.161-b12)
OS: Mac OS X 10.14.3 x86_64
gradleプロジェクトをkotlin-application
を指定して作成します
$ gradle init --dsl kotlin
Select type of project to generate:
1: basic
2: cpp-application
3: cpp-library
4: groovy-application
5: groovy-library
6: java-application
7: java-library
8: kotlin-application
9: kotlin-library
10: scala-library
Enter selection (default: basic) [1..10] 8
Project name (default: api):
Source package (default: api):
BUILD SUCCESSFUL in 7s
2 actionable tasks: 2 executed
build.gradle.kts
にsparkの依存関係と必要な依存関係を追加します
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Kotlin application project to get you started.
*/
plugins {
// Apply the Kotlin JVM plugin to add support for Kotlin on the JVM.
id("org.jetbrains.kotlin.jvm").version("1.3.21")
// Apply the application plugin to add support for building a CLI application.
application
}
repositories {
// Use jcenter for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
dependencies {
// Use the Kotlin JDK 8 standard library.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// Use the Kotlin test library.
testImplementation("org.jetbrains.kotlin:kotlin-test")
// Use the Kotlin JUnit integration.
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
compile("com.sparkjava:spark-core:+")
compile("org.slf4j:slf4j-log4j12:1.7.21")
}
application {
// Define the main class for the application.
mainClassName = "api.AppKt"
}
src/main/kotlin/api/App.kt
を編集します
package api
import spark.Spark.*
fun main(args: Array<String>) {
get("/") { req, res -> "Hello World" }
}
gradleを実行します
$ gradle run
> Task :run
log4j:WARN No appenders could be found for logger (spark.route.Routes).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
<==========---> 80% EXECUTING [7s]
> :run
http://localhost:4567/
これでHello Worldが表示されます
DB操作
jdbcとjsonのマッパーの依存関係を追加します
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Kotlin application project to get you started.
*/
plugins {
// Apply the Kotlin JVM plugin to add support for Kotlin on the JVM.
id("org.jetbrains.kotlin.jvm").version("1.3.21")
// Apply the application plugin to add support for building a CLI application.
application
}
repositories {
// Use jcenter for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
dependencies {
// Use the Kotlin JDK 8 standard library.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// Use the Kotlin test library.
testImplementation("org.jetbrains.kotlin:kotlin-test")
// Use the Kotlin JUnit integration.
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
compile("com.sparkjava:spark-core:+")
compile("org.slf4j:slf4j-log4j12:1.7.21")
compile("org.jetbrains.kotlin:kotlin-jdbc:0.10.1316")
compile("joda-time:joda-time:2.10.1")
compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.8.8")
compile("com.fasterxml.jackson.core:jackson-databind:2.8.8.1")
}
application {
// Define the main class for the application.
mainClassName = "api.AppKt"
}
App.ktを編集します
/*
* This Kotlin source file was generated by the Gradle 'init' task.
*/
package api
import spark.Spark.*
import spark.*
import java.sql.DriverManager
import java.util.*
import java.sql.Connection;
import java.sql.Statement
import java.sql.ResultSet
import org.joda.time.DateTime
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import spark.ResponseTransformer
data class Task(
var id: Long,
var name: String,
// jdbcがDateTimeをうまく扱ってくれないのでString
var createdAt: String
)
fun main(args: Array<String>) {
Class.forName("com.mysql.jdbc.Driver");
val toJson = JsonTransformer(ObjectMapper().registerKotlinModule())
path("/tasks"){
get("/:id", getTask(),toJson)
}
}
fun getTask(): Route = Route { req, _ ->
findTask(req.params("id").toInt())
}
fun findTask(id: Int): Task {
lateinit var task: Task
var statement: Statement? = null
statement = getDBConnection()?.createStatement()
var resultSet: ResultSet? = statement?.executeQuery("SELECT * FROM tasks WHERE id = ${id}")
while(resultSet?.next() ?:false) {
var sdf :java.text.SimpleDateFormat = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
var date = Date(resultSet!!.getTimestamp(3).getTime())
task = Task(resultSet!!.getLong(1),resultSet!!.getString(2),sdf.format(date))
}
resultSet?.close()
statement.close()
return task
}
// DB接続
fun getDBConnection(): Connection {
var conn: Connection = DriverManager.getConnection("jdbc:mysql://host:port/db","username","pass")
return conn
}
// jsonにマッピング
class JsonTransformer(private val objectMapper: ObjectMapper) : ResponseTransformer {
override fun render(model: Any?): String =
objectMapper.writeValueAsString(model)
}
実行します
gradle run
http://localhost:4567/tasks/1
これでjsonが帰ってきます
ちなみにkotlinは入門難易度が高すぎです
このjson返すまで3時間かかりました笑笑笑
参考
[Python] Flask 入門
Python3からMySQL繋ぐ時は、いろいろあるけどとりあえずPyMySQLにしとこうや
Nim 言語で RESTful API 作ってみた
Nim言語感想&概説
至高の言語、Nimを始めるエンジニアへ
goでtime.Timeをmysqlから読む
Goでmysqlに接続する
Gradle 5.0 で作れるようになった build.gradle.kts と settings.gradle.kts
Kotlin+Spark FrameworkでAPI作ってみた
GradleでKotlinのプロジェクトを作成する
フレームワーク
Flask
Jester
Go Echo
Spark Framework
所属
レッドインパルス 株式会社ではインターン生を積極的に募集しています!
興味ある方はぜひ!!
株式会社POLでも募集しています!