Authors: Sylver-John Imhoff, Mathieu Morainville
When we finished our last project Freatle that used Graphcool as the backend we realized that there was no MySQL equivalent of this really cool BaaS. So we wondered if we could do something similar but instead of relying on GraphQL we would just create some REST endpoints and a MySQL database. The idea of Poorless was born.
When you start a project from scratch and you need a database, you have to install a server locally like MariaDB with Xampp on Windows. This is a waste of time when you are building a side project. With a serverless solution, you just have to call an API to manage your data.
As Poorless should be an API, there is only one good choice: Go. Using the small but good framework Echo, you can build a small API in less than 1 day. The plan is really simple:
e.GET("/:key/table/:table", handler.GetTable)e.GET("/:key/table/:table/:id", handler.GetRowById)e.GET("/:key/table/:table/:filter/:id", handler.GetFilteredRow)e.POST("/:key/table/:table", handler.AddRow)e.PUT("/:key/table/:table/:id", handler.AddRow)e.DELETE("/:key/table/:table", handler.DeleteTable)e.DELETE("/:key/table/:table/:id", handler.DeleteTable)e.DELETE("/:key/table/:table/:filter/:id", handler.DeleteTable)
On the API side, we have a MySQL server running where we store the user’s data. It’s really easy to access and manage the MySQL server with Go.
/*Here we create the user's database*/func CreateDatabase(db *****sql.DB, uid string) {log.Println("Create Database " + uid)_, err := db.Query("Create Database " + uid)if err != nil {log.Fatal(err)}}
As you saw above, we create the routes which the user can call to manage his data. As this is a REST API, one route = one entity. So this route
e.GET("/:key/table/:table", handler.GetTable)
handled by
func GetTable(c echo.Context) error {userId := c.Param("key")table := c.Param("table")
config, configErr := util.GetConfig("./config.json")if configErr != nil {log.Fatal(configErr)}
db := service.GetDatabaseConnexion(config, userId)data := service.FindAll(db, table)
return c.JSON(http.StatusOK, data)}
matches with
/*Here we find all row in the table*/func FindAll(db *****sql.DB, tableName string) *****sql.Rows{query := "Select * From " + tableNamelog.Print(query)rows, err := db.Query(query)if err != nil {log.Fatal(err)}return rows}
Do you see the problem? You are limited.
If you only need to select some fields, add a count, a groupby, etc. you can’t. If you use Poorless, you are limited to the routes that we create. So I asked myself:
How can I let the user customize the request without having to write more routes?
Well the solution already exists and I love it: GraphQL.
With GraphQL, as a client, you tell to the API what you need. With only one request, you can retrieve many entities, add as many filter as you want, etc.
Yes.
I’m not convinced.
Imagine you want to create an app, you hire some mobile developers who cost you 10,000 $ each month. Five months already passed and you need two more months to end the project. But your idea leaked at the beginning of the project without you knowing it. Someone stole it and released the app. Should you invest 20,000 $ to end your project to release an app that already exists? This is called sunk cost. In this case you should stop the app production. Your money is already spent and releasing the app two months later will only make you waste more money.
So did I worked for nothing?
Of course you didn’t. Even if you don’t reach your goal and even if you don’t realize it, you have learn something. Giving up your project will not remove this knowledge and experience from your brain.