This course is no longer maintained and may be out-of-date. While it remains available for reference, its content may not reflect the latest updates, best practices, or supported features.
Subscription
Lets use the ports defined in the previous step to open a subscription client
Imports
Open src/Main.elm
and add the following code:
+import Graphql.Documentimport Graphql.Http- import Graphql.Operation exposing (RootMutation, RootQuery)+import Graphql.Operation exposing (RootMutation, RootQuery, RootSubscription)+import Hasura.Object.Online_users as OnlineUser+import Hasura.Subscription as Subscription
Construct GraphQL Subscription
updateLastSeen : String -> SelectionSet (Maybe MutationResponse) RootMutation -> Cmd MsgupdateLastSeen authToken updateQuery =makeGraphQLMutationauthTokenupdateQuery(RemoteData.fromResult >> UpdateLastSeen)+onlineUsersSubscription : SelectionSet OnlineUsers RootSubscription+onlineUsersSubscription =+ Subscription.online_users identity onlineUsersSelection+++onlineUsersSelection : SelectionSet OnlineUser Hasura.Object.Online_users+onlineUsersSelection =+ SelectionSet.map2 OnlineUser+ OnlineUser.id+ (OnlineUser.user selectUser)
Add/Update Data Types
Configure subscriptions and update getInitialEvent
to initiate a subscription connection via ports. The subscription in this case will remain active as long as apollo client connection is live.
Here is what it is doing: 1) Initiate a subscription a connection on page load/successful login 2) Configure elm subscription to listen to any changes from the javascript side.
- type alias OnlineUser =- { id : String- , user : User- }+type alias OnlineUser =+ { id : Maybe String+ , user : Maybe User+ }+type alias OnlineUsersData =+ RemoteData Decode.Error OnlineUserstype alias Model ={ privateData : PrivateTodo, publicTodoInsert : String, publicTodoInfo : PublicTodoData- , online_users : OnlineUsers+ , online_users : OnlineUsersData, authData : AuthData, authForm : AuthForm}- generateOnlineUser : Int -> OnlineUser- generateOnlineUser id =- OnlineUser (String.fromInt id) (generateUser id)--- getOnlineUsers : OnlineUsers- getOnlineUsers =- List.map generateOnlineUser seedIdsinitialize : Modelinitialize ={ privateData = initializePrivateTodo- , online_users = getOnlineUsers+ , online_users = RemoteData.NotAsked, publicTodoInsert = "", publicTodoInfo = PublicTodoData getPublicTodos 0 1 0 True, authData = AuthData "" "" "" "", authForm = AuthForm Login False False ""}subscriptions : Model -> Sub Msgsubscriptions model =case String.length model.authData.authToken of0 ->Sub.none_ ->Sub.batch+ [ gotOnlineUsers GotOnlineUsers, Time.every 30000 Tick]getInitialEvent : String -> Cmd MsggetInitialEvent authToken =Cmd.batch[ fetchPrivateTodos authToken+ , createSubscriptionToOnlineUsers ( onlineUsersSubscription |> Graphql.Document.serializeSubscription, authToken )]
Add new Msg type
type Msg= EnteredEmail String| EnteredPassword String| EnteredUsername String| MakeLoginRequest| MakeSignupRequest| ToggleAuthForm DisplayForm| GotLoginResponse LoginResponseParser| GotSignupResponse SignupResponseParser| ClearAuthToken| FetchPrivateDataSuccess TodoData| InsertPrivateTodo| UpdateNewTodo String| InsertPrivateTodoResponse (GraphQLResponse MaybeMutationResponse)| MarkCompleted Int Bool| UpdateTodo UpdateTodoItemResponse| DelTodo Int| TodoDeleted DeleteTodo| AllCompletedItemsDeleted AllDeleted| DeleteAllCompletedItems| Tick Time.Posix| UpdateLastSeen UpdateLastSeenResponse+ | GotOnlineUsers Decode.Value
Handle new Msg types in update
UpdateLastSeen _ ->( model, Cmd.none)+ GotOnlineUsers data ->+ let+ remoteData =+ Decode.decodeValue (onlineUsersSubscription |> Graphql.Document.decoder) data |> RemoteData.fromResult+ in+ ( { model | online_users = remoteData }, Cmd.none )
Update render functions
- generateOnlineUsersList : OnlineUsers -> List (Html msg)- generateOnlineUsersList onlineUser =- List.map viewOnlineUser onlineUser+generateOnlineUsersList : OnlineUsersData -> List (Html msg)+generateOnlineUsersList onlineUser =+ case onlineUser of+ RemoteData.Success d ->+ List.map viewOnlineUser d++ _ ->+ [ text "" ]- getOnlineUsersCount : OnlineUsers -> Int- getOnlineUsersCount onlineUsers =- List.length onlineUsers+getOnlineUsersCount : OnlineUsersData -> Int+getOnlineUsersCount onlineUsers =+ case onlineUsers of+ RemoteData.Success data ->+ List.length data++ _ ->+ 0- viewOnlineUser : OnlineUser -> Html msg- viewOnlineUser onlineUser =- viewUserName onlineUser.user.name+viewOnlineUser : OnlineUser -> Html msg+viewOnlineUser onlineUser =+ case onlineUser.user of+ Just user ->+ viewUserName user.name++ Nothing ->+ text ""
Add port integration to Main.
Open src/Main.elm
and add the following code:
document.addEventListener("DOMContentLoaded", function() {var app = Elm.Main.init({node: document.getElementById("root")});// ports+ app.ports.createSubscriptionToOnlineUsers.subscribe(function(data) {+ /* Initiate subscription request */+ var [ data, authToken ] = data;+ if (authToken.length > 0) {+ getClient(authToken).subscribe({+ query: gql`${data}`,+ variables: {}+ }).subscribe({+ next(resp) {+ app.ports.gotOnlineUsers.send(resp);+ },+ error(err) {+ console.log('error is');+ console.log(err);+ }+ });+ }+ });})
Awesome! You have completed implementations of a GraphQL Query, Mutation and Subscriptions.
Build apps and APIs 10x faster
Built-in authorization and caching
8x more performant than hand-rolled APIs

