classes/RestMethod/RestMethod.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
using module ..\AtlassianContext.psm1
using module .\RestMethodQueryParams.psm1

class RestMethod {

    #####################
    # HIDDEN PROPERTIES #
    #####################
    
    #####################
    # PUBLIC PROPERTIES #
    #####################

    # The URI path of function to invoke (do not include host name)
    [ValidateNotNullOrEmpty()]
    [string]
    $FunctionPath

    # The HTTP method to use for the request
    [ValidateSet("GET","POST","PUT","PATCH","DELETE")]
    [string]
    $HttpMethod

    # Additional headers to be added to the request (Auth and Content Type are included automatically)
    [hashtable]
    $Headers=@{}

    # The default content type
    [string]
    $ContentType = 'application/json'

    # Parameters to be supplied to the method in the query string
    [RestMethodQueryParams]
    $Query

    ################
    # CONSTRUCTORS #
    ################

    #no params
    RestMethod(
        [string]$FunctionPath,
        [string]$HttpMethod
    ){
        $this.Init($FunctionPath,$HttpMethod)
    }

    #query params only
    RestMethod(
        [string]$FunctionPath,
        [string]$HttpMethod,
        [RestMethodQueryParams]$Query
    ){
        $this.Init($FunctionPath,$HttpMethod)
        $this.Query = $Query
    }

    ##################
    # HIDDEN METHODS #
    ##################

    hidden
    [void]
    Init(
        [string]$FunctionPath,
        [string]$HttpMethod
    ){
        $this.FunctionPath = if ($FunctionPath.StartsWith("/")) {$FunctionPath.Substring(1)} else {$FunctionPath}
        $this.HttpMethod = $HttpMethod
    }

    hidden
    static
    [AtlassianContext]
    FillContext(
        [AtlassianContext]$AtlassianContext
    ){
        if ($null -eq $AtlassianContext) {
            $toReturn = $Global:PowerAtlassian.Context
            if ($null -eq $toReturn) {
                throw "`$AtlassianContext was not provided when invoking a REST method"
            } else {
                return $toReturn
            }
        } else {
            return $AtlassianContext
        }
    }

    hidden
    static
    [object]
    RootInvoke(
        [hashtable]$splat
    ){
        $failCount = 0
        $callSuccess = $false
        $result = $null
        $maxRetries = $splat.MaximumRetryCount
        $retryDelay = $splat.RetryIntervalSec
        $splat.Remove("MaximumRetryCount")
        $splat.Remove("RetryIntervalSec")
        do {
            try {
                $result = Invoke-RestMethod @splat -ErrorAction "Stop"
                $callSuccess = $true
            } catch [System.Net.Http.HttpRequestException] {
                $failCount++
                if ($failCount -le $maxRetries) {
                    Write-Verbose "Error while invoking REST method; sleeping for $retryDelay seconds before re-attempting"
                    Start-Sleep -Seconds $retryDelay
                } else {
                    throw $_
                }
            }
        } while (!$callSuccess)
        return $result
    }

    ##################
    # PUBLIC METHODS #
    ##################

    [string]
    Uri(
        [AtlassianContext]$AtlassianContext
    ){
        $uri = $AtlassianContext.HostName + "/" + $this.FunctionPath
        if ($this.Query -and $this.Query.Params -and $this.Query.Params.Count -gt 0) {
            $uri += $this.Query.ToString()
        }
        return $uri
    }

    [hashtable]
    HeadersToSend(
        [AtlassianContext]$AtlassianContext
    ){
        #compile headers object
        $sendHeaders = @{}
        $sendHeaders += $AtlassianContext.AuthHeader
        $sendHeaders += $this.Headers
        return $sendHeaders
    }

    [object]
    Invoke(){
        return $this.Invoke($Global:PowerAtlassian.Context)
    }

    [object]
    Invoke(
        [AtlassianContext]$AtlassianContext
    ){
        $AtlassianContext = [RestMethod]::FillContext($AtlassianContext)
        $invokeSplat = @{
            Uri = $this.Uri($AtlassianContext)
            Method = $this.HttpMethod
            ContentType = $this.ContentType 
            Headers = $this.HeadersToSend($AtlassianContext) 
            MaximumRetryCount = $AtlassianContext.Retries
            RetryIntervalSec = $AtlassianContext.RetryDelay
        }
        return [RestMethod]::RootInvoke($invokeSplat)
    }
}