mackerel-client 0.1.0 → 0.2.0
raw patch · 12 files changed
+172/−31 lines, 12 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Web.Mackerel.Types.Invitation: InvitationAuthorityCollaborator :: InvitationAuthority
- Web.Mackerel.Types.Invitation: InvitationAuthorityManager :: InvitationAuthority
- Web.Mackerel.Types.Invitation: InvitationAuthorityViewer :: InvitationAuthority
- Web.Mackerel.Types.Invitation: data InvitationAuthority
- Web.Mackerel.Types.Invitation: instance Data.Aeson.Types.FromJSON.FromJSON Web.Mackerel.Types.Invitation.InvitationAuthority
- Web.Mackerel.Types.Invitation: instance Data.Aeson.Types.ToJSON.ToJSON Web.Mackerel.Types.Invitation.InvitationAuthority
- Web.Mackerel.Types.Invitation: instance GHC.Classes.Eq Web.Mackerel.Types.Invitation.InvitationAuthority
- Web.Mackerel.Types.Invitation: instance GHC.Read.Read Web.Mackerel.Types.Invitation.InvitationAuthority
- Web.Mackerel.Types.Invitation: instance GHC.Show.Show Web.Mackerel.Types.Invitation.InvitationAuthority
+ Web.Mackerel.Api.Channel: instance Data.Aeson.Types.FromJSON.FromJSON Web.Mackerel.Api.Channel.ListChannelsResponse
+ Web.Mackerel.Api.Channel: instance Data.Aeson.Types.ToJSON.ToJSON Web.Mackerel.Api.Channel.ListChannelsResponse
+ Web.Mackerel.Api.Channel: listChannels :: Client -> IO (Either ApiError [Channel])
+ Web.Mackerel.Api.Service: createService :: Client -> Service -> IO (Either ApiError Service)
+ Web.Mackerel.Api.Service: deleteService :: Client -> String -> IO (Either ApiError Service)
+ Web.Mackerel.Types.Authority: AuthorityCollaborator :: Authority
+ Web.Mackerel.Types.Authority: AuthorityManager :: Authority
+ Web.Mackerel.Types.Authority: AuthorityOwner :: Authority
+ Web.Mackerel.Types.Authority: AuthorityViewer :: Authority
+ Web.Mackerel.Types.Authority: data Authority
+ Web.Mackerel.Types.Authority: instance Data.Aeson.Types.FromJSON.FromJSON Web.Mackerel.Types.Authority.Authority
+ Web.Mackerel.Types.Authority: instance Data.Aeson.Types.ToJSON.ToJSON Web.Mackerel.Types.Authority.Authority
+ Web.Mackerel.Types.Authority: instance GHC.Classes.Eq Web.Mackerel.Types.Authority.Authority
+ Web.Mackerel.Types.Authority: instance GHC.Read.Read Web.Mackerel.Types.Authority.Authority
+ Web.Mackerel.Types.Authority: instance GHC.Show.Show Web.Mackerel.Types.Authority.Authority
+ Web.Mackerel.Types.Channel: Channel :: ChannelId -> String -> String -> Channel
+ Web.Mackerel.Types.Channel: ChannelId :: String -> ChannelId
+ Web.Mackerel.Types.Channel: [channelId] :: Channel -> ChannelId
+ Web.Mackerel.Types.Channel: [channelName] :: Channel -> String
+ Web.Mackerel.Types.Channel: [channelType] :: Channel -> String
+ Web.Mackerel.Types.Channel: data Channel
+ Web.Mackerel.Types.Channel: data ChannelId
+ Web.Mackerel.Types.Channel: instance Data.Aeson.Types.FromJSON.FromJSON Web.Mackerel.Types.Channel.Channel
+ Web.Mackerel.Types.Channel: instance Data.Aeson.Types.FromJSON.FromJSON Web.Mackerel.Types.Channel.ChannelId
+ Web.Mackerel.Types.Channel: instance Data.Aeson.Types.ToJSON.ToJSON Web.Mackerel.Types.Channel.Channel
+ Web.Mackerel.Types.Channel: instance Data.Aeson.Types.ToJSON.ToJSON Web.Mackerel.Types.Channel.ChannelId
+ Web.Mackerel.Types.Channel: instance GHC.Classes.Eq Web.Mackerel.Types.Channel.Channel
+ Web.Mackerel.Types.Channel: instance GHC.Classes.Eq Web.Mackerel.Types.Channel.ChannelId
+ Web.Mackerel.Types.Channel: instance GHC.Show.Show Web.Mackerel.Types.Channel.Channel
+ Web.Mackerel.Types.Channel: instance GHC.Show.Show Web.Mackerel.Types.Channel.ChannelId
+ Web.Mackerel.Types.User: [userAuthority] :: User -> Authority
- Web.Mackerel.Types.Invitation: Invitation :: String -> InvitationAuthority -> Invitation
+ Web.Mackerel.Types.Invitation: Invitation :: String -> Authority -> Invitation
- Web.Mackerel.Types.Invitation: [invitationAuthority] :: Invitation -> InvitationAuthority
+ Web.Mackerel.Types.Invitation: [invitationAuthority] :: Invitation -> Authority
- Web.Mackerel.Types.User: User :: UserId -> String -> String -> User
+ Web.Mackerel.Types.User: User :: UserId -> String -> String -> Authority -> User
Files
- mackerel-client.cabal +5/−1
- src/Web/Mackerel/Api.hs +1/−0
- src/Web/Mackerel/Api/Channel.hs +18/−0
- src/Web/Mackerel/Api/Service.hs +10/−0
- src/Web/Mackerel/Types.hs +1/−0
- src/Web/Mackerel/Types/Authority.hs +39/−0
- src/Web/Mackerel/Types/Channel.hs +29/−0
- src/Web/Mackerel/Types/Invitation.hs +2/−26
- src/Web/Mackerel/Types/User.hs +3/−1
- test/Types/ChannelSpec.hs +57/−0
- test/Types/InvitationSpec.hs +2/−1
- test/Types/UserSpec.hs +5/−2
mackerel-client.cabal view
@@ -1,5 +1,5 @@ name: mackerel-client-version: 0.1.0+version: 0.2.0 author: itchyny maintainer: itchyny <itchyny@hatena.ne.jp> license: MIT@@ -24,11 +24,13 @@ , Web.Mackerel.Types.Organization , Web.Mackerel.Types.User , Web.Mackerel.Types.Invitation+ , Web.Mackerel.Types.Authority , Web.Mackerel.Types.Service , Web.Mackerel.Types.Role , Web.Mackerel.Types.Host , Web.Mackerel.Types.Metadata , Web.Mackerel.Types.Monitor+ , Web.Mackerel.Types.Channel , Web.Mackerel.Types.Alert , Web.Mackerel.Types.Dashboard , Web.Mackerel.Types.GraphAnnotation@@ -41,6 +43,7 @@ , Web.Mackerel.Api.Host , Web.Mackerel.Api.Metadata , Web.Mackerel.Api.Monitor+ , Web.Mackerel.Api.Channel , Web.Mackerel.Api.Alert , Web.Mackerel.Api.Dashboard , Web.Mackerel.Api.GraphAnnotation@@ -76,6 +79,7 @@ , Types.HostSpec , Types.MetadataSpec , Types.MonitorSpec+ , Types.ChannelSpec , Types.AlertSpec , Types.DashboardSpec , Types.GraphAnnotationSpec
src/Web/Mackerel/Api.hs view
@@ -1,6 +1,7 @@ module Web.Mackerel.Api (module Api, ApiError, errorStatusCode, errorMessage) where import Web.Mackerel.Api.Alert as Api+import Web.Mackerel.Api.Channel as Api import Web.Mackerel.Api.Dashboard as Api import Web.Mackerel.Api.GraphAnnotation as Api import Web.Mackerel.Api.Host as Api
+ src/Web/Mackerel/Api/Channel.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}+-- | Channel API.+module Web.Mackerel.Api.Channel (listChannels) where++import Data.Aeson.TH (deriveJSON)+import Network.HTTP.Types (StdMethod(..))++import Web.Mackerel.Client+import Web.Mackerel.Internal.Api+import Web.Mackerel.Internal.TH+import Web.Mackerel.Types.Channel++data ListChannelsResponse = ListChannelsResponse { responseChannels :: [Channel] }+$(deriveJSON options ''ListChannelsResponse)++listChannels :: Client -> IO (Either ApiError [Channel])+listChannels client+ = request client GET "/api/v0/channels" [] emptyBody (createHandler responseChannels)
src/Web/Mackerel/Api/Service.hs view
@@ -2,6 +2,8 @@ -- | Service API. module Web.Mackerel.Api.Service ( listServices+ , createService+ , deleteService , listServiceMetricNames ) where @@ -21,6 +23,14 @@ listServices :: Client -> IO (Either ApiError [Service]) listServices client = request client GET "/api/v0/services" [] emptyBody (createHandler responseServices)++createService :: Client -> Service -> IO (Either ApiError Service)+createService client service+ = request client POST "/api/v0/services" [] (Just service) (createHandler id)++deleteService :: Client -> String -> IO (Either ApiError Service)+deleteService client name+ = request client DELETE ("/api/v0/services/" <> BS.pack name) [] emptyBody (createHandler id) data ListMetricNamesResponse = ListMetricNamesResponse { responseNames :: [String] } $(deriveJSON options ''ListMetricNamesResponse)
src/Web/Mackerel/Types.hs view
@@ -1,6 +1,7 @@ module Web.Mackerel.Types (module Types) where import Web.Mackerel.Types.Alert as Types+import Web.Mackerel.Types.Channel as Types import Web.Mackerel.Types.Dashboard as Types import Web.Mackerel.Types.GraphAnnotation as Types import Web.Mackerel.Types.Host as Types
+ src/Web/Mackerel/Types/Authority.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE TemplateHaskell #-}+module Web.Mackerel.Types.Authority where++import Data.Aeson+import qualified Data.Aeson as Aeson+import Data.Aeson.Types (typeMismatch)+import qualified Data.Text as Text++data Authority = AuthorityOwner+ | AuthorityManager+ | AuthorityCollaborator+ | AuthorityViewer+ deriving Eq++instance Show Authority where+ show AuthorityOwner = "owner"+ show AuthorityManager = "manager"+ show AuthorityCollaborator = "collaborator"+ show AuthorityViewer = "viewer"++instance Read Authority where+ readsPrec _ xs = [ (hs, drop (length str) xs) | (hs, str) <- pairs', take (length str) xs == str ]+ where pairs' = [+ (AuthorityOwner, "owner"),+ (AuthorityManager, "manager"),+ (AuthorityCollaborator, "collaborator"),+ (AuthorityViewer, "viewer")]++instance FromJSON Authority where+ parseJSON (Aeson.String txt)+ | str == "owner" = return AuthorityOwner+ | str == "manager" = return AuthorityManager+ | str == "collaborator" = return AuthorityCollaborator+ | str == "viewer" = return AuthorityViewer+ where str = Text.unpack txt+ parseJSON o = typeMismatch "Authority" o++instance ToJSON Authority where+ toJSON method = toJSON (show method)
+ src/Web/Mackerel/Types/Channel.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE TemplateHaskell #-}+module Web.Mackerel.Types.Channel where++import Data.Aeson+import qualified Data.Aeson as Aeson+import Data.Aeson.TH (deriveJSON)+import Data.Aeson.Types (typeMismatch)+import qualified Data.Text as Text++import Web.Mackerel.Internal.TH++data ChannelId = ChannelId String+ deriving (Eq, Show)++instance FromJSON ChannelId where+ parseJSON (Aeson.String channelId) = return $ ChannelId $ Text.unpack channelId+ parseJSON o = typeMismatch "ChannelId" o++instance ToJSON ChannelId where+ toJSON (ChannelId channelId) = toJSON channelId++data Channel+ = Channel {+ channelId :: ChannelId,+ channelName :: String,+ channelType :: String+ } deriving (Eq, Show)++$(deriveJSON options ''Channel)
src/Web/Mackerel/Types/Invitation.hs view
@@ -8,36 +8,12 @@ import qualified Data.Text as Text import Web.Mackerel.Internal.TH--data InvitationAuthority = InvitationAuthorityManager- | InvitationAuthorityCollaborator- | InvitationAuthorityViewer- deriving Eq--instance Show InvitationAuthority where- show InvitationAuthorityManager = "manager"- show InvitationAuthorityCollaborator = "collaborator"- show InvitationAuthorityViewer = "viewer"--instance Read InvitationAuthority where- readsPrec _ xs = [ (hs, drop (length str) xs) | (hs, str) <- pairs', take (length str) xs == str ]- where pairs' = [(InvitationAuthorityManager, "manager"), (InvitationAuthorityCollaborator, "collaborator"), (InvitationAuthorityViewer, "viewer")]--instance FromJSON InvitationAuthority where- parseJSON (Aeson.String txt)- | str == "manager" = return InvitationAuthorityManager- | str == "collaborator" = return InvitationAuthorityCollaborator- | str == "viewer" = return InvitationAuthorityViewer- where str = Text.unpack txt- parseJSON o = typeMismatch "InvitationAuthority" o--instance ToJSON InvitationAuthority where- toJSON method = toJSON (show method)+import Web.Mackerel.Types.Authority data Invitation = Invitation { invitationEmail :: String,- invitationAuthority :: InvitationAuthority+ invitationAuthority :: Authority } deriving (Eq, Show) $(deriveJSON options ''Invitation)
src/Web/Mackerel/Types/User.hs view
@@ -8,6 +8,7 @@ import qualified Data.Text as Text import Web.Mackerel.Internal.TH+import Web.Mackerel.Types.Authority data UserId = UserId String deriving (Eq, Show)@@ -23,7 +24,8 @@ = User { userId :: UserId, userScreenName :: String,- userEmail :: String+ userEmail :: String,+ userAuthority :: Authority } deriving (Eq, Show) $(deriveJSON options ''User)
+ test/Types/ChannelSpec.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}+module Types.ChannelSpec where++import Control.Monad (forM_)+import Data.Aeson (decode, encode, Value(..))+import Data.Aeson.QQ+import qualified Data.HashMap.Lazy as HM+import Test.Hspec++import Web.Mackerel.Types.Channel++spec :: Spec+spec = do++ let channel1 = Channel {+ channelId = ChannelId "abcde1",+ channelName = "Example Channel 1",+ channelType = "slack"+ }++ let json1 = [aesonQQ|+ {+ "id": "abcde1",+ "name": "Example Channel 1",+ "type": "slack"+ }+ |]++ let channel2 = Channel {+ channelId = ChannelId "abcde2",+ channelName = "Example Channel 2",+ channelType = "email"+ }++ let json2 = [aesonQQ|+ {+ "id": "abcde2",+ "name": "Example Channel 2",+ "type": "email"+ }+ |]++ describe "Channel FromJSON" $ do+ it "should parse a json" $+ forM_ [(channel1, json1), (channel2, json2)] $ \(channel, json) ->+ decode (encode json) `shouldBe` Just channel++ it "should reject an invalid json" $ do+ decode "{}" `shouldBe` (Nothing :: Maybe Channel)+ let (Object hm) = json1+ forM_ ["id", "name", "type"] $ \key ->+ decode (encode (Object (HM.delete key hm))) `shouldBe` (Nothing :: Maybe Channel)++ describe "Channel ToJSON" $+ it "should encode into a json" $+ forM_ [(channel1, json1), (channel2, json2)] $ \(channel, json) ->+ decode (encode channel) `shouldBe` Just json
test/Types/InvitationSpec.hs view
@@ -7,6 +7,7 @@ import qualified Data.HashMap.Lazy as HM import Test.Hspec +import Web.Mackerel.Types.Authority import Web.Mackerel.Types.Invitation spec :: Spec@@ -14,7 +15,7 @@ let invitation' = Invitation { invitationEmail = "foobar@example.com",- invitationAuthority = InvitationAuthorityManager+ invitationAuthority = AuthorityManager } let json = [aesonQQ|
test/Types/UserSpec.hs view
@@ -7,6 +7,7 @@ import qualified Data.HashMap.Lazy as HM import Test.Hspec +import Web.Mackerel.Types.Authority import Web.Mackerel.Types.User spec :: Spec@@ -15,14 +16,16 @@ let user = User { userId = UserId "abcde", userScreenName = "Example Mackerel",- userEmail = "mackerel@example.com"+ userEmail = "mackerel@example.com",+ userAuthority = AuthorityCollaborator } let json = [aesonQQ| { "id": "abcde", "screenName": "Example Mackerel",- "email": "mackerel@example.com"+ "email": "mackerel@example.com",+ "authority": "collaborator" } |]