From 55d42f1dd83b428aa0f1352bc0ea1402b9c2b811 Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 21 Feb 2026 14:18:13 +0100 Subject: generate initial commit Generate haskell-http-client from running g4f v-7.1.4. Server started like this: python -m g4f --port 8080 --debug Code generated like this: openapi-generator-cli generate \ -i http://localhost:8080/openapi.json \ -g haskell-http-client \ --skip-validate-spec \ -o g4f-client \ --additional-properties=cabalPackage=g4f-client,cabalVersion=7.1.4,baseModule=G4fApi --- lib/G4fClient.hs | 31 + lib/G4fClient/API.hs | 19 + lib/G4fClient/API/ApiDefault.hs | 680 ++++++++++++++++ lib/G4fClient/Client.hs | 223 ++++++ lib/G4fClient/Core.hs | 589 ++++++++++++++ lib/G4fClient/Logging.hs | 33 + lib/G4fClient/LoggingKatip.hs | 117 +++ lib/G4fClient/LoggingMonadLogger.hs | 126 +++ lib/G4fClient/MimeTypes.hs | 225 ++++++ lib/G4fClient/Model.hs | 1513 +++++++++++++++++++++++++++++++++++ lib/G4fClient/ModelLens.hs | 858 ++++++++++++++++++++ 11 files changed, 4414 insertions(+) create mode 100644 lib/G4fClient.hs create mode 100644 lib/G4fClient/API.hs create mode 100644 lib/G4fClient/API/ApiDefault.hs create mode 100644 lib/G4fClient/Client.hs create mode 100644 lib/G4fClient/Core.hs create mode 100644 lib/G4fClient/Logging.hs create mode 100644 lib/G4fClient/LoggingKatip.hs create mode 100644 lib/G4fClient/LoggingMonadLogger.hs create mode 100644 lib/G4fClient/MimeTypes.hs create mode 100644 lib/G4fClient/Model.hs create mode 100644 lib/G4fClient/ModelLens.hs (limited to 'lib') diff --git a/lib/G4fClient.hs b/lib/G4fClient.hs new file mode 100644 index 0000000..711c375 --- /dev/null +++ b/lib/G4fClient.hs @@ -0,0 +1,31 @@ +{- + FastAPI + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + OpenAPI Version: 3.1.0 + FastAPI API version: 0.1.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) +-} + +{-| +Module : G4fClient +-} + +module G4fClient + ( module G4fClient.API + , module G4fClient.Client + , module G4fClient.Core + , module G4fClient.Logging + , module G4fClient.MimeTypes + , module G4fClient.Model + , module G4fClient.ModelLens + ) where + +import G4fClient.API +import G4fClient.Client +import G4fClient.Core +import G4fClient.Logging +import G4fClient.MimeTypes +import G4fClient.Model +import G4fClient.ModelLens \ No newline at end of file diff --git a/lib/G4fClient/API.hs b/lib/G4fClient/API.hs new file mode 100644 index 0000000..0ec10da --- /dev/null +++ b/lib/G4fClient/API.hs @@ -0,0 +1,19 @@ +{- + FastAPI + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + OpenAPI Version: 3.1.0 + FastAPI API version: 0.1.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) +-} + +{-| +Module : G4fClient.API +-} + +module G4fClient.API + ( module G4fClient.API.ApiDefault + ) where + +import G4fClient.API.ApiDefault \ No newline at end of file diff --git a/lib/G4fClient/API/ApiDefault.hs b/lib/G4fClient/API/ApiDefault.hs new file mode 100644 index 0000000..3991f71 --- /dev/null +++ b/lib/G4fClient/API/ApiDefault.hs @@ -0,0 +1,680 @@ +{- + FastAPI + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + OpenAPI Version: 3.1.0 + FastAPI API version: 0.1.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) +-} + +{-| +Module : G4fClient.API.ApiDefault +-} + +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module G4fClient.API.ApiDefault where + +import G4fClient.Core +import G4fClient.MimeTypes +import G4fClient.Model as M + +import qualified Data.Aeson as A +import qualified Data.ByteString as B +import qualified Data.ByteString.Lazy as BL +import qualified Data.Data as P (Typeable, TypeRep, typeOf, typeRep) +import qualified Data.Foldable as P +import qualified Data.Map as Map +import qualified Data.Maybe as P +import qualified Data.Proxy as P (Proxy(..)) +import qualified Data.Set as Set +import qualified Data.String as P +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Data.Text.Lazy as TL +import qualified Data.Text.Lazy.Encoding as TL +import qualified Data.Time as TI +import qualified Network.HTTP.Client.MultipartFormData as NH +import qualified Network.HTTP.Media as ME +import qualified Network.HTTP.Types as NH +import qualified Web.FormUrlEncoded as WH +import qualified Web.HttpApiData as WH + +import Data.Text (Text) +import GHC.Base ((<|>)) + +import Prelude ((==),(/=),($), (.),(<$>),(<*>),(>>=),Maybe(..),Bool(..),Char,Double,FilePath,Float,Int,Integer,String,fmap,undefined,mempty,maybe,pure,Monad,Applicative,Functor) +import qualified Prelude as P + +-- * Operations + + +-- ** Default + +-- *** chatCompletionsApiProviderChatCompletionsPost + +-- | @POST \/api\/{provider}\/chat\/completions@ +-- +-- Chat Completions +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +chatCompletionsApiProviderChatCompletionsPost + :: (Consumes ChatCompletionsApiProviderChatCompletionsPost MimeJSON, MimeRender MimeJSON ChatCompletionsConfig) + => ChatCompletionsConfig -- ^ "chatCompletionsConfig" + -> Provider -- ^ "provider" + -> G4fClientRequest ChatCompletionsApiProviderChatCompletionsPost MimeJSON ChatCompletion MimeJSON +chatCompletionsApiProviderChatCompletionsPost chatCompletionsConfig (Provider provider) = + _mkRequest "POST" ["/api/",toPath provider,"/chat/completions"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + `setBodyParam` chatCompletionsConfig + +data ChatCompletionsApiProviderChatCompletionsPost +instance HasBodyParam ChatCompletionsApiProviderChatCompletionsPost ChatCompletionsConfig +instance HasOptionalParam ChatCompletionsApiProviderChatCompletionsPost ConversationId where + applyOptionalParam req (ConversationId xs) = + req `addQuery` toQuery ("conversation_id", Just xs) +instance HasOptionalParam ChatCompletionsApiProviderChatCompletionsPost XUser where + applyOptionalParam req (XUser xs) = + req `addHeader` toHeader ("x-user", xs) + +-- | @application/json@ +instance Consumes ChatCompletionsApiProviderChatCompletionsPost MimeJSON + +-- | @application/json@ +instance Produces ChatCompletionsApiProviderChatCompletionsPost MimeJSON + + +-- *** chatCompletionsApiProviderConversationIdChatCompletionsPost + +-- | @POST \/api\/{provider}\/{conversation_id}\/chat\/completions@ +-- +-- Chat Completions +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +chatCompletionsApiProviderConversationIdChatCompletionsPost + :: (Consumes ChatCompletionsApiProviderConversationIdChatCompletionsPost MimeJSON, MimeRender MimeJSON ChatCompletionsConfig) + => ChatCompletionsConfig -- ^ "chatCompletionsConfig" + -> Provider -- ^ "provider" + -> ConversationId -- ^ "conversationId" + -> G4fClientRequest ChatCompletionsApiProviderConversationIdChatCompletionsPost MimeJSON ChatCompletion MimeJSON +chatCompletionsApiProviderConversationIdChatCompletionsPost chatCompletionsConfig (Provider provider) (ConversationId conversationId) = + _mkRequest "POST" ["/api/",toPath provider,"/",toPath conversationId,"/chat/completions"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + `setBodyParam` chatCompletionsConfig + +data ChatCompletionsApiProviderConversationIdChatCompletionsPost +instance HasBodyParam ChatCompletionsApiProviderConversationIdChatCompletionsPost ChatCompletionsConfig +instance HasOptionalParam ChatCompletionsApiProviderConversationIdChatCompletionsPost XUser where + applyOptionalParam req (XUser xs) = + req `addHeader` toHeader ("x-user", xs) + +-- | @application/json@ +instance Consumes ChatCompletionsApiProviderConversationIdChatCompletionsPost MimeJSON + +-- | @application/json@ +instance Produces ChatCompletionsApiProviderConversationIdChatCompletionsPost MimeJSON + + +-- *** chatCompletionsV1ChatCompletionsPost + +-- | @POST \/v1\/chat\/completions@ +-- +-- Chat Completions +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +chatCompletionsV1ChatCompletionsPost + :: (Consumes ChatCompletionsV1ChatCompletionsPost MimeJSON, MimeRender MimeJSON ChatCompletionsConfig) + => ChatCompletionsConfig -- ^ "chatCompletionsConfig" + -> G4fClientRequest ChatCompletionsV1ChatCompletionsPost MimeJSON ChatCompletion MimeJSON +chatCompletionsV1ChatCompletionsPost chatCompletionsConfig = + _mkRequest "POST" ["/v1/chat/completions"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + `setBodyParam` chatCompletionsConfig + +data ChatCompletionsV1ChatCompletionsPost +instance HasBodyParam ChatCompletionsV1ChatCompletionsPost ChatCompletionsConfig +instance HasOptionalParam ChatCompletionsV1ChatCompletionsPost Provider where + applyOptionalParam req (Provider xs) = + req `addQuery` toQuery ("provider", Just xs) +instance HasOptionalParam ChatCompletionsV1ChatCompletionsPost ConversationId where + applyOptionalParam req (ConversationId xs) = + req `addQuery` toQuery ("conversation_id", Just xs) +instance HasOptionalParam ChatCompletionsV1ChatCompletionsPost XUser where + applyOptionalParam req (XUser xs) = + req `addHeader` toHeader ("x-user", xs) + +-- | @application/json@ +instance Consumes ChatCompletionsV1ChatCompletionsPost MimeJSON + +-- | @application/json@ +instance Produces ChatCompletionsV1ChatCompletionsPost MimeJSON + + +-- *** convertApiMarkitdownPost + +-- | @POST \/api\/markitdown@ +-- +-- Convert +-- +convertApiMarkitdownPost + :: (Consumes ConvertApiMarkitdownPost MimeMultipartFormData) + => File -- ^ "file" + -> G4fClientRequest ConvertApiMarkitdownPost MimeMultipartFormData TranscriptionResponseModel MimeJSON +convertApiMarkitdownPost (File file) = + _mkRequest "POST" ["/api/markitdown"] + `_addMultiFormPart` NH.partFileSource "file" file + +data ConvertApiMarkitdownPost +instance HasOptionalParam ConvertApiMarkitdownPost Model where + applyOptionalParam req (Model xs) = + req `_addMultiFormPart` NH.partLBS "model" (mimeRender' MimeMultipartFormData xs) +instance HasOptionalParam ConvertApiMarkitdownPost Provider where + applyOptionalParam req (Provider xs) = + req `_addMultiFormPart` NH.partLBS "provider" (mimeRender' MimeMultipartFormData xs) +instance HasOptionalParam ConvertApiMarkitdownPost Prompt where + applyOptionalParam req (Prompt xs) = + req `_addMultiFormPart` NH.partLBS "prompt" (mimeRender' MimeMultipartFormData xs) +instance HasOptionalParam ConvertApiMarkitdownPost PathProvider where + applyOptionalParam req (PathProvider xs) = + req `addQuery` toQuery ("path_provider", Just xs) + +-- | @multipart/form-data@ +instance Consumes ConvertApiMarkitdownPost MimeMultipartFormData + +-- | @application/json@ +instance Produces ConvertApiMarkitdownPost MimeJSON + + +-- *** convertApiPathProviderAudioTranscriptionsPost + +-- | @POST \/api\/{path_provider}\/audio\/transcriptions@ +-- +-- Convert +-- +convertApiPathProviderAudioTranscriptionsPost + :: (Consumes ConvertApiPathProviderAudioTranscriptionsPost MimeMultipartFormData) + => File -- ^ "file" + -> PathProvider -- ^ "pathProvider" + -> G4fClientRequest ConvertApiPathProviderAudioTranscriptionsPost MimeMultipartFormData TranscriptionResponseModel MimeJSON +convertApiPathProviderAudioTranscriptionsPost (File file) (PathProvider pathProvider) = + _mkRequest "POST" ["/api/",toPath pathProvider,"/audio/transcriptions"] + `_addMultiFormPart` NH.partFileSource "file" file + +data ConvertApiPathProviderAudioTranscriptionsPost +instance HasOptionalParam ConvertApiPathProviderAudioTranscriptionsPost Model where + applyOptionalParam req (Model xs) = + req `_addMultiFormPart` NH.partLBS "model" (mimeRender' MimeMultipartFormData xs) +instance HasOptionalParam ConvertApiPathProviderAudioTranscriptionsPost Provider where + applyOptionalParam req (Provider xs) = + req `_addMultiFormPart` NH.partLBS "provider" (mimeRender' MimeMultipartFormData xs) +instance HasOptionalParam ConvertApiPathProviderAudioTranscriptionsPost Prompt where + applyOptionalParam req (Prompt xs) = + req `_addMultiFormPart` NH.partLBS "prompt" (mimeRender' MimeMultipartFormData xs) + +-- | @multipart/form-data@ +instance Consumes ConvertApiPathProviderAudioTranscriptionsPost MimeMultipartFormData + +-- | @application/json@ +instance Produces ConvertApiPathProviderAudioTranscriptionsPost MimeJSON + + +-- *** convertV1AudioTranscriptionsPost + +-- | @POST \/v1\/audio\/transcriptions@ +-- +-- Convert +-- +convertV1AudioTranscriptionsPost + :: (Consumes ConvertV1AudioTranscriptionsPost MimeMultipartFormData) + => File -- ^ "file" + -> G4fClientRequest ConvertV1AudioTranscriptionsPost MimeMultipartFormData TranscriptionResponseModel MimeJSON +convertV1AudioTranscriptionsPost (File file) = + _mkRequest "POST" ["/v1/audio/transcriptions"] + `_addMultiFormPart` NH.partFileSource "file" file + +data ConvertV1AudioTranscriptionsPost +instance HasOptionalParam ConvertV1AudioTranscriptionsPost Model where + applyOptionalParam req (Model xs) = + req `_addMultiFormPart` NH.partLBS "model" (mimeRender' MimeMultipartFormData xs) +instance HasOptionalParam ConvertV1AudioTranscriptionsPost Provider where + applyOptionalParam req (Provider xs) = + req `_addMultiFormPart` NH.partLBS "provider" (mimeRender' MimeMultipartFormData xs) +instance HasOptionalParam ConvertV1AudioTranscriptionsPost Prompt where + applyOptionalParam req (Prompt xs) = + req `_addMultiFormPart` NH.partLBS "prompt" (mimeRender' MimeMultipartFormData xs) +instance HasOptionalParam ConvertV1AudioTranscriptionsPost PathProvider where + applyOptionalParam req (PathProvider xs) = + req `addQuery` toQuery ("path_provider", Just xs) + +-- | @multipart/form-data@ +instance Consumes ConvertV1AudioTranscriptionsPost MimeMultipartFormData + +-- | @application/json@ +instance Produces ConvertV1AudioTranscriptionsPost MimeJSON + + +-- *** generateImageApiProviderImagesGenerationsPost + +-- | @POST \/api\/{provider}\/images\/generations@ +-- +-- Generate Image +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +generateImageApiProviderImagesGenerationsPost + :: (Consumes GenerateImageApiProviderImagesGenerationsPost MimeJSON, MimeRender MimeJSON ImageGenerationConfig) + => ImageGenerationConfig -- ^ "imageGenerationConfig" + -> Provider -- ^ "provider" + -> G4fClientRequest GenerateImageApiProviderImagesGenerationsPost MimeJSON ImagesResponse MimeJSON +generateImageApiProviderImagesGenerationsPost imageGenerationConfig (Provider provider) = + _mkRequest "POST" ["/api/",toPath provider,"/images/generations"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + `setBodyParam` imageGenerationConfig + +data GenerateImageApiProviderImagesGenerationsPost +instance HasBodyParam GenerateImageApiProviderImagesGenerationsPost ImageGenerationConfig + +-- | @application/json@ +instance Consumes GenerateImageApiProviderImagesGenerationsPost MimeJSON + +-- | @application/json@ +instance Produces GenerateImageApiProviderImagesGenerationsPost MimeJSON + + +-- *** generateImageV1ImagesGeneratePost + +-- | @POST \/v1\/images\/generate@ +-- +-- Generate Image +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +generateImageV1ImagesGeneratePost + :: (Consumes GenerateImageV1ImagesGeneratePost MimeJSON, MimeRender MimeJSON ImageGenerationConfig) + => ImageGenerationConfig -- ^ "imageGenerationConfig" + -> G4fClientRequest GenerateImageV1ImagesGeneratePost MimeJSON ImagesResponse MimeJSON +generateImageV1ImagesGeneratePost imageGenerationConfig = + _mkRequest "POST" ["/v1/images/generate"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + `setBodyParam` imageGenerationConfig + +data GenerateImageV1ImagesGeneratePost +instance HasBodyParam GenerateImageV1ImagesGeneratePost ImageGenerationConfig +instance HasOptionalParam GenerateImageV1ImagesGeneratePost Provider where + applyOptionalParam req (Provider xs) = + req `addQuery` toQuery ("provider", Just xs) + +-- | @application/json@ +instance Consumes GenerateImageV1ImagesGeneratePost MimeJSON + +-- | @application/json@ +instance Produces GenerateImageV1ImagesGeneratePost MimeJSON + + +-- *** generateImageV1ImagesGenerationsPost + +-- | @POST \/v1\/images\/generations@ +-- +-- Generate Image +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +generateImageV1ImagesGenerationsPost + :: (Consumes GenerateImageV1ImagesGenerationsPost MimeJSON, MimeRender MimeJSON ImageGenerationConfig) + => ImageGenerationConfig -- ^ "imageGenerationConfig" + -> G4fClientRequest GenerateImageV1ImagesGenerationsPost MimeJSON ImagesResponse MimeJSON +generateImageV1ImagesGenerationsPost imageGenerationConfig = + _mkRequest "POST" ["/v1/images/generations"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + `setBodyParam` imageGenerationConfig + +data GenerateImageV1ImagesGenerationsPost +instance HasBodyParam GenerateImageV1ImagesGenerationsPost ImageGenerationConfig +instance HasOptionalParam GenerateImageV1ImagesGenerationsPost Provider where + applyOptionalParam req (Provider xs) = + req `addQuery` toQuery ("provider", Just xs) + +-- | @application/json@ +instance Consumes GenerateImageV1ImagesGenerationsPost MimeJSON + +-- | @application/json@ +instance Produces GenerateImageV1ImagesGenerationsPost MimeJSON + + +-- *** generateImageV1MediaGeneratePost + +-- | @POST \/v1\/media\/generate@ +-- +-- Generate Image +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +generateImageV1MediaGeneratePost + :: (Consumes GenerateImageV1MediaGeneratePost MimeJSON, MimeRender MimeJSON ImageGenerationConfig) + => ImageGenerationConfig -- ^ "imageGenerationConfig" + -> G4fClientRequest GenerateImageV1MediaGeneratePost MimeJSON ImagesResponse MimeJSON +generateImageV1MediaGeneratePost imageGenerationConfig = + _mkRequest "POST" ["/v1/media/generate"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + `setBodyParam` imageGenerationConfig + +data GenerateImageV1MediaGeneratePost +instance HasBodyParam GenerateImageV1MediaGeneratePost ImageGenerationConfig +instance HasOptionalParam GenerateImageV1MediaGeneratePost Provider where + applyOptionalParam req (Provider xs) = + req `addQuery` toQuery ("provider", Just xs) + +-- | @application/json@ +instance Consumes GenerateImageV1MediaGeneratePost MimeJSON + +-- | @application/json@ +instance Produces GenerateImageV1MediaGeneratePost MimeJSON + + +-- *** generateSpeechApiProviderAudioSpeechPost + +-- | @POST \/api\/{provider}\/audio\/speech@ +-- +-- Generate Speech +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +generateSpeechApiProviderAudioSpeechPost + :: (Consumes GenerateSpeechApiProviderAudioSpeechPost MimeJSON, MimeRender MimeJSON AudioSpeechConfig) + => Accept accept -- ^ request accept ('MimeType') + -> AudioSpeechConfig -- ^ "audioSpeechConfig" + -> Provider -- ^ "provider" + -> G4fClientRequest GenerateSpeechApiProviderAudioSpeechPost MimeJSON AnyType accept +generateSpeechApiProviderAudioSpeechPost _ audioSpeechConfig (Provider provider) = + _mkRequest "POST" ["/api/",toPath provider,"/audio/speech"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + `setBodyParam` audioSpeechConfig + +data GenerateSpeechApiProviderAudioSpeechPost +instance HasBodyParam GenerateSpeechApiProviderAudioSpeechPost AudioSpeechConfig + +-- | @application/json@ +instance Consumes GenerateSpeechApiProviderAudioSpeechPost MimeJSON + +-- | @application/json@ +instance Produces GenerateSpeechApiProviderAudioSpeechPost MimeJSON +-- | @audio/*@ +instance Produces GenerateSpeechApiProviderAudioSpeechPost MimeAudio + + +-- *** generateSpeechV1AudioSpeechPost + +-- | @POST \/v1\/audio\/speech@ +-- +-- Generate Speech +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +generateSpeechV1AudioSpeechPost + :: (Consumes GenerateSpeechV1AudioSpeechPost MimeJSON, MimeRender MimeJSON AudioSpeechConfig) + => Accept accept -- ^ request accept ('MimeType') + -> AudioSpeechConfig -- ^ "audioSpeechConfig" + -> G4fClientRequest GenerateSpeechV1AudioSpeechPost MimeJSON AnyType accept +generateSpeechV1AudioSpeechPost _ audioSpeechConfig = + _mkRequest "POST" ["/v1/audio/speech"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + `setBodyParam` audioSpeechConfig + +data GenerateSpeechV1AudioSpeechPost +instance HasBodyParam GenerateSpeechV1AudioSpeechPost AudioSpeechConfig +instance HasOptionalParam GenerateSpeechV1AudioSpeechPost Provider where + applyOptionalParam req (Provider xs) = + req `addQuery` toQuery ("provider", Just xs) + +-- | @application/json@ +instance Consumes GenerateSpeechV1AudioSpeechPost MimeJSON + +-- | @application/json@ +instance Produces GenerateSpeechV1AudioSpeechPost MimeJSON +-- | @audio/*@ +instance Produces GenerateSpeechV1AudioSpeechPost MimeAudio + + +-- *** getMediaImagesFilenameGet + +-- | @GET \/images\/{filename}@ +-- +-- Get Media +-- +getMediaImagesFilenameGet + :: Accept accept -- ^ request accept ('MimeType') + -> Filename -- ^ "filename" + -> G4fClientRequest GetMediaImagesFilenameGet MimeNoContent AnyType accept +getMediaImagesFilenameGet _ (Filename filename) = + _mkRequest "GET" ["/images/",toPath filename] + +data GetMediaImagesFilenameGet +instance HasOptionalParam GetMediaImagesFilenameGet Thumbnail where + applyOptionalParam req (Thumbnail xs) = + req `addQuery` toQuery ("thumbnail", Just xs) +-- | @image/*@ +instance Produces GetMediaImagesFilenameGet MimeImage +-- | @application/json@ +instance Produces GetMediaImagesFilenameGet MimeJSON + + +-- *** getMediaMediaFilenameGet + +-- | @GET \/media\/{filename}@ +-- +-- Get Media +-- +getMediaMediaFilenameGet + :: Accept accept -- ^ request accept ('MimeType') + -> Filename -- ^ "filename" + -> G4fClientRequest GetMediaMediaFilenameGet MimeNoContent AnyType accept +getMediaMediaFilenameGet _ (Filename filename) = + _mkRequest "GET" ["/media/",toPath filename] + +data GetMediaMediaFilenameGet +instance HasOptionalParam GetMediaMediaFilenameGet Thumbnail where + applyOptionalParam req (Thumbnail xs) = + req `addQuery` toQuery ("thumbnail", Just xs) +-- | @image/*@ +instance Produces GetMediaMediaFilenameGet MimeImage +-- | @application/json@ +instance Produces GetMediaMediaFilenameGet MimeJSON +-- | @audio/*@ +instance Produces GetMediaMediaFilenameGet MimeAudio + + +-- *** getMediaThumbnailThumbnailFilenameGet + +-- | @GET \/thumbnail\/{filename}@ +-- +-- Get Media Thumbnail +-- +getMediaThumbnailThumbnailFilenameGet + :: Accept accept -- ^ request accept ('MimeType') + -> FilenameText -- ^ "filename" + -> G4fClientRequest GetMediaThumbnailThumbnailFilenameGet MimeNoContent AnyType accept +getMediaThumbnailThumbnailFilenameGet _ (FilenameText filename) = + _mkRequest "GET" ["/thumbnail/",toPath filename] + +data GetMediaThumbnailThumbnailFilenameGet +-- | @image/*@ +instance Produces GetMediaThumbnailThumbnailFilenameGet MimeImage +-- | @application/json@ +instance Produces GetMediaThumbnailThumbnailFilenameGet MimeJSON +-- | @audio/*@ +instance Produces GetMediaThumbnailThumbnailFilenameGet MimeAudio + + +-- *** modelInfoV1ModelsModelNameGet + +-- | @GET \/v1\/models\/{model_name}@ +-- +-- Model Info +-- +modelInfoV1ModelsModelNameGet + :: ModelName -- ^ "modelName" + -> G4fClientRequest ModelInfoV1ModelsModelNameGet MimeNoContent ModelResponseModel MimeJSON +modelInfoV1ModelsModelNameGet (ModelName modelName) = + _mkRequest "GET" ["/v1/models/",toPath modelName] + +data ModelInfoV1ModelsModelNameGet +-- | @application/json@ +instance Produces ModelInfoV1ModelsModelNameGet MimeJSON + + +-- *** modelInfoV1ModelsModelNamePost + +-- | @POST \/v1\/models\/{model_name}@ +-- +-- Model Info +-- +modelInfoV1ModelsModelNamePost + :: ModelName -- ^ "modelName" + -> G4fClientRequest ModelInfoV1ModelsModelNamePost MimeNoContent ModelResponseModel MimeJSON +modelInfoV1ModelsModelNamePost (ModelName modelName) = + _mkRequest "POST" ["/v1/models/",toPath modelName] + +data ModelInfoV1ModelsModelNamePost +-- | @application/json@ +instance Produces ModelInfoV1ModelsModelNamePost MimeJSON + + +-- *** modelsApiProviderModelsGet + +-- | @GET \/api\/{provider}\/models@ +-- +-- Models +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +modelsApiProviderModelsGet + :: Provider -- ^ "provider" + -> G4fClientRequest ModelsApiProviderModelsGet MimeNoContent [ModelResponseModel] MimeJSON +modelsApiProviderModelsGet (Provider provider) = + _mkRequest "GET" ["/api/",toPath provider,"/models"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + +data ModelsApiProviderModelsGet +-- | @application/json@ +instance Produces ModelsApiProviderModelsGet MimeJSON + + +-- *** modelsV1ModelsGet + +-- | @GET \/v1\/models@ +-- +-- Models +-- +modelsV1ModelsGet + :: G4fClientRequest ModelsV1ModelsGet MimeNoContent [ModelResponseModel] MimeJSON +modelsV1ModelsGet = + _mkRequest "GET" ["/v1/models"] + +data ModelsV1ModelsGet +-- | @application/json@ +instance Produces ModelsV1ModelsGet MimeJSON + + +-- *** providerQuotaApiProviderQuotaGet + +-- | @GET \/api\/{provider}\/quota@ +-- +-- Provider Quota +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +providerQuotaApiProviderQuotaGet + :: Provider -- ^ "provider" + -> G4fClientRequest ProviderQuotaApiProviderQuotaGet MimeNoContent AnyType MimeJSON +providerQuotaApiProviderQuotaGet (Provider provider) = + _mkRequest "GET" ["/api/",toPath provider,"/quota"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + +data ProviderQuotaApiProviderQuotaGet +-- | @application/json@ +instance Produces ProviderQuotaApiProviderQuotaGet MimeJSON + + +-- *** providersInfoV1ProvidersProviderGet + +-- | @GET \/v1\/providers\/{provider}@ +-- +-- Providers Info +-- +providersInfoV1ProvidersProviderGet + :: Provider -- ^ "provider" + -> G4fClientRequest ProvidersInfoV1ProvidersProviderGet MimeNoContent ProviderResponseDetailModel MimeJSON +providersInfoV1ProvidersProviderGet (Provider provider) = + _mkRequest "GET" ["/v1/providers/",toPath provider] + +data ProvidersInfoV1ProvidersProviderGet +-- | @application/json@ +instance Produces ProvidersInfoV1ProvidersProviderGet MimeJSON + + +-- *** providersV1ProvidersGet + +-- | @GET \/v1\/providers@ +-- +-- Providers +-- +providersV1ProvidersGet + :: G4fClientRequest ProvidersV1ProvidersGet MimeNoContent [ProviderResponseModel] MimeJSON +providersV1ProvidersGet = + _mkRequest "GET" ["/v1/providers"] + +data ProvidersV1ProvidersGet +-- | @application/json@ +instance Produces ProvidersV1ProvidersGet MimeJSON + + +-- *** readRootV1V1Get + +-- | @GET \/v1@ +-- +-- Read Root V1 +-- +readRootV1V1Get + :: G4fClientRequest ReadRootV1V1Get MimeNoContent AnyType MimeJSON +readRootV1V1Get = + _mkRequest "GET" ["/v1"] + +data ReadRootV1V1Get +-- | @application/json@ +instance Produces ReadRootV1V1Get MimeJSON + + +-- *** uploadCookiesV1UploadCookiesPost + +-- | @POST \/v1\/upload_cookies@ +-- +-- Upload Cookies +-- +-- AuthMethod: 'AuthBasicHTTPBearer' +-- +uploadCookiesV1UploadCookiesPost + :: (Consumes UploadCookiesV1UploadCookiesPost MimeMultipartFormData) + => Files -- ^ "files" + -> G4fClientRequest UploadCookiesV1UploadCookiesPost MimeMultipartFormData [FileResponseModel] MimeJSON +uploadCookiesV1UploadCookiesPost (Files files) = + _mkRequest "POST" ["/v1/upload_cookies"] + `_hasAuthType` (P.Proxy :: P.Proxy AuthBasicHTTPBearer) + `_addMultiFormPart` NH.partFileSource "files" files + +data UploadCookiesV1UploadCookiesPost + +-- | @multipart/form-data@ +instance Consumes UploadCookiesV1UploadCookiesPost MimeMultipartFormData + +-- | @application/json@ +instance Produces UploadCookiesV1UploadCookiesPost MimeJSON + diff --git a/lib/G4fClient/Client.hs b/lib/G4fClient/Client.hs new file mode 100644 index 0000000..0fed516 --- /dev/null +++ b/lib/G4fClient/Client.hs @@ -0,0 +1,223 @@ +{- + FastAPI + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + OpenAPI Version: 3.1.0 + FastAPI API version: 0.1.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) +-} + +{-| +Module : G4fClient.Client +-} + +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveFoldable #-} +{-# LANGUAGE DeriveTraversable #-} +{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module G4fClient.Client where + +import G4fClient.Core +import G4fClient.Logging +import G4fClient.MimeTypes + +import qualified Control.Exception.Safe as E +import qualified Control.Monad.IO.Class as P +import qualified Control.Monad as P +import qualified Data.Aeson.Types as A +import qualified Data.ByteString as B +import qualified Data.ByteString.Char8 as BC +import qualified Data.ByteString.Lazy as BL +import qualified Data.ByteString.Lazy.Char8 as BCL +import qualified Data.Proxy as P (Proxy(..)) +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Network.HTTP.Client as NH +import qualified Network.HTTP.Client.MultipartFormData as NH +import qualified Network.HTTP.Types as NH +import qualified Web.FormUrlEncoded as WH +import qualified Web.HttpApiData as WH + +import Data.Function ((&)) +import Data.Monoid ((<>)) +import Data.Text (Text) +import GHC.Exts (IsString(..)) + +-- * Dispatch + +-- ** Lbs + +-- | send a request returning the raw http response +dispatchLbs + :: (Produces req accept, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> G4fClientConfig -- ^ config + -> G4fClientRequest req contentType res accept -- ^ request + -> IO (NH.Response BCL.ByteString) -- ^ response +dispatchLbs manager config request = do + initReq <- _toInitRequest config request + dispatchInitUnsafe manager config initReq + +-- ** Mime + +-- | pair of decoded http body and http response +data MimeResult res = + MimeResult { mimeResult :: Either MimeError res -- ^ decoded http body + , mimeResultResponse :: NH.Response BCL.ByteString -- ^ http response + } + deriving (Show, Functor, Foldable, Traversable) + +-- | pair of unrender/parser error and http response +data MimeError = + MimeError { + mimeError :: String -- ^ unrender/parser error + , mimeErrorResponse :: NH.Response BCL.ByteString -- ^ http response + } deriving (Show) + +-- | send a request returning the 'MimeResult' +dispatchMime + :: forall req contentType res accept. (Produces req accept, MimeUnrender accept res, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> G4fClientConfig -- ^ config + -> G4fClientRequest req contentType res accept -- ^ request + -> IO (MimeResult res) -- ^ response +dispatchMime manager config request = do + httpResponse <- dispatchLbs manager config request + let statusCode = NH.statusCode . NH.responseStatus $ httpResponse + parsedResult <- + runConfigLogWithExceptions "Client" config $ + do if (statusCode >= 400 && statusCode < 600) + then do + let s = "error statusCode: " ++ show statusCode + _log "Client" levelError (T.pack s) + pure (Left (MimeError s httpResponse)) + else case mimeUnrender (P.Proxy :: P.Proxy accept) (NH.responseBody httpResponse) of + Left s -> do + _log "Client" levelError (T.pack s) + pure (Left (MimeError s httpResponse)) + Right r -> pure (Right r) + return (MimeResult parsedResult httpResponse) + +-- | like 'dispatchMime', but only returns the decoded http body +dispatchMime' + :: (Produces req accept, MimeUnrender accept res, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> G4fClientConfig -- ^ config + -> G4fClientRequest req contentType res accept -- ^ request + -> IO (Either MimeError res) -- ^ response +dispatchMime' manager config request = do + MimeResult parsedResult _ <- dispatchMime manager config request + return parsedResult + +-- ** Unsafe + +-- | like 'dispatchReqLbs', but does not validate the operation is a 'Producer' of the "accept" 'MimeType'. (Useful if the server's response is undocumented) +dispatchLbsUnsafe + :: (MimeType accept, MimeType contentType) + => NH.Manager -- ^ http-client Connection manager + -> G4fClientConfig -- ^ config + -> G4fClientRequest req contentType res accept -- ^ request + -> IO (NH.Response BCL.ByteString) -- ^ response +dispatchLbsUnsafe manager config request = do + initReq <- _toInitRequest config request + dispatchInitUnsafe manager config initReq + +-- | dispatch an InitRequest +dispatchInitUnsafe + :: NH.Manager -- ^ http-client Connection manager + -> G4fClientConfig -- ^ config + -> InitRequest req contentType res accept -- ^ init request + -> IO (NH.Response BCL.ByteString) -- ^ response +dispatchInitUnsafe manager config (InitRequest req) = do + runConfigLogWithExceptions src config $ + do _log src levelInfo requestLogMsg + _log src levelDebug requestDbgLogMsg + res <- P.liftIO $ NH.httpLbs req manager + _log src levelInfo (responseLogMsg res) + _log src levelDebug ((T.pack . show) res) + return res + where + src = "Client" + endpoint = + T.pack $ + BC.unpack $ + NH.method req <> " " <> NH.host req <> NH.path req <> NH.queryString req + requestLogMsg = "REQ:" <> endpoint + requestDbgLogMsg = + "Headers=" <> (T.pack . show) (NH.requestHeaders req) <> " Body=" <> + (case NH.requestBody req of + NH.RequestBodyLBS xs -> T.decodeUtf8 (BL.toStrict xs) + _ -> "") + responseStatusCode = (T.pack . show) . NH.statusCode . NH.responseStatus + responseLogMsg res = + "RES:statusCode=" <> responseStatusCode res <> " (" <> endpoint <> ")" + +-- * InitRequest + +-- | wraps an http-client 'Request' with request/response type parameters +newtype InitRequest req contentType res accept = InitRequest + { unInitRequest :: NH.Request + } deriving (Show) + +-- | Build an http-client 'Request' record from the supplied config and request +_toInitRequest + :: (MimeType accept, MimeType contentType) + => G4fClientConfig -- ^ config + -> G4fClientRequest req contentType res accept -- ^ request + -> IO (InitRequest req contentType res accept) -- ^ initialized request +_toInitRequest config req0 = + runConfigLogWithExceptions "Client" config $ do + parsedReq <- P.liftIO $ NH.parseRequest $ BCL.unpack $ BCL.append (configHost config) (BCL.concat (rUrlPath req0)) + req1 <- P.liftIO $ _applyAuthMethods req0 config + P.when + (configValidateAuthMethods config && (not . null . rAuthTypes) req1) + (E.throw $ AuthMethodException $ "AuthMethod not configured: " <> (show . head . rAuthTypes) req1) + let req2 = req1 & _setContentTypeHeader & _setAcceptHeader + params = rParams req2 + reqHeaders = ("User-Agent", WH.toHeader (configUserAgent config)) : paramsHeaders params + reqQuery = let query = paramsQuery params + queryExtraUnreserved = configQueryExtraUnreserved config + in if B.null queryExtraUnreserved + then NH.renderQuery True query + else NH.renderQueryPartialEscape True (toPartialEscapeQuery queryExtraUnreserved query) + pReq = parsedReq { NH.method = rMethod req2 + , NH.requestHeaders = reqHeaders + , NH.queryString = reqQuery + } + outReq <- case paramsBody params of + ParamBodyNone -> pure (pReq { NH.requestBody = mempty }) + ParamBodyB bs -> pure (pReq { NH.requestBody = NH.RequestBodyBS bs }) + ParamBodyBL bl -> pure (pReq { NH.requestBody = NH.RequestBodyLBS bl }) + ParamBodyFormUrlEncoded form -> pure (pReq { NH.requestBody = NH.RequestBodyLBS (WH.urlEncodeForm form) }) + ParamBodyMultipartFormData parts -> NH.formDataBody parts pReq + + pure (InitRequest outReq) + +-- | modify the underlying Request +modifyInitRequest :: InitRequest req contentType res accept -> (NH.Request -> NH.Request) -> InitRequest req contentType res accept +modifyInitRequest (InitRequest req) f = InitRequest (f req) + +-- | modify the underlying Request (monadic) +modifyInitRequestM :: Monad m => InitRequest req contentType res accept -> (NH.Request -> m NH.Request) -> m (InitRequest req contentType res accept) +modifyInitRequestM (InitRequest req) f = fmap InitRequest (f req) + +-- ** Logging + +-- | Run a block using the configured logger instance +runConfigLog + :: P.MonadIO m + => G4fClientConfig -> LogExec m a +runConfigLog config = configLogExecWithContext config (configLogContext config) + +-- | Run a block using the configured logger instance (logs exceptions) +runConfigLogWithExceptions + :: (E.MonadCatch m, P.MonadIO m) + => T.Text -> G4fClientConfig -> LogExec m a +runConfigLogWithExceptions src config = runConfigLog config . logExceptions src diff --git a/lib/G4fClient/Core.hs b/lib/G4fClient/Core.hs new file mode 100644 index 0000000..72756be --- /dev/null +++ b/lib/G4fClient/Core.hs @@ -0,0 +1,589 @@ +{- + FastAPI + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + OpenAPI Version: 3.1.0 + FastAPI API version: 0.1.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) +-} + +{-| +Module : G4fClient.Core +-} + +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE ExistentialQuantification #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE CPP #-} +{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-unused-binds -fno-warn-unused-imports #-} + +module G4fClient.Core where + +import G4fClient.MimeTypes +import G4fClient.Logging + +import qualified Control.Arrow as P (left) +import qualified Control.DeepSeq as NF +import qualified Control.Exception.Safe as E +import qualified Data.Aeson as A +import qualified Data.ByteString as B +import qualified Data.ByteString.Base64.Lazy as BL64 +import qualified Data.ByteString.Builder as BB +import qualified Data.ByteString.Char8 as BC +import qualified Data.ByteString.Lazy as BL +import qualified Data.ByteString.Lazy.Char8 as BCL +import qualified Data.CaseInsensitive as CI +import qualified Data.Data as P (Data, Typeable, TypeRep, typeRep) +import qualified Data.Foldable as P +import qualified Data.Ix as P +import qualified Data.Kind as K (Type) +import qualified Data.Maybe as P +import qualified Data.Proxy as P (Proxy(..)) +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Data.Text.Lazy.Encoding as TL +import qualified Data.Time as TI +import qualified Data.Time.ISO8601 as TI +import qualified GHC.Base as P (Alternative) +import qualified Lens.Micro as L +import qualified Network.HTTP.Client.MultipartFormData as NH +import qualified Network.HTTP.Types as NH +import qualified Prelude as P +import qualified Text.Printf as T +import qualified Web.FormUrlEncoded as WH +import qualified Web.HttpApiData as WH + +import Control.Applicative ((<|>)) +import Control.Applicative (Alternative) +import Control.Monad.Fail (MonadFail) +import Data.Function ((&)) +import Data.Foldable(foldlM) +import Data.Monoid ((<>)) +import Data.Text (Text) +import Prelude (($), (.), (&&), (<$>), (<*>), Maybe(..), Bool(..), Char, String, fmap, mempty, pure, return, show, IO, Monad, Functor, maybe) + +-- * G4fClientConfig + +-- | +data G4fClientConfig = G4fClientConfig + { configHost :: BCL.ByteString -- ^ host supplied in the Request + , configUserAgent :: Text -- ^ user-agent supplied in the Request + , configLogExecWithContext :: LogExecWithContext -- ^ Run a block using a Logger instance + , configLogContext :: LogContext -- ^ Configures the logger + , configAuthMethods :: [AnyAuthMethod] -- ^ List of configured auth methods + , configValidateAuthMethods :: Bool -- ^ throw exceptions if auth methods are not configured + , configQueryExtraUnreserved :: B.ByteString -- ^ Configures additional querystring characters which must not be URI encoded, e.g. '+' or ':' + } + +-- | display the config +instance P.Show G4fClientConfig where + show c = + T.printf + "{ configHost = %v, configUserAgent = %v, ..}" + (show (configHost c)) + (show (configUserAgent c)) + +-- | constructs a default G4fClientConfig +-- +-- configHost: +-- +-- @http://localhost@ +-- +-- configUserAgent: +-- +-- @"g4f-client/7.1.4"@ +-- +newConfig :: IO G4fClientConfig +newConfig = do + logCxt <- initLogContext + return $ G4fClientConfig + { configHost = "http://localhost" + , configUserAgent = "g4f-client/7.1.4" + , configLogExecWithContext = runDefaultLogExecWithContext + , configLogContext = logCxt + , configAuthMethods = [] + , configValidateAuthMethods = True + , configQueryExtraUnreserved = "" + } + +-- | updates config use AuthMethod on matching requests +addAuthMethod :: AuthMethod auth => G4fClientConfig -> auth -> G4fClientConfig +addAuthMethod config@G4fClientConfig {configAuthMethods = as} a = + config { configAuthMethods = AnyAuthMethod a : as} + +-- | updates the config to use stdout logging +withStdoutLogging :: G4fClientConfig -> IO G4fClientConfig +withStdoutLogging p = do + logCxt <- stdoutLoggingContext (configLogContext p) + return $ p { configLogExecWithContext = stdoutLoggingExec, configLogContext = logCxt } + +-- | updates the config to use stderr logging +withStderrLogging :: G4fClientConfig -> IO G4fClientConfig +withStderrLogging p = do + logCxt <- stderrLoggingContext (configLogContext p) + return $ p { configLogExecWithContext = stderrLoggingExec, configLogContext = logCxt } + +-- | updates the config to disable logging +withNoLogging :: G4fClientConfig -> G4fClientConfig +withNoLogging p = p { configLogExecWithContext = runNullLogExec} + +-- * G4fClientRequest + +-- | Represents a request. +-- +-- Type Variables: +-- +-- * req - request operation +-- * contentType - 'MimeType' associated with request body +-- * res - response model +-- * accept - 'MimeType' associated with response body +data G4fClientRequest req contentType res accept = G4fClientRequest + { rMethod :: NH.Method -- ^ Method of G4fClientRequest + , rUrlPath :: [BCL.ByteString] -- ^ Endpoint of G4fClientRequest + , rParams :: Params -- ^ params of G4fClientRequest + , rAuthTypes :: [P.TypeRep] -- ^ types of auth methods + } + deriving (P.Show) + +-- | 'rMethod' Lens +rMethodL :: Lens_' (G4fClientRequest req contentType res accept) NH.Method +rMethodL f G4fClientRequest{..} = (\rMethod -> G4fClientRequest { rMethod, ..} ) <$> f rMethod +{-# INLINE rMethodL #-} + +-- | 'rUrlPath' Lens +rUrlPathL :: Lens_' (G4fClientRequest req contentType res accept) [BCL.ByteString] +rUrlPathL f G4fClientRequest{..} = (\rUrlPath -> G4fClientRequest { rUrlPath, ..} ) <$> f rUrlPath +{-# INLINE rUrlPathL #-} + +-- | 'rParams' Lens +rParamsL :: Lens_' (G4fClientRequest req contentType res accept) Params +rParamsL f G4fClientRequest{..} = (\rParams -> G4fClientRequest { rParams, ..} ) <$> f rParams +{-# INLINE rParamsL #-} + +-- | 'rParams' Lens +rAuthTypesL :: Lens_' (G4fClientRequest req contentType res accept) [P.TypeRep] +rAuthTypesL f G4fClientRequest{..} = (\rAuthTypes -> G4fClientRequest { rAuthTypes, ..} ) <$> f rAuthTypes +{-# INLINE rAuthTypesL #-} + +-- * HasBodyParam + +-- | Designates the body parameter of a request +class HasBodyParam req param where + setBodyParam :: forall contentType res accept. (Consumes req contentType, MimeRender contentType param) => G4fClientRequest req contentType res accept -> param -> G4fClientRequest req contentType res accept + setBodyParam req xs = + req `_setBodyLBS` mimeRender (P.Proxy :: P.Proxy contentType) xs & _setContentTypeHeader + +-- * HasOptionalParam + +-- | Designates the optional parameters of a request +class HasOptionalParam req param where + {-# MINIMAL applyOptionalParam | (-&-) #-} + + -- | Apply an optional parameter to a request + applyOptionalParam :: G4fClientRequest req contentType res accept -> param -> G4fClientRequest req contentType res accept + applyOptionalParam = (-&-) + {-# INLINE applyOptionalParam #-} + + -- | infix operator \/ alias for 'addOptionalParam' + (-&-) :: G4fClientRequest req contentType res accept -> param -> G4fClientRequest req contentType res accept + (-&-) = applyOptionalParam + {-# INLINE (-&-) #-} + +infixl 2 -&- + +-- | Request Params +data Params = Params + { paramsQuery :: NH.Query + , paramsHeaders :: NH.RequestHeaders + , paramsBody :: ParamBody + } + deriving (P.Show) + +-- | 'paramsQuery' Lens +paramsQueryL :: Lens_' Params NH.Query +paramsQueryL f Params{..} = (\paramsQuery -> Params { paramsQuery, ..} ) <$> f paramsQuery +{-# INLINE paramsQueryL #-} + +-- | 'paramsHeaders' Lens +paramsHeadersL :: Lens_' Params NH.RequestHeaders +paramsHeadersL f Params{..} = (\paramsHeaders -> Params { paramsHeaders, ..} ) <$> f paramsHeaders +{-# INLINE paramsHeadersL #-} + +-- | 'paramsBody' Lens +paramsBodyL :: Lens_' Params ParamBody +paramsBodyL f Params{..} = (\paramsBody -> Params { paramsBody, ..} ) <$> f paramsBody +{-# INLINE paramsBodyL #-} + +-- | Request Body +data ParamBody + = ParamBodyNone + | ParamBodyB B.ByteString + | ParamBodyBL BL.ByteString + | ParamBodyFormUrlEncoded WH.Form + | ParamBodyMultipartFormData [NH.Part] + deriving (P.Show) + +-- ** G4fClientRequest Utils + +_mkRequest :: NH.Method -- ^ Method + -> [BCL.ByteString] -- ^ Endpoint + -> G4fClientRequest req contentType res accept -- ^ req: Request Type, res: Response Type +_mkRequest m u = G4fClientRequest m u _mkParams [] + +_mkParams :: Params +_mkParams = Params [] [] ParamBodyNone + +setHeader :: + G4fClientRequest req contentType res accept + -> [NH.Header] + -> G4fClientRequest req contentType res accept +setHeader req header = + req `removeHeader` P.fmap P.fst header + & (`addHeader` header) + +addHeader :: + G4fClientRequest req contentType res accept + -> [NH.Header] + -> G4fClientRequest req contentType res accept +addHeader req header = L.over (rParamsL . paramsHeadersL) (header P.++) req + +removeHeader :: G4fClientRequest req contentType res accept -> [NH.HeaderName] -> G4fClientRequest req contentType res accept +removeHeader req header = + req & + L.over + (rParamsL . paramsHeadersL) + (P.filter (\h -> cifst h `P.notElem` P.fmap CI.mk header)) + where + cifst = CI.mk . P.fst + + +_setContentTypeHeader :: forall req contentType res accept. MimeType contentType => G4fClientRequest req contentType res accept -> G4fClientRequest req contentType res accept +_setContentTypeHeader req = + case mimeType (P.Proxy :: P.Proxy contentType) of + Just m -> req `setHeader` [("content-type", BC.pack $ P.show m)] + Nothing -> req `removeHeader` ["content-type"] + +_setAcceptHeader :: forall req contentType res accept. MimeType accept => G4fClientRequest req contentType res accept -> G4fClientRequest req contentType res accept +_setAcceptHeader req = + case mimeType (P.Proxy :: P.Proxy accept) of + Just m -> req `setHeader` [("accept", BC.pack $ P.show m)] + Nothing -> req `removeHeader` ["accept"] + +setQuery :: + G4fClientRequest req contentType res accept + -> [NH.QueryItem] + -> G4fClientRequest req contentType res accept +setQuery req query = + req & + L.over + (rParamsL . paramsQueryL) + (P.filter (\q -> cifst q `P.notElem` P.fmap cifst query)) & + (`addQuery` query) + where + cifst = CI.mk . P.fst + +addQuery :: + G4fClientRequest req contentType res accept + -> [NH.QueryItem] + -> G4fClientRequest req contentType res accept +addQuery req query = req & L.over (rParamsL . paramsQueryL) (query P.++) + +addForm :: G4fClientRequest req contentType res accept -> WH.Form -> G4fClientRequest req contentType res accept +addForm req newform = + let form = case paramsBody (rParams req) of + ParamBodyFormUrlEncoded _form -> _form + _ -> mempty + in req & L.set (rParamsL . paramsBodyL) (ParamBodyFormUrlEncoded (newform <> form)) + +_addMultiFormPart :: G4fClientRequest req contentType res accept -> NH.Part -> G4fClientRequest req contentType res accept +_addMultiFormPart req newpart = + let parts = case paramsBody (rParams req) of + ParamBodyMultipartFormData _parts -> _parts + _ -> [] + in req & L.set (rParamsL . paramsBodyL) (ParamBodyMultipartFormData (newpart : parts)) + +_setBodyBS :: G4fClientRequest req contentType res accept -> B.ByteString -> G4fClientRequest req contentType res accept +_setBodyBS req body = + req & L.set (rParamsL . paramsBodyL) (ParamBodyB body) + +_setBodyLBS :: G4fClientRequest req contentType res accept -> BL.ByteString -> G4fClientRequest req contentType res accept +_setBodyLBS req body = + req & L.set (rParamsL . paramsBodyL) (ParamBodyBL body) + +_hasAuthType :: AuthMethod authMethod => G4fClientRequest req contentType res accept -> P.Proxy authMethod -> G4fClientRequest req contentType res accept +_hasAuthType req proxy = + req & L.over rAuthTypesL (P.typeRep proxy :) + +-- ** Params Utils + +toPath + :: WH.ToHttpApiData a + => a -> BCL.ByteString +toPath = BB.toLazyByteString . WH.toEncodedUrlPiece + +toHeader :: WH.ToHttpApiData a => (NH.HeaderName, a) -> [NH.Header] +toHeader x = [fmap WH.toHeader x] + +toForm :: WH.ToHttpApiData v => (BC.ByteString, v) -> WH.Form +toForm (k,v) = WH.toForm [(BC.unpack k,v)] + +toQuery :: WH.ToHttpApiData a => (BC.ByteString, Maybe a) -> [NH.QueryItem] +toQuery x = [(fmap . fmap) toQueryParam x] + where toQueryParam = T.encodeUtf8 . WH.toQueryParam + +toJsonQuery :: A.ToJSON a => (BC.ByteString, Maybe a) -> [NH.QueryItem] +toJsonQuery = toQuery . (fmap . fmap) (TL.decodeUtf8 . A.encode) + +toPartialEscapeQuery :: B.ByteString -> NH.Query -> NH.PartialEscapeQuery +toPartialEscapeQuery extraUnreserved query = fmap (\(k, v) -> (k, maybe [] go v)) query + where go :: B.ByteString -> [NH.EscapeItem] + go v = v & B.groupBy (\a b -> a `B.notElem` extraUnreserved && b `B.notElem` extraUnreserved) + & fmap (\xs -> if B.null xs then NH.QN xs + else if B.head xs `B.elem` extraUnreserved + then NH.QN xs -- Not Encoded + else NH.QE xs -- Encoded + ) + +-- *** OpenAPI `CollectionFormat` Utils + +-- | Determines the format of the array if type array is used. +data CollectionFormat + = CommaSeparated -- ^ CSV format for multiple parameters. + | SpaceSeparated -- ^ Also called "SSV" + | TabSeparated -- ^ Also called "TSV" + | PipeSeparated -- ^ `value1|value2|value2` + | MultiParamArray -- ^ Using multiple GET parameters, e.g. `foo=bar&foo=baz`. This is valid only for parameters in "query" ('NH.Query') or "formData" ('WH.Form') + +toHeaderColl :: WH.ToHttpApiData a => CollectionFormat -> (NH.HeaderName, [a]) -> [NH.Header] +toHeaderColl c xs = _toColl c toHeader xs + +toFormColl :: WH.ToHttpApiData v => CollectionFormat -> (BC.ByteString, [v]) -> WH.Form +toFormColl c xs = WH.toForm $ fmap unpack $ _toColl c toHeader $ pack xs + where + pack (k,v) = (CI.mk k, v) + unpack (k,v) = (BC.unpack (CI.original k), BC.unpack v) + +toQueryColl :: WH.ToHttpApiData a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query +toQueryColl c xs = _toCollA c toQuery xs + +toJsonQueryColl :: A.ToJSON a => CollectionFormat -> (BC.ByteString, Maybe [a]) -> NH.Query +toJsonQueryColl c xs = _toCollA c toJsonQuery xs + +_toColl :: P.Traversable f => CollectionFormat -> (f a -> [(b, BC.ByteString)]) -> f [a] -> [(b, BC.ByteString)] +_toColl c encode xs = fmap (fmap P.fromJust) (_toCollA' c fencode BC.singleton (fmap Just xs)) + where fencode = fmap (fmap Just) . encode . fmap P.fromJust + {-# INLINE fencode #-} + +_toCollA :: (P.Traversable f, P.Traversable t, P.Alternative t) => CollectionFormat -> (f (t a) -> [(b, t BC.ByteString)]) -> f (t [a]) -> [(b, t BC.ByteString)] +_toCollA c encode xs = _toCollA' c encode BC.singleton xs + +_toCollA' :: (P.Monoid c, P.Traversable f, P.Traversable t, P.Alternative t) => CollectionFormat -> (f (t a) -> [(b, t c)]) -> (Char -> c) -> f (t [a]) -> [(b, t c)] +_toCollA' c encode one xs = case c of + CommaSeparated -> go (one ',') + SpaceSeparated -> go (one ' ') + TabSeparated -> go (one '\t') + PipeSeparated -> go (one '|') + MultiParamArray -> expandList + where + go sep = + [P.foldl1 (\(sk, sv) (_, v) -> (sk, (combine sep <$> sv <*> v) <|> sv <|> v)) expandList] + combine sep x y = x <> sep <> y + expandList = (P.concatMap encode . (P.traverse . P.traverse) P.toList) xs + {-# INLINE go #-} + {-# INLINE expandList #-} + {-# INLINE combine #-} + +-- * AuthMethods + +-- | Provides a method to apply auth methods to requests +class P.Typeable a => + AuthMethod a where + applyAuthMethod + :: G4fClientConfig + -> a + -> G4fClientRequest req contentType res accept + -> IO (G4fClientRequest req contentType res accept) + +-- | An existential wrapper for any AuthMethod +data AnyAuthMethod = forall a. AuthMethod a => AnyAuthMethod a deriving (P.Typeable) + +instance AuthMethod AnyAuthMethod where applyAuthMethod config (AnyAuthMethod a) req = applyAuthMethod config a req + +-- | indicates exceptions related to AuthMethods +data AuthMethodException = AuthMethodException String deriving (P.Show, P.Typeable) + +instance E.Exception AuthMethodException + +-- | apply all matching AuthMethods in config to request +_applyAuthMethods + :: G4fClientRequest req contentType res accept + -> G4fClientConfig + -> IO (G4fClientRequest req contentType res accept) +_applyAuthMethods req config@(G4fClientConfig {configAuthMethods = as}) = + foldlM go req as + where + go r (AnyAuthMethod a) = applyAuthMethod config a r + +-- * Utils + +-- | Removes Null fields. (OpenAPI-Specification 2.0 does not allow Null in JSON) +#if MIN_VERSION_aeson(2,0,0) +_omitNulls :: [(A.Key, A.Value)] -> A.Value +#else +_omitNulls :: [(Text, A.Value)] -> A.Value +#endif +_omitNulls = A.object . P.filter notNull + where + notNull (_, A.Null) = False + notNull _ = True + +-- | Encodes fields using WH.toQueryParam +_toFormItem :: (WH.ToHttpApiData a, Functor f) => t -> f a -> f (t, [Text]) +_toFormItem name x = (name,) . (:[]) . WH.toQueryParam <$> x + +-- | Collapse (Just "") to Nothing +_emptyToNothing :: Maybe String -> Maybe String +_emptyToNothing (Just "") = Nothing +_emptyToNothing x = x +{-# INLINE _emptyToNothing #-} + +-- | Collapse (Just mempty) to Nothing +_memptyToNothing :: (P.Monoid a, P.Eq a) => Maybe a -> Maybe a +_memptyToNothing (Just x) | x P.== P.mempty = Nothing +_memptyToNothing x = x +{-# INLINE _memptyToNothing #-} + +-- * DateTime Formatting + +newtype DateTime = DateTime { unDateTime :: TI.UTCTime } + deriving (P.Eq,P.Data,P.Ord,P.Typeable,NF.NFData) +instance A.FromJSON DateTime where + parseJSON = A.withText "DateTime" (_readDateTime . T.unpack) +instance A.ToJSON DateTime where + toJSON (DateTime t) = A.toJSON (_showDateTime t) +instance WH.FromHttpApiData DateTime where + parseUrlPiece = P.maybe (P.Left "parseUrlPiece @DateTime") P.Right . _readDateTime . T.unpack +instance WH.ToHttpApiData DateTime where + toUrlPiece (DateTime t) = T.pack (_showDateTime t) +instance P.Show DateTime where + show (DateTime t) = _showDateTime t +instance MimeRender MimeMultipartFormData DateTime where + mimeRender _ = mimeRenderDefaultMultipartFormData + +-- | @_parseISO8601@ +_readDateTime :: (MonadFail m, Alternative m) => String -> m DateTime +_readDateTime s = + DateTime <$> _parseISO8601 s +{-# INLINE _readDateTime #-} + +-- | @TI.formatISO8601Millis@ +_showDateTime :: (t ~ TI.UTCTime, TI.FormatTime t) => t -> String +_showDateTime = + TI.formatISO8601Millis +{-# INLINE _showDateTime #-} + +-- | parse an ISO8601 date-time string +_parseISO8601 :: (TI.ParseTime t, MonadFail m, Alternative m) => String -> m t +_parseISO8601 t = + P.asum $ + P.flip (TI.parseTimeM True TI.defaultTimeLocale) t <$> + ["%FT%T%QZ", "%FT%T%Q%z", "%FT%T%Q%Z"] +{-# INLINE _parseISO8601 #-} + +-- * Date Formatting + +newtype Date = Date { unDate :: TI.Day } + deriving (P.Enum,P.Eq,P.Data,P.Ord,P.Ix,NF.NFData) +instance A.FromJSON Date where + parseJSON = A.withText "Date" (_readDate . T.unpack) +instance A.ToJSON Date where + toJSON (Date t) = A.toJSON (_showDate t) +instance WH.FromHttpApiData Date where + parseUrlPiece = P.maybe (P.Left "parseUrlPiece @Date") P.Right . _readDate . T.unpack +instance WH.ToHttpApiData Date where + toUrlPiece (Date t) = T.pack (_showDate t) +instance P.Show Date where + show (Date t) = _showDate t +instance MimeRender MimeMultipartFormData Date where + mimeRender _ = mimeRenderDefaultMultipartFormData + +-- | @TI.parseTimeM True TI.defaultTimeLocale "%Y-%m-%d"@ +_readDate :: MonadFail m => String -> m Date +_readDate s = Date <$> TI.parseTimeM True TI.defaultTimeLocale "%Y-%m-%d" s +{-# INLINE _readDate #-} + +-- | @TI.formatTime TI.defaultTimeLocale "%Y-%m-%d"@ +_showDate :: TI.FormatTime t => t -> String +_showDate = + TI.formatTime TI.defaultTimeLocale "%Y-%m-%d" +{-# INLINE _showDate #-} + +-- * Byte/Binary Formatting + + +-- | base64 encoded characters +newtype ByteArray = ByteArray { unByteArray :: BL.ByteString } + deriving (P.Eq,P.Data,P.Ord,P.Typeable,NF.NFData) + +instance A.FromJSON ByteArray where + parseJSON = A.withText "ByteArray" _readByteArray +instance A.ToJSON ByteArray where + toJSON = A.toJSON . _showByteArray +instance WH.FromHttpApiData ByteArray where + parseUrlPiece = P.maybe (P.Left "parseUrlPiece @ByteArray") P.Right . _readByteArray +instance WH.ToHttpApiData ByteArray where + toUrlPiece = _showByteArray +instance P.Show ByteArray where + show = T.unpack . _showByteArray +instance MimeRender MimeMultipartFormData ByteArray where + mimeRender _ = mimeRenderDefaultMultipartFormData + +-- | read base64 encoded characters +_readByteArray :: MonadFail m => Text -> m ByteArray +_readByteArray = P.either P.fail (pure . ByteArray) . BL64.decode . BL.fromStrict . T.encodeUtf8 +{-# INLINE _readByteArray #-} + +-- | show base64 encoded characters +_showByteArray :: ByteArray -> Text +_showByteArray = T.decodeUtf8 . BL.toStrict . BL64.encode . unByteArray +{-# INLINE _showByteArray #-} + +-- | any sequence of octets +newtype Binary = Binary { unBinary :: BL.ByteString } + deriving (P.Eq,P.Data,P.Ord,P.Typeable,NF.NFData) + +instance A.FromJSON Binary where + parseJSON = A.withText "Binary" _readBinaryBase64 +instance A.ToJSON Binary where + toJSON = A.toJSON . _showBinaryBase64 +instance WH.FromHttpApiData Binary where + parseUrlPiece = P.maybe (P.Left "parseUrlPiece @Binary") P.Right . _readBinaryBase64 +instance WH.ToHttpApiData Binary where + toUrlPiece = _showBinaryBase64 +instance P.Show Binary where + show = T.unpack . _showBinaryBase64 +instance MimeRender MimeMultipartFormData Binary where + mimeRender _ = unBinary + +_readBinaryBase64 :: MonadFail m => Text -> m Binary +_readBinaryBase64 = P.either P.fail (pure . Binary) . BL64.decode . BL.fromStrict . T.encodeUtf8 +{-# INLINE _readBinaryBase64 #-} + +_showBinaryBase64 :: Binary -> Text +_showBinaryBase64 = T.decodeUtf8 . BL.toStrict . BL64.encode . unBinary +{-# INLINE _showBinaryBase64 #-} + +-- * Lens Type Aliases + +type Lens_' s a = Lens_ s s a a +type Lens_ s t a b = forall (f :: K.Type -> K.Type). Functor f => (a -> f b) -> s -> f t diff --git a/lib/G4fClient/Logging.hs b/lib/G4fClient/Logging.hs new file mode 100644 index 0000000..ab7b449 --- /dev/null +++ b/lib/G4fClient/Logging.hs @@ -0,0 +1,33 @@ +{- + FastAPI + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + OpenAPI Version: 3.1.0 + FastAPI API version: 0.1.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) +-} + +{-| +Module : G4fClient.Logging +Logging functions +-} +{-# LANGUAGE CPP #-} + +#ifdef USE_KATIP + +module G4fClient.Logging + ( module G4fClient.LoggingKatip + ) where + +import G4fClient.LoggingKatip + +#else + +module G4fClient.Logging + ( module G4fClient.LoggingMonadLogger + ) where + +import G4fClient.LoggingMonadLogger + +#endif diff --git a/lib/G4fClient/LoggingKatip.hs b/lib/G4fClient/LoggingKatip.hs new file mode 100644 index 0000000..3d258f7 --- /dev/null +++ b/lib/G4fClient/LoggingKatip.hs @@ -0,0 +1,117 @@ +{- + FastAPI + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + OpenAPI Version: 3.1.0 + FastAPI API version: 0.1.0 + Generated by OpenAPI Generator (https://openapi-generator.tech) +-} + +{-| +Module : G4fClient.LoggingKatip +Katip Logging functions +-} + +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module G4fClient.LoggingKatip where + +import qualified Control.Exception.Safe as E +import qualified Control.Monad.IO.Class as P +import qualified Control.Monad.Trans.Reader as P +import qualified Data.Text as T +import qualified Lens.Micro as L +import qualified System.IO as IO + +import Data.Text (Text) +import GHC.Exts (IsString(..)) + +import qualified Katip as LG + +-- * Type Aliases (for compatibility) + +-- | Runs a Katip logging block with the Log environment +type LogExecWithContext = forall m a. P.MonadIO m => + LogContext -> LogExec m a + +-- | A Katip logging block +type LogExec m a = LG.KatipT m a -> m a + +-- | A Katip Log environment +type LogContext = LG.LogEnv + +-- | A Katip Log severity +type LogLevel = LG.Severity + +-- * default logger + +-- | the default log environment +initLogContext :: IO LogContext +initLogContext = LG.initLogEnv "G4fClient" "dev" + +-- | Runs a Katip logging block with the Log environment +runDefaultLogExecWithContext :: LogExecWithContext +runDefaultLogExecWithContext = LG.runKatipT + +-- * stdout logger + +-- | Runs a Katip logging block with the Log environment +stdoutLoggingExec :: LogExecWithContext +stdoutLoggingExec = runDefaultLogExecWithContext + +-- | A Katip Log environment which targets stdout +stdoutLoggingContext :: LogContext -> IO LogContext +stdoutLoggingContext cxt = do + handleScribe <- LG.mkHandleScribe LG.ColorIfTerminal IO.stdout (LG.permitItem LG.InfoS) LG.V2 + LG.registerScribe "stdout" handleScribe LG.defaultScribeSettings cxt + +-- * stderr logger + +-- | Runs a Katip logging block with the Log environment +stderrLoggingExec :: LogExecWithContext +stderrLoggingExec = runDefaultLogExecWithContext + +-- | A Katip Log environment which targets stderr +stderrLoggingContext :: LogContext -> IO LogContext +stderrLoggingContext cxt = do + handleScribe <- LG.mkHandleScribe LG.ColorIfTerminal IO.stderr (LG.permitItem LG.InfoS) LG.V2 + LG.registerScribe "stderr" handleScribe LG.defaultScribeSettings cxt + +-- * Null logger + +-- | Disables Katip logging +runNullLogExec :: LogExecWithContext +runNullLogExec le (LG.KatipT f) = P.runReaderT f (L.set LG.logEnvScribes mempty le) + +-- * Log Msg + +-- | Log a katip message +_log :: (Applicative m, LG.Katip m) => Text -> LogLevel -> Text -> m () +_log src level msg = do + LG.logMsg (fromString $ T.unpack src) level (LG.logStr msg) + +-- * Log Exceptions + +-- | re-throws exceptions after logging them +logExceptions + :: (LG.Katip m, E.MonadCatch m, Applicative m) + => Text -> m a -> m a +logExceptions src = + E.handle + (\(e :: E.SomeException) -> do + _log src LG.ErrorS ((T.pack . show) e) + E.throw e) + +-- * Log Level + +levelInfo :: LogLevel +levelInfo = LG.InfoS + +levelError :: LogLevel +levelError = LG.ErrorS + +levelDebug :: LogLevel +levelDebug = LG.DebugS diff --git a/lib/G4fClient/LoggingMonadLogger.hs b/lib/G4fClient/LoggingMonadLogger.hs new file mode 100644 index 0000000..70ab956 --- /dev/null +++ b/lib/G4fClient/LoggingMonadLogger.hs @@ -0,0 +1,126 @@ +{- + FastAPI + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + OpenAPI Version: 3.1.0 + FastAPI