---
# System prepended metadata

title: TwitterClone
tags: [Products]

---

# TwitterClone
###### tags: `Products`

### フロントエンド
- Nextjs
- Apollo
- GraphQL-CodeGenerator
- TailwindCSS
- RadixUI
- Stitches
- Vercel

### バックエンド
- Nestjs(Express, GraphQL)
- TypeORM
- PostgreSQL
- Docker
- Heroku

### 認証
- next-firebase-auth

# 参考になりそうな記事

**Next.js, Apollo Client and Server on a single Express app**
> https://dev.to/givehug/next-js-apollo-client-and-server-on-a-single-express-app-55l6

**NestJS/Next.js/GraphQL**
> https://zenn.dev/mikan3rd/articles/5b7840cdbcd2d9

**Heroku/Nodejs starter**
> https://devcenter.heroku.com/articles/getting-started-with-nodejs#provision-a-database
--- 

**Continuous deployment of an Express GraphQL server to Heroku**
> https://circleci.com/blog/continuous-deployment-of-an-express-graphql-server-to-heroku/

# 今回使わないけど気になった技術

## [aspida](https://github.com/aspida/aspida)
- RESTAPIに型定義ができるライブラリ
- パス、URLクエリ、ヘッダー、本文、応答のすべての型を指定できる
- FormData/URLSearchParamsコンテンツのタイプを指定することも
- HTTPクライアントはaxios/fetch/node-fetchをサポート

> https://zenn.dev/solufa/articles/getting-started-with-aspida
> https://qiita.com/yoshii0110/items/d3db124865fb8131ff51
> https://qiita.com/m_mitsuhide/items/9ce4e048749075845655

## [frourio](https://frourio.io/)
- TypeScriptフルスタック環境を一発で作れる軽量フレームワーク
> 
>https://qiita.com/m_mitsuhide/items/00b139bb565dddf8006a
> https://github.com/frouriojs/frourio
> https://zenn.dev/jun1123/articles/deploy-frourio

![](https://i.imgur.com/i3Kk3QC.png)



## fastify
- JavaScriptの軽量バックエンドフレームワーク

## Golang
- 早いバックエンド言語


--- 
# 🔥 Nextjs

## 📦 react-apollo
> サンプルコード
> https://qiita.com/mizchi/items/c078aea032cd00ba3e86

## 📦 SWR

### 🪝 useSWR
> Doc
> https://swr.vercel.app/docs/options


> サンプルコード
> https://zenn.dev/mast1ff/articles/40b3ea4e221c36

## 📦 apollo-client

### 🪝 useQuery

> Doc
https://www.apollographql.com/docs/react/api/react/hooks/


# 🍁 Vercel


# 🌙 TailwindCSS

# 🍀 GraphQL

## Resolvers
何をレスポンスするのかの処理を書く

## Query
Query は REST APIの GET に相当します。

> 多分取得はuseQueryでやるかも？
> SWRでやってみたさもある

> サンプルコード
> https://qiita.com/ut0n/items/83b5836bc542c8f9bc71

> express-graphql
> https://github.com/graphql/express-graphql

# ⚡️ Express

## 📦 Gulp （Grunt）


## 📦 express-graphql
> README
> https://github.com/graphql/express-graphql

**サーバー起動**
```javascript=
const restify = require('restify');
const { graphqlHTTP } = require('express-graphql');

const app = restify.createServer();

// -----------------------------
app.use(
  '/graphql',
  graphqlHTTP({
    schema: MyGraphQLSchema,
    graphiql: true,
  }),
);

// ----------- or --------------
app.post(
  '/graphql',
  graphqlHTTP({
    schema: MyGraphQLSchema, // GraphQLのGraphQLSchemaインスタンス
    graphiql: false, // ブラウザにgraphiqlを表示するか
  }),
);

app.get(
  '/graphql',
  graphqlHTTP({
    schema: MyGraphQLSchema, // GraphQLのGraphQLSchemaインスタンス
    graphiql: true, // ブラウザにgraphiqlを表示するか
  }),
);
// -----------------------------

app.listen(4000);
```

### 🔧 graphqlHTTPのオプション

> README-options
> https://github.com/graphql/express-graphql#options

- schema
    - GraphQLのGraphQLSchemaインスタンス
    - スケジュールを提供する必要がある
- pretty
    - trueの場合、JSON応答はすべて綺麗に出力される
- validationRules
    - GraphQLの仕様で定義されているものに加えて、クエリが満たさなければならないオプションの追加の検証ルール
- customValidateFn
    - Graphqlからのデフォルトの実行の代わりに実行するために使用されるオプションの関数
- rootValue
    - 関数を渡す
    
💡 非同期処理もできる
```javascript=
app.use(
  '/graphql',
  graphqlHTTP(async (request, response, graphQLParams) => ({
    schema: MyGraphQLSchema,
    rootValue: await someFunctionToGetRootValue(request),
    graphiql: true,
  })),
);
```

### HTTPの使用法

パスにインストールされるexpress-graphqlと、次のパラメータを使用してリクエストを受け入れます。

- query
    - 実行される文字列GraphQLドキュメント
- variables
    - JSONオブジェクトとしてGraphQLクエリ変数に使用するランタイム値
- operationName
    - 提供さqueryれたものに複数の名前付き操作が含まれている場合、これはどの操作を実行するかを指定します。指定しない場合、queryに複数の名前付き操作が含まれていると、400エラーが返されます。
- raw
    - graphiqlオプションが有効でrawパラメーターが指定されている場合、ブラウザーからロードされた場合でも、GraphiQLではなく生のJSONが常に返されます。

GraphQLは最初にURLのクエリ文字列内の各パラメーターを検索し、見つからなかった場合はPOSTリクエストの本文を検索する

    /graphql?query=query+getUser($id:ID){user(id:$id){name}}&variables={"id":"4"}


以前のミドルウェアがすでにPOST本体を解析しているrequest.body 場合は、その値が使用される

multerまたは同様のミドルウェアを使用して、multipart/form-dataコンテンツのサポートを追加します。これは、ファイルのアップロードを伴うGraphQLミューテーションに役立つ場合があります。multerを使用した例を参照してください

## 📦 Multer

> サンプルコード
> https://tech.chakapoko.com/nodejs/express/upload.html

### Multerについて
- フロントエンドとバックエンドとのデータのやり取りでは、html、javascript、png、jsonなど様々な種類のデータを扱う
- その際に、どんなデータを扱っているのかを指定する必要がある
- そののデータの種類を指定するために、MIME Typeという形式が利用されている
- それをHTTPのヘッダ（Content-Typeヘッダ）に付与して、送信先にコンテンツの種類を伝えることをしないといけない
        htmlファイルを受け取る場合のHTTPヘッダ
> MIME Typeの種類
>https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types

### 🤔 MIME Typeの中でも、multipart/form-dataを使うには？


**✍️ multipart/form-data形式でリクエストを投げてみる**

HTMLフォームで複合型を使うには、formタグの属性でenctype="multipart/form-data"を指定しないといけない
これをPOSTすると、multipart/form-data形式でサーバーにデータが送信される

```htmlembedded=
<form method="POST" action="/upload" enctype="multipart/form-data">
    <input type="text" name="message" value="Hello"/><br>
    <input type="file" name="file"/><br>
    <input type="submit" value="SUBMIT"/>
</form>
```
**✍️ HTTPヘッダーで確認**

これをリクエストで受けた側のサーバーでHTTPヘッダーを確認すると、このデータ形式がmultipart/form-dataであることが確認できる

**✍️ HTTPボディを確認**

```shell=
------WebKitFormBoundaryO5quBRiT4G7Vm3R7
Content-Disposition: form-data; name="message"

Hello # <- input(text)からのメッセージ

------WebKitFormBoundaryO5quBRiT4G7Vm3R7
Content-Disposition: form-data; name="file"; filename="a.txt"
Content-Type: text/plain

aaa # <- input(file)からの送られたファイルの内容（この場合は、"a.txt"ファイルの中に書いてある文字列）
------WebKitFormBoundaryO5quBRiT4G7Vm3R7--
```

**👍 複数のデータ型をまとめて扱うことができる形式がmultipart/form-data形式**
> 参考
> https://www.yoheim.net/blog.php?q=20171201



# ❄️ Heroku

> 
> https://circleci.com/blog/continuous-deployment-of-an-express-graphql-server-to-heroku/

# 🪨 ORM

>https://qiita.com/yk-nakamura/items/acd071f16cda844579b9

- データベースからデータを取得する
- 取得したデータをオブジェクト化する
- データの更新・変更などをデータベースに格納する

普通にデータベースからデータを取得して、フロントエンドにレスポンスを返す場合、データをオブジェクト形式に変換しないといけない

1. **DB取得**
![](https://i.imgur.com/NGWptl0.png)
1. **オブジェクト変換（PHP）**
![](https://i.imgur.com/KAUQUm1.png)


しかし、ORMを利用すると上記３点のことを自動でやってくれる

テーブルデータは単純な連想配列みたいなものなので、オブジェクトとして使うには自前でオブジェクト化するための仕組みを作らなければならなかった


## ORMのメリット
1. SQLを書かなくていい
2. SQLという「別言語」を混在させずに済む
3. 良いSQLを作ってくれる


## ORMのデメリット
1. SQLを書けなくてもできてしまう
2. JOINを使わないかもしれない（これが悪いとも言い切れない）
3. 嫌ってる人がいる

> 参考
> https://qiita.com/niisan-tokyo/items/156eb35c6eeaf07b9b65


## 📦 [TypeORM](https://typeorm.io/)

- 公式ドキュメントはわかりやすく、ボリュームもそこまでないので学習コストは低め
- リレーショナルDBサポート (MySQL / MariaDB / Postgres / CockroachDB / SQLite / Microsoft SQL Server / Oracle / sql.js)
- Entityから差分を自動検知するDB migrationの仕組み
- RepositoryパターンもしくはActiveRecordパターンどちらも採用可
- SQLのQueryBuilderやTransactionの仕組みも提供

> 参考　　https://qiita.com/tejitak/items/b6965380afd600db6513

# 💧 PostgreSQL