처음 ELM.× GraphiQL~Elm에서 포켓몬을 재현할 때까지~
Elm의 시도로 GraphQL Pokemon 데이터만 그리는 프로그램을 만들었다.Elm × 나는 GraphiQL의 입문이 매우 좋다고 생각해서 교과서 형식으로 총결하였다.
만든 물건
GraphQL Pokemon에 조회를 던져 응답을 나타내는 Elm 앱을 제작합니다.
기술 스택은 다음과 같습니다.
0.19.1
5.0.3
5.22.0
1. 프로젝트 제작
create-react-app의 Elm 버전create-elm-app으로 제작된 프로젝트입니다.
주요 파일과 구축 환경을 동시에 만들 수 있어 편리하다.
$ npx create-elm-app my-app
my-app로 이동하면 디렉터리는 다음과 같습니다.my-app/
├── .gitignore
├── README.md
├── elm.json
├── elm-stuff
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo.svg
│ └── manifest.json
├── src
│ ├── Main.elm
│ ├── index.js
│ ├── main.css
│ └── serviceWorker.js
└── tests
└── Tests.elm
애플리케이션을 시작합니다.npx elm-app start
조금만 기다리면localhost 프로그램이 시작됩니다.Elm의 환경 구축이 완료되었습니다.
화면을 제작하는 단계에서는 조형을 수월하게 하기 위해 먼저 엘엠에 CSS 프레임Bulma과 볼마의 등급을 추가해 안전하게 사용형
ahstro/elm-bulma-classes
을 적용한다.$ yarn add bulma
$ elm install ahstro/elm-bulma-classes
src/index.js에 다음 내용을 보충해 주십시오.이렇게 구성할 때 Bullma의 CSS를 읽습니다.index.js
import 'bulma/css/bulma.min.css';
2.elm-graphiql &CodeGenerate 증가
Elm의 GraphQL 클라이언트는 여러 가지가 있지만 이번에는 GraphQL 조회를 안전하게 쓰려고 GraphQL 모드를 이용해 유형과 관련 함수
dillonkearns/elm-graphql
를 자동으로 생성한다.먼저 설치합니다.
elm-graphiql은 elm의 포장뿐만 아니라 npm의 포장도 추가하는 것이 중점이다.
elm-graphiql의 Code Generatr 스크립트를 계속 시작합니다.제이슨에 기입하다.
여기GraphQL Pokemon의 URL을 지정합니다.
package.json
$ elm install dillonkearns/elm-graphql
$ elm install elm/json
$ elm install krisajenkins/remotedata
$ yarn add -D @dillonkearns/elm-graphql
이 상태에서 yarn code:generate
를 실행하면 다음과 같은 src/Pokemons
파일이 자동으로 생성됩니다. "scripts": {
"code:generate": "elm-graphql https://graphql-pokemon2.vercel.app/ --base Pokemon"
}
Elm에서 GraphiQL을 안전하게 사용하는 간이다.3. 설치
호스트가 설치됩니다.
코드가 길기 때문에 요점만 발췌합니다.
전체 코드는 아래를 보세요.
GraphQLClient.elm
src/GraphqlClient.elm
src/Pokemon/
├── Enum
├── InputObject
├── InputObject.elm
├── Interface
├── Interface.elm
├── Object
│ ├── Attack.elm
│ ├── Pokemon.elm
│ ├── PokemonAttack.elm
│ ├── PokemonDimension.elm
│ └── PokemonEvolutionRequirement.elm
├── Object.elm
├── Query.elm
├── Scalar.elm
├── ScalarCodecs.elm
├── Union
├── Union.elm
├── VerifyScalarCodecs.elm
└── elm-graphql-metadata.json
Main.elmsrc/Main.elm
module GraphQLClient exposing (makeGraphQLQuery)
import Graphql.Http
import Graphql.Operation exposing (RootQuery)
import Graphql.SelectionSet as SelectionSet exposing (SelectionSet)
graphql_url : String
graphql_url =
"https://graphql-pokemon2.vercel.app/"
makeGraphQLQuery : SelectionSet decodesTo RootQuery -> (Result (Graphql.Http.Error decodesTo) decodesTo -> msg) -> Cmd msg
makeGraphQLQuery query decodesTo =
query
|> Graphql.Http.queryRequest graphql_url
|> Graphql.Http.send decodesTo
GraphQL Client
GraphiQL 요청을 보낸 고객입니다.
GraphiQL Pokemon은 인증이 필요하지 않기 때문에, 단점의 URL을 elm-graphiql에서 제공하는 함수에 전달하면 됩니다.
src/GraphQLClient.elm
module Main exposing (..)
import Browser
import Bulma.Classes as Bulma
import GraphQLClient exposing (makeGraphQLQuery)
import Graphql.Http
import Graphql.Operation exposing (RootQuery)
import Graphql.SelectionSet as SelectionSet exposing (SelectionSet)
import Html exposing (Html, div, figure, h1, img, p, text)
import Html.Attributes exposing (class, src)
import List
import Pokemon.Object
import Pokemon.Object.Pokemon as Pokemon
import Pokemon.Query as Query exposing (PokemonsRequiredArguments)
import Pokemon.ScalarCodecs
import RemoteData exposing (RemoteData)
---- MODEL ----
type alias Pokemon =
{ id : Pokemon.ScalarCodecs.Id
, name : Maybe String
, image : Maybe String
}
type alias Pokemons = Maybe (List (Maybe Pokemon))
type alias PokemonData =
RemoteData (Graphql.Http.Error Pokemons) Pokemons
type alias Model =
{ pokemons : PokemonData }
init : ( Model, Cmd Msg )
init =
( { pokemons = RemoteData.Loading
}
, fetchPokemons 151
)
---- UPDATE ----
type Msg
= FetchDataSuccess PokemonData
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
FetchDataSuccess response ->
updatePokemonsData response model Cmd.none
updatePokemonsData : PokemonData -> Model -> Cmd Msg -> ( Model, Cmd Msg )
updatePokemonsData data model cmd =
( { model | pokemons = data }, cmd )
---- VIEW ----
view : Model -> Html Msg
view model =
div [ class Bulma.container ]
[ img [ src "https://i.gyazo.com/480551bded5134ddacf08616b2595717.png" ] []
, h1 [ class Bulma.title, class Bulma.is4, class Bulma.mb6 ] [ text "Pokemons with elm-graphql" ]
, renderPokemonList model.pokemons
]
renderPokemonList : PokemonData -> Html Msg
renderPokemonList pokemonData =
let
renderPokemon pokemon =
div [ class Bulma.card ]
[ div [ class Bulma.cardImage ]
[ figure [ class Bulma.image, class Bulma.is16by9, class Bulma.mx5, class Bulma.mt5 ]
[ img [ src (pokemon.image |> Maybe.withDefault "") ] []
]
]
, div [ class Bulma.cardContent ]
[ p [ class Bulma.isSize4 ] [ text (pokemon.name |> Maybe.withDefault "") ]
]
]
renderPokemons maybePokemons =
maybePokemons
|> Maybe.withDefault []
|> List.map
(\maybePokemon ->
div [ class Bulma.column, class Bulma.is3 ]
[ maybePokemon
|> Maybe.map renderPokemon
|> Maybe.withDefault (text "")
]
)
|> div [ class Bulma.columns, class Bulma.isMultiline ]
in
case pokemonData of
RemoteData.NotAsked ->
p [ class Bulma.isSize4, class Bulma.hasTextCentered ] [ text "not" ]
RemoteData.Success maybePokemons ->
renderPokemons maybePokemons
RemoteData.Loading ->
p [ class Bulma.isSize4, class Bulma.hasTextCentered ] [ text "loading..." ]
RemoteData.Failure err ->
p [ class Bulma.isSize4, class Bulma.hasTextCentered ] [ text "Error" ]
---- GraphQL API ----
pokemonsRequiredArguments : Int -> PokemonsRequiredArguments
pokemonsRequiredArguments num =
{ first = num }
pokemonListSelection : SelectionSet Pokemon Pokemon.Object.Pokemon
pokemonListSelection =
SelectionSet.map3 Pokemon
Pokemon.id
Pokemon.name
Pokemon.image
fetchPokemonsQuery : Int -> SelectionSet Pokemons RootQuery
fetchPokemonsQuery num =
Query.pokemons (pokemonsRequiredArguments num) pokemonListSelection
fetchPokemons : Int -> Cmd Msg
fetchPokemons num =
makeGraphQLQuery (fetchPokemonsQuery num) (RemoteData.fromResult >> FetchDataSuccess)
---- PROGRAM ----
main : Program () Model Msg
main =
Browser.element
{ view = view
, init = \_ -> init
, update = update
, subscriptions = always Sub.none
}
Type alias & Model
Main.엘엠의 type alias와 모델입니다.
GraphiQL 요청의 응답은
krisajenkins/remotedata
의RemoteData로 처리됩니다.init에서 포켓몬을 가져오는 GraphiQL 조회를 실행 중입니다.main.elm
graphql_url : String
graphql_url =
"https://graphql-pokemon2.vercel.app/"
makeGraphQLQuery : SelectionSet decodesTo RootQuery -> (Result (Graphql.Http.Error decodesTo) decodesTo -> msg) -> Cmd msg
makeGraphQLQuery query decodesTo =
query
|> Graphql.Http.queryRequest graphql_url
|> Graphql.Http.send decodesTo
GraphQL Query
이것은 GraphiQL의 조회 부분입니다.
pokemonsRequiredArguments
에서 GraphiQL이 질의할 때의 매개변수입니다.조립pokemonListSelection
에서 얻은 필드입니다.fetchPokemonsQuery
에서 어떤 조회를 호출할지 지정합니다.이것은 Query.pokemons
자동으로 생성된 함수다.마지막으로
elm-graphql
에서 방금 제작한fetchPokemons
을 사용하여GraphiQL 요청을 수행하는 함수를 제작합니다.elm-graphiql에서 제공하는 형식 함수를 사용하여 형식을 완전히 준수한 상태에서GraphiQL 조회를 할 수 있습니다.대단해!
Main.elm
type alias Pokemon =
{ id : Pokemon.ScalarCodecs.Id
, name : Maybe String
, image : Maybe String
}
type alias Pokemons =
Maybe (List (Maybe Pokemon))
type alias PokemonData =
RemoteData (Graphql.Http.Error Pokemons) Pokemons
type alias Model =
{ pokemons : PokemonData }
init : ( Model, Cmd Msg )
init =
( { pokemons = RemoteData.Loading
}
, fetchPokemons 151
)
Update
Update를 통해 상태를 변경합니다.
GraphiQL 조회를 실행한 후 FetchDataSuccess의 Msg를 통해 응답 업데이트 모델입니다.
Main.elm
pokemonsRequiredArguments : Int -> PokemonsRequiredArguments
pokemonsRequiredArguments num =
{ first = num }
pokemonListSelection : SelectionSet Pokemon Pokemon.Object.Pokemon
pokemonListSelection =
SelectionSet.map3 Pokemon
Pokemon.id
Pokemon.name
Pokemon.image
fetchPokemonsQuery : Int -> SelectionSet Pokemons RootQuery
fetchPokemonsQuery num =
Query.pokemons (pokemonsRequiredArguments num) pokemonListSelection
fetchPokemons : Int -> Cmd Msg
fetchPokemons num =
makeGraphQLQuery (fetchPokemonsQuery num) (RemoteData.fromResult >> FetchDataSuccess)
View
마지막은 View입니다.
makeGraphQLQuery
pokemonData의 RemoteData 값에 따라 변경 처리.결과의 HTML은 RemoteData가 Success인 경우에만 표시됩니다.
RemoteData를 사용하면 팟캐스트할 때 로드 문자열을 쉽게 보낼 수 있어 좋습니다.
GraphiQL Pokemon의 반응은 등급별 메이브형이지만 메이브형을 제거하면서 HTML을 조립하는 과정에 익숙하지 않아 막힌다.마지막으로 여기.의 문장
renderPokemons
과 Maybe.withDefault
을 참고하여 쓰겠습니다.메이비형을 좀 더 스마트하게 다룰 수 있는 방법이 있다면 알고 싶어요🙏
2010/12/2220:00 추기
Elm의 선교사들의 권유로 "let in"을 사용한 표기법을 팩스로 전송했습니다.감사🙏
type Msg
= FetchDataSuccess PokemonData
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
FetchDataSuccess response ->
updatePokemonsData response model Cmd.none
updatePokemonsData : PokemonData -> Model -> Cmd Msg -> ( Model, Cmd Msg )
updatePokemonsData data model cmd =
( { model | pokemons = data }, cmd )
이상 종료.다음 명령을 실행하면 포켓몬이 나타날 거예요!
완성🎉
view : Model -> Html Msg
view model =
div [ class Bulma.container ]
[ img [ src "https://i.gyazo.com/480551bded5134ddacf08616b2595717.png" ] []
, h1 [ class Bulma.title, class Bulma.is4, class Bulma.mb6 ] [ text "Pokemons with elm-graphql" ]
, renderPokemonList model.pokemons
]
renderPokemonList : PokemonData -> Html Msg
renderPokemonList pokemonData =
let
renderPokemon pokemon =
div [ class Bulma.card ]
[ div [ class Bulma.cardImage ]
[ figure [ class Bulma.image, class Bulma.is16by9, class Bulma.mx5, class Bulma.mt5 ]
[ img [ src (pokemon.image |> Maybe.withDefault "") ] []
]
]
, div [ class Bulma.cardContent ]
[ p [ class Bulma.isSize4 ] [ text (pokemon.name |> Maybe.withDefault "") ]
]
]
renderPokemons maybePokemons =
maybePokemons
|> Maybe.withDefault []
|> List.map
(\maybePokemon ->
div [ class Bulma.column, class Bulma.is3 ]
[ maybePokemon
|> Maybe.map renderPokemon
|> Maybe.withDefault (text "")
]
)
|> div [ class Bulma.columns, class Bulma.isMultiline ]
in
case pokemonData of
RemoteData.NotAsked ->
p [ class Bulma.isSize4, class Bulma.hasTextCentered ] [ text "not" ]
RemoteData.Success maybePokemons ->
renderPokemons maybePokemons
RemoteData.Loading ->
p [ class Bulma.isSize4, class Bulma.hasTextCentered ] [ text "loading..." ]
RemoteData.Failure err ->
p [ class Bulma.isSize4, class Bulma.hasTextCentered ] [ text "Error" ]
끝말
이상× GraphiQL”.
예전에 Elm의 학습회에 참가한 적이 있어요. 이렇게 했지만 결국 Elm을 접할 기회가 없어서 Elm advent 달력 기한 4일 전에 갑자기 이걸 했어요.😅
아직 Elm에 익숙하지 않아서 이상한 점이 있으면 편하게 메모를 남겨주시면 좋을 것 같아요.
솔직히 처음에는 아무리 해도 번역 오류를 바로잡을 수 없었고 완전히 꽉 차서 새로운 언어를 끊임없이 모색하면서 공부하는 과정이 재미있었다.
이번 앱 제작은 엘엠과 조금 친해진 것 같아서 천천히 쓸 기회를 보고 싶었다.
참고 자료
Reference
이 문제에 관하여(처음 ELM.× GraphiQL~Elm에서 포켓몬을 재현할 때까지~), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/ryo_kawamata/articles/elm-graphql-pokemon텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)