postman2openapi/postman/
mod.rs

1use serde::{Deserialize, Deserializer};
2
3extern crate serde_json;
4
5#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Default)]
6pub struct Spec {
7    #[serde(rename = "auth")]
8    pub auth: Option<Auth>,
9
10    #[serde(rename = "event")]
11    pub event: Option<Vec<Event>>,
12
13    #[serde(rename = "info")]
14    pub info: Information,
15
16    /// Items are the basic unit for a Postman collection. You can think of them as corresponding
17    /// to a single API endpoint. Each Item has one request and may have multiple API responses
18    /// associated with it.
19    #[serde(rename = "item")]
20    pub item: Vec<Items>,
21
22    #[serde(rename = "variable")]
23    pub variable: Option<Vec<Variable>>,
24}
25
26/// Represents authentication helpers provided by Postman
27#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
28pub struct Auth {
29    /// The attributes for [AWS
30    /// Auth](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html).
31    #[serde(rename = "awsv4")]
32    pub awsv4: Option<AuthAttributeUnion>,
33
34    /// The attributes for [Basic
35    /// Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication).
36    #[serde(rename = "basic")]
37    pub basic: Option<AuthAttributeUnion>,
38
39    /// The helper attributes for [Bearer Token
40    /// Authentication](https://tools.ietf.org/html/rfc6750)
41    #[serde(rename = "bearer")]
42    pub bearer: Option<AuthAttributeUnion>,
43
44    #[serde(rename = "jwt")]
45    pub jwt: Option<AuthAttributeUnion>,
46
47    /// The attributes for [Digest
48    /// Authentication](https://en.wikipedia.org/wiki/Digest_access_authentication).
49    #[serde(rename = "digest")]
50    pub digest: Option<AuthAttributeUnion>,
51
52    /// The attributes for [Hawk Authentication](https://github.com/hueniverse/hawk)
53    #[serde(rename = "hawk")]
54    pub hawk: Option<AuthAttributeUnion>,
55
56    #[serde(rename = "noauth")]
57    pub noauth: Option<serde_json::Value>,
58
59    /// The attributes for [NTLM
60    /// Authentication](https://msdn.microsoft.com/en-us/library/cc237488.aspx)
61    #[serde(rename = "ntlm")]
62    pub ntlm: Option<AuthAttributeUnion>,
63
64    /// The attributes for [Oauth2](https://oauth.net/1/)
65    #[serde(rename = "oauth1")]
66    pub oauth1: Option<AuthAttributeUnion>,
67
68    /// Helper attributes for [Oauth2](https://oauth.net/2/)
69    #[serde(rename = "oauth2")]
70    pub oauth2: Option<Oauth2>,
71
72    #[serde(rename = "apikey")]
73    pub apikey: Option<ApiKey>,
74
75    #[serde(rename = "type")]
76    pub auth_type: AuthType,
77}
78
79#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
80pub struct ApiKey {
81    pub key: Option<String>,
82    pub location: ApiKeyLocation,
83    pub value: Option<String>,
84}
85
86#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
87pub enum ApiKeyLocation {
88    Header,
89    Query,
90}
91
92impl<'de> Deserialize<'de> for ApiKey {
93    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
94    where
95        D: Deserializer<'de>,
96    {
97        let mut key = None;
98        let mut location = ApiKeyLocation::Header;
99        let mut value = None;
100
101        let deserialized = AuthAttributeUnion::deserialize(deserializer)?;
102        if let AuthAttributeUnion::AuthAttribute21(v) = deserialized {
103            for item in v {
104                if let Some(serde_json::Value::String(str)) = item.value {
105                    match item.key.as_str() {
106                        "key" => key = Some(str),
107                        "in" => {
108                            location = match str.as_str() {
109                                "query" => ApiKeyLocation::Query,
110                                "header" => ApiKeyLocation::Header,
111                                _ => ApiKeyLocation::Header,
112                            }
113                        }
114                        "value" => value = Some(str),
115                        _ => {}
116                    }
117                }
118            }
119        }
120        Ok(ApiKey {
121            key,
122            location,
123            value,
124        })
125    }
126}
127
128#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
129pub struct Oauth2 {
130    pub grant_type: Oauth2GrantType,
131    pub access_token_url: Option<String>,
132    pub add_token_to: Option<String>,
133    pub auth_url: Option<String>,
134    pub client_id: Option<String>,
135    pub client_secret: Option<String>,
136    pub refresh_token_url: Option<String>,
137    pub scope: Option<Vec<String>>,
138    pub state: Option<String>,
139    pub token_name: Option<String>,
140}
141
142impl<'de> Deserialize<'de> for Oauth2 {
143    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
144    where
145        D: Deserializer<'de>,
146    {
147        let mut grant_type = Oauth2GrantType::AuthorizationCode;
148        let mut access_token_url = None;
149        let mut add_token_to = None;
150        let mut auth_url = None;
151        let mut client_id = None;
152        let mut client_secret = None;
153        let mut refresh_token_url = None;
154        let mut scope = None;
155        let mut state = None;
156        let mut token_name = None;
157
158        let deserialized = AuthAttributeUnion::deserialize(deserializer)?;
159        if let AuthAttributeUnion::AuthAttribute21(v) = deserialized {
160            for item in v {
161                if let Some(serde_json::Value::String(str)) = item.value {
162                    match item.key.as_str() {
163                        "grantType" => {
164                            grant_type = match str.as_str() {
165                                "authorization_code" => Oauth2GrantType::AuthorizationCode,
166                                "authorization_code_with_pkce" => {
167                                    Oauth2GrantType::AuthorizationCodeWithPkce
168                                }
169                                "client_credentials" => Oauth2GrantType::ClientCredentials,
170                                "implicit" => Oauth2GrantType::Implicit,
171                                "password_credentials" => Oauth2GrantType::PasswordCredentials,
172                                _ => Oauth2GrantType::AuthorizationCode,
173                            }
174                        }
175                        "accessTokenUrl" => access_token_url = Some(str),
176                        "addTokenTo" => add_token_to = Some(str),
177                        "authUrl" => auth_url = Some(str),
178                        "clientId" => client_id = Some(str),
179                        "clientSecret" => client_secret = Some(str),
180                        "refreshTokenUrl" => refresh_token_url = Some(str),
181                        "scope" => scope = Some(str.split(' ').map(|s| s.to_string()).collect()),
182                        "state" => state = Some(str),
183                        "tokenName" => token_name = Some(str),
184                        _ => {}
185                    }
186                }
187            }
188        }
189        Ok(Oauth2 {
190            grant_type,
191            access_token_url,
192            add_token_to,
193            auth_url,
194            client_id,
195            client_secret,
196            refresh_token_url,
197            scope,
198            state,
199            token_name,
200        })
201    }
202}
203
204#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
205pub enum Oauth2GrantType {
206    AuthorizationCodeWithPkce,
207    ClientCredentials,
208    Implicit,
209    PasswordCredentials,
210    AuthorizationCode,
211}
212
213/// Represents an attribute for any authorization method provided by Postman. For example
214/// `username` and `password` are set as auth attributes for Basic Authentication method.
215#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
216pub struct AuthAttribute {
217    #[serde(rename = "key")]
218    pub key: String,
219
220    #[serde(rename = "type")]
221    pub auth_type: Option<String>,
222
223    #[serde(rename = "value")]
224    pub value: Option<serde_json::Value>,
225}
226
227#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
228#[serde(untagged)]
229pub enum AuthAttributeUnion {
230    AuthAttribute21(Vec<AuthAttribute>),
231    AuthAttribute20(Option<serde_json::Value>),
232}
233
234/// Postman allows you to configure scripts to run when specific events occur. These scripts
235/// are stored here, and can be referenced in the collection by their ID.
236///
237/// Defines a script associated with an associated event name
238#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
239pub struct Event {
240    /// Indicates whether the event is disabled. If absent, the event is assumed to be enabled.
241    #[serde(rename = "disabled")]
242    pub disabled: Option<bool>,
243
244    /// A unique identifier for the enclosing event.
245    #[serde(rename = "id")]
246    pub id: Option<String>,
247
248    /// Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.
249    #[serde(rename = "listen")]
250    pub listen: String,
251
252    #[serde(rename = "script")]
253    pub script: Option<Script>,
254}
255
256/// A script is a snippet of Javascript code that can be used to to perform setup or teardown
257/// operations on a particular response.
258#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
259pub struct Script {
260    #[serde(rename = "exec")]
261    pub exec: Option<Host>,
262
263    /// A unique, user defined identifier that can  be used to refer to this script from requests.
264    #[serde(rename = "id")]
265    pub id: Option<String>,
266
267    /// Script name
268    #[serde(rename = "name")]
269    pub name: Option<String>,
270
271    #[serde(rename = "src")]
272    pub src: Option<Url>,
273
274    /// Type of the script. E.g: 'text/javascript'
275    #[serde(rename = "type")]
276    pub script_type: Option<String>,
277}
278
279#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
280pub struct UrlClass {
281    /// Contains the URL fragment (if any). Usually this is not transmitted over the network, but
282    /// it could be useful to store this in some cases.
283    #[serde(rename = "hash")]
284    pub hash: Option<String>,
285
286    /// The host for the URL, E.g: api.yourdomain.com. Can be stored as a string or as an array
287    /// of strings.
288    #[serde(rename = "host")]
289    pub host: Option<Host>,
290
291    #[serde(rename = "path")]
292    pub path: Option<UrlPath>,
293
294    /// The port number present in this URL. An empty value implies 80/443 depending on whether
295    /// the protocol field contains http/https.
296    #[serde(rename = "port")]
297    pub port: Option<String>,
298
299    /// The protocol associated with the request, E.g: 'http'
300    #[serde(rename = "protocol")]
301    pub protocol: Option<String>,
302
303    /// An array of QueryParams, which is basically the query string part of the URL, parsed into
304    /// separate variables
305    #[serde(rename = "query")]
306    pub query: Option<Vec<QueryParam>>,
307
308    /// The string representation of the request URL, including the protocol, host, path, hash,
309    /// query parameter(s) and path variable(s).
310    #[serde(rename = "raw")]
311    pub raw: Option<String>,
312
313    /// Postman supports path variables with the syntax `/path/:variableName/to/somewhere`. These
314    /// variables are stored in this field.
315    #[serde(rename = "variable")]
316    pub variable: Option<Vec<Variable>>,
317}
318
319#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
320pub struct PathClass {
321    #[serde(rename = "type")]
322    pub path_type: Option<String>,
323
324    #[serde(rename = "value")]
325    pub value: Option<String>,
326}
327
328#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
329pub struct GraphQlBodyClass {
330    #[serde(rename = "query")]
331    pub query: Option<String>,
332
333    #[serde(rename = "variables")]
334    pub variables: Option<String>,
335}
336
337#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
338pub struct QueryParam {
339    #[serde(rename = "description")]
340    pub description: Option<DescriptionUnion>,
341
342    /// If set to true, the current query parameter will not be sent with the request.
343    #[serde(rename = "disabled")]
344    pub disabled: Option<bool>,
345
346    #[serde(rename = "key")]
347    pub key: Option<String>,
348
349    #[serde(rename = "value")]
350    pub value: Option<String>,
351}
352
353#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
354pub struct Description {
355    /// The content of the description goes here, as a raw string.
356    #[serde(rename = "content")]
357    pub content: Option<String>,
358
359    /// Holds the mime type of the raw description content. E.g: 'text/markdown' or 'text/html'.
360    /// The type is used to correctly render the description when generating documentation, or in
361    /// the Postman app.
362    #[serde(rename = "type")]
363    pub description_type: Option<String>,
364
365    /// Description can have versions associated with it, which should be put in this property.
366    #[serde(rename = "version")]
367    pub version: Option<serde_json::Value>,
368}
369
370/// Collection variables allow you to define a set of variables, that are a *part of the
371/// collection*, as opposed to environments, which are separate entities.
372/// *Note: Collection variables must not contain any sensitive information.*
373///
374/// Using variables in your Postman requests eliminates the need to duplicate requests, which
375/// can save a lot of time. Variables can be defined, and referenced to from any part of a
376/// request.
377#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
378pub struct Variable {
379    #[serde(rename = "description")]
380    pub description: Option<DescriptionUnion>,
381
382    #[serde(rename = "disabled")]
383    pub disabled: Option<bool>,
384
385    /// A variable ID is a unique user-defined value that identifies the variable within a
386    /// collection. In traditional terms, this would be a variable name.
387    #[serde(rename = "id")]
388    pub id: Option<String>,
389
390    /// A variable key is a human friendly value that identifies the variable within a
391    /// collection. In traditional terms, this would be a variable name.
392    #[serde(rename = "key")]
393    pub key: Option<String>,
394
395    /// Variable name
396    #[serde(rename = "name")]
397    pub name: Option<String>,
398
399    /// When set to true, indicates that this variable has been set by Postman
400    #[serde(rename = "system")]
401    pub system: Option<bool>,
402
403    /// A variable may have multiple types. This field specifies the type of the variable.
404    #[serde(rename = "type")]
405    pub variable_type: Option<VariableType>,
406
407    /// The value that a variable holds in this collection. Ultimately, the variables will be
408    /// replaced by this value, when say running a set of requests from a collection
409    #[serde(rename = "value")]
410    pub value: Option<serde_json::Value>,
411}
412
413/// Detailed description of the info block
414#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Default)]
415pub struct Information {
416    /// Every collection is identified by the unique value of this field. The value of this field
417    /// is usually easiest to generate using a UID generator function. If you already have a
418    /// collection, it is recommended that you maintain the same id since changing the id usually
419    /// implies that is a different collection than it was originally.
420    /// *Note: This field exists for compatibility reasons with Collection Format V1.*
421    #[serde(rename = "_postman_id")]
422    pub postman_id: Option<String>,
423
424    #[serde(rename = "_exporter_id")]
425    pub exporter_id: Option<String>,
426
427    #[serde(rename = "description")]
428    pub description: Option<DescriptionUnion>,
429
430    /// A collection's friendly name is defined by this field. You would want to set this field
431    /// to a value that would allow you to easily identify this collection among a bunch of other
432    /// collections, as such outlining its usage or content.
433    #[serde(rename = "name")]
434    pub name: String,
435
436    /// This should ideally hold a link to the Postman schema that is used to validate this
437    /// collection. E.g: https://schema.getpostman.com/collection/v1
438    #[serde(rename = "schema")]
439    pub schema: String,
440
441    #[serde(rename = "version")]
442    pub version: Option<CollectionVersion>,
443}
444
445#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
446pub struct CollectionVersionClass {
447    /// A human friendly identifier to make sense of the version numbers. E.g: 'beta-3'
448    #[serde(rename = "identifier")]
449    pub identifier: Option<String>,
450
451    /// Increment this number if you make changes to the collection that changes its behaviour.
452    /// E.g: Removing or adding new test scripts. (partly or completely).
453    #[serde(rename = "major")]
454    pub major: i64,
455
456    #[serde(rename = "meta")]
457    pub meta: Option<serde_json::Value>,
458
459    /// You should increment this number if you make changes that will not break anything that
460    /// uses the collection. E.g: removing a folder.
461    #[serde(rename = "minor")]
462    pub minor: i64,
463
464    /// Ideally, minor changes to a collection should result in the increment of this number.
465    #[serde(rename = "patch")]
466    pub patch: i64,
467}
468
469/// Items are entities which contain an actual HTTP request, and sample responses attached to
470/// it.
471///
472/// One of the primary goals of Postman is to organize the development of APIs. To this end,
473/// it is necessary to be able to group requests together. This can be achived using
474/// 'Folders'. A folder just is an ordered set of requests.
475#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
476pub struct Items {
477    #[serde(rename = "description")]
478    pub description: Option<DescriptionUnion>,
479
480    #[serde(rename = "event")]
481    pub event: Option<Vec<Event>>,
482
483    /// A unique ID that is used to identify collections internally
484    #[serde(rename = "id")]
485    pub id: Option<String>,
486
487    /// A human readable identifier for the current item.
488    ///
489    /// A folder's friendly name is defined by this field. You would want to set this field to a
490    /// value that would allow you to easily identify this folder.
491    #[serde(rename = "name")]
492    pub name: Option<String>,
493
494    /// Set of configurations used to alter the usual behavior of sending the request
495    #[serde(rename = "protocolProfileBehavior")]
496    pub protocol_profile_behavior: Option<ProtocolProfileBehavior>,
497
498    #[serde(rename = "request")]
499    pub request: Option<RequestUnion>,
500
501    #[serde(rename = "response")]
502    pub response: Option<Vec<Option<ResponseClass>>>,
503
504    #[serde(rename = "variable")]
505    pub variable: Option<Vec<Variable>>,
506
507    #[serde(rename = "auth")]
508    pub auth: Option<Auth>,
509
510    /// Items are entities which contain an actual HTTP request, and sample responses attached to
511    /// it. Folders may contain many items.
512    #[serde(rename = "item")]
513    pub item: Option<Vec<Items>>,
514}
515
516/// Set of configurations used to alter the usual behavior of sending the request
517#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
518pub struct ProtocolProfileBehavior {
519    /// Disable body pruning for GET, COPY, HEAD, PURGE and UNLOCK request methods.
520    #[serde(rename = "disableBodyPruning")]
521    pub disable_body_pruning: Option<bool>,
522}
523
524#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
525pub struct RequestClass {
526    #[serde(rename = "auth")]
527    pub auth: Option<Auth>,
528
529    #[serde(rename = "body")]
530    pub body: Option<Body>,
531
532    #[serde(rename = "certificate")]
533    pub certificate: Option<Certificate>,
534
535    #[serde(rename = "description")]
536    pub description: Option<DescriptionUnion>,
537
538    #[serde(rename = "header")]
539    pub header: Option<HeaderUnion>,
540
541    #[serde(rename = "method")]
542    pub method: Option<String>,
543
544    #[serde(rename = "proxy")]
545    pub proxy: Option<ProxyConfig>,
546
547    #[serde(rename = "url")]
548    pub url: Option<Url>,
549}
550
551/// This field contains the data usually contained in the request body.
552#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
553pub struct Body {
554    /// When set to true, prevents request body from being sent.
555    #[serde(rename = "disabled")]
556    pub disabled: Option<bool>,
557
558    #[serde(rename = "file")]
559    pub file: Option<File>,
560
561    #[serde(rename = "formdata")]
562    pub formdata: Option<Vec<FormParameter>>,
563
564    /// Postman stores the type of data associated with this request in this field.
565    #[serde(rename = "mode")]
566    pub mode: Option<Mode>,
567
568    #[serde(rename = "raw")]
569    pub raw: Option<String>,
570
571    #[serde(rename = "options")]
572    pub options: Option<BodyOptions>,
573
574    #[serde(rename = "urlencoded")]
575    pub urlencoded: Option<Vec<UrlEncodedParameter>>,
576
577    #[serde(rename = "graphql")]
578    pub graphql: Option<GraphQlBody>,
579}
580
581#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
582pub struct BodyOptions {
583    #[serde(rename = "raw")]
584    pub raw: Option<RawOptions>,
585}
586
587#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
588pub struct RawOptions {
589    #[serde(rename = "language")]
590    pub language: Option<String>,
591}
592
593#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
594pub struct File {
595    #[serde(rename = "content")]
596    pub content: Option<String>,
597
598    #[serde(rename = "src")]
599    pub src: Option<String>,
600}
601
602#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
603pub struct FormParameter {
604    /// Override Content-Type header of this form data entity.
605    #[serde(rename = "contentType")]
606    pub content_type: Option<String>,
607
608    #[serde(rename = "description")]
609    pub description: Option<DescriptionUnion>,
610
611    /// When set to true, prevents this form data entity from being sent.
612    #[serde(rename = "disabled")]
613    pub disabled: Option<bool>,
614
615    #[serde(rename = "key")]
616    pub key: String,
617
618    #[serde(rename = "type")]
619    pub form_parameter_type: Option<String>,
620
621    #[serde(rename = "value")]
622    pub value: Option<String>,
623}
624
625#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
626pub struct UrlEncodedParameter {
627    #[serde(rename = "description")]
628    pub description: Option<DescriptionUnion>,
629
630    #[serde(rename = "disabled")]
631    pub disabled: Option<bool>,
632
633    #[serde(rename = "key")]
634    pub key: String,
635
636    #[serde(rename = "value")]
637    pub value: Option<String>,
638}
639
640/// A representation of an ssl certificate
641#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
642pub struct Certificate {
643    /// An object containing path to file certificate, on the file system
644    #[serde(rename = "cert")]
645    pub cert: Option<Cert>,
646
647    /// An object containing path to file containing private key, on the file system
648    #[serde(rename = "key")]
649    pub key: Option<Key>,
650
651    /// A list of Url match pattern strings, to identify Urls this certificate can be used for.
652    #[serde(rename = "matches")]
653    pub matches: Option<Vec<Option<serde_json::Value>>>,
654
655    /// A name for the certificate for user reference
656    #[serde(rename = "name")]
657    pub name: Option<String>,
658
659    /// The passphrase for the certificate
660    #[serde(rename = "passphrase")]
661    pub passphrase: Option<String>,
662}
663
664/// An object containing path to file certificate, on the file system
665#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
666pub struct Cert {
667    /// The path to file containing key for certificate, on the file system
668    #[serde(rename = "src")]
669    pub src: Option<serde_json::Value>,
670}
671
672/// An object containing path to file containing private key, on the file system
673#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
674pub struct Key {
675    /// The path to file containing key for certificate, on the file system
676    #[serde(rename = "src")]
677    pub src: Option<serde_json::Value>,
678}
679
680/// A representation for a list of headers
681///
682/// Represents a single HTTP Header
683#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
684pub struct Header {
685    #[serde(rename = "description", default)]
686    pub description: Option<DescriptionUnion>,
687
688    /// If set to true, the current header will not be sent with requests.
689    #[serde(rename = "disabled", default)]
690    pub disabled: Option<bool>,
691
692    /// This holds the LHS of the HTTP Header, e.g ``Content-Type`` or ``X-Custom-Header``
693    #[serde(rename = "key", default)]
694    pub key: Option<String>,
695
696    /// The value (or the RHS) of the Header is stored in this field.
697    #[serde(rename = "value", deserialize_with = "deserialize_as_string", default)]
698    pub value: Option<String>,
699}
700
701struct DeserializeAnyAsString;
702impl<'de> serde::de::Visitor<'de> for DeserializeAnyAsString {
703    type Value = Option<String>;
704    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
705        formatter.write_str("missing, null, an integer, or a string")
706    }
707
708    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
709    where
710        E: serde::de::Error,
711    {
712        Ok(Some(v.to_string()))
713    }
714
715    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> {
716        Ok(Some(v.to_string()))
717    }
718
719    fn visit_string<E>(self, v: String) -> Result<Self::Value, E> {
720        Ok(Some(v))
721    }
722
723    fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
724    where
725        E: serde::de::Error,
726    {
727        Ok(Some(v.to_string()))
728    }
729
730    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
731    where
732        E: serde::de::Error,
733    {
734        Ok(Some(v.to_string()))
735    }
736
737    fn visit_none<E>(self) -> Result<Self::Value, E>
738    where
739        E: serde::de::Error,
740    {
741        Ok(None)
742    }
743}
744
745fn deserialize_as_string<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
746where
747    D: Deserializer<'de>,
748{
749    deserializer.deserialize_any(DeserializeAnyAsString)
750}
751
752/// Using the Proxy, you can configure your custom proxy into the postman for particular url
753/// match
754#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
755pub struct ProxyConfig {
756    /// When set to true, ignores this proxy configuration entity
757    #[serde(rename = "disabled")]
758    pub disabled: Option<bool>,
759
760    /// The proxy server host
761    #[serde(rename = "host")]
762    pub host: Option<String>,
763
764    /// The Url match for which the proxy config is defined
765    #[serde(rename = "match")]
766    pub proxy_config_match: Option<String>,
767
768    /// The proxy server port
769    #[serde(rename = "port")]
770    pub port: Option<i64>,
771
772    /// The tunneling details for the proxy config
773    #[serde(rename = "tunnel")]
774    pub tunnel: Option<bool>,
775}
776
777#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
778pub struct ResponseClass {
779    /// The name of the response.
780    #[serde(rename = "name")]
781    pub name: Option<String>,
782
783    /// The raw text of the response.
784    #[serde(rename = "body")]
785    pub body: Option<String>,
786
787    /// The numerical response code, example: 200, 201, 404, etc.
788    #[serde(rename = "code")]
789    pub code: Option<i64>,
790
791    #[serde(rename = "cookie")]
792    pub cookie: Option<Vec<Cookie>>,
793
794    #[serde(rename = "header")]
795    pub header: Option<Headers>,
796
797    /// A unique, user defined identifier that can  be used to refer to this response from
798    /// requests.
799    #[serde(rename = "id")]
800    pub id: Option<String>,
801
802    #[serde(rename = "originalRequest")]
803    pub original_request: Option<RequestClass>,
804
805    /// The time taken by the request to complete. If a number, the unit is milliseconds. If the
806    /// response is manually created, this can be set to `null`.
807    #[serde(rename = "responseTime")]
808    pub response_time: Option<ResponseTime>,
809
810    /// The response status, e.g: '200 OK'
811    #[serde(rename = "status")]
812    pub status: Option<String>,
813}
814
815/// A Cookie, that follows the [Google Chrome
816/// format](https://developer.chrome.com/extensions/cookies)
817#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
818pub struct Cookie {
819    /// The domain for which this cookie is valid.
820    #[serde(rename = "domain")]
821    pub domain: Option<String>,
822
823    /// When the cookie expires.
824    #[serde(rename = "expires")]
825    pub expires: Option<String>,
826
827    /// Custom attributes for a cookie go here, such as the [Priority
828    /// Field](https://code.google.com/p/chromium/issues/detail?id=232693)
829    #[serde(rename = "extensions")]
830    pub extensions: Option<Vec<Option<serde_json::Value>>>,
831
832    /// True if the cookie is a host-only cookie. (i.e. a request's URL domain must exactly match
833    /// the domain of the cookie).
834    #[serde(rename = "hostOnly")]
835    pub host_only: Option<bool>,
836
837    /// Indicates if this cookie is HTTP Only. (if True, the cookie is inaccessible to
838    /// client-side scripts)
839    #[serde(rename = "httpOnly")]
840    pub http_only: Option<bool>,
841
842    #[serde(rename = "maxAge")]
843    pub max_age: Option<String>,
844
845    /// This is the name of the Cookie.
846    #[serde(rename = "name")]
847    pub name: Option<String>,
848
849    /// The path associated with the Cookie.
850    #[serde(rename = "path")]
851    pub path: Option<String>,
852
853    /// Indicates if the 'secure' flag is set on the Cookie, meaning that it is transmitted over
854    /// secure connections only. (typically HTTPS)
855    #[serde(rename = "secure")]
856    pub secure: Option<bool>,
857
858    /// True if the cookie is a session cookie.
859    #[serde(rename = "session")]
860    pub session: Option<bool>,
861
862    /// The value of the Cookie.
863    #[serde(rename = "value")]
864    pub value: Option<String>,
865}
866
867/// The host for the URL, E.g: api.yourdomain.com. Can be stored as a string or as an array
868/// of strings.
869#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
870#[serde(untagged)]
871pub enum Host {
872    String(String),
873
874    StringArray(Vec<String>),
875}
876
877/// If object, contains the complete broken-down URL for this request. If string, contains
878/// the literal request URL.
879#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
880#[serde(untagged)]
881pub enum Url {
882    String(String),
883
884    UrlClass(UrlClass),
885}
886
887#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
888#[serde(untagged)]
889pub enum UrlPath {
890    String(String),
891
892    UnionArray(Vec<PathElement>),
893}
894
895/// The complete path of the current url, broken down into segments. A segment could be a
896/// string, or a path variable.
897#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
898#[serde(untagged)]
899pub enum PathElement {
900    PathClass(PathClass),
901
902    String(String),
903}
904
905/// A Description can be a raw text, or be an object, which holds the description along with
906/// its format.
907#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
908#[serde(untagged)]
909pub enum DescriptionUnion {
910    Description(Description),
911
912    String(String),
913}
914
915/// Postman allows you to version your collections as they grow, and this field holds the
916/// version number. While optional, it is recommended that you use this field to its fullest
917/// extent!
918#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
919#[serde(untagged)]
920pub enum CollectionVersion {
921    CollectionVersionClass(CollectionVersionClass),
922
923    String(String),
924}
925
926/// A request represents an HTTP request. If a string, the string is assumed to be the
927/// request URL and the method is assumed to be 'GET'.
928#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
929#[serde(untagged)]
930pub enum RequestUnion {
931    RequestClass(Box<RequestClass>),
932
933    String(String),
934}
935
936#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
937#[serde(untagged)]
938pub enum HeaderUnion {
939    HeaderArray(Vec<Header>),
940
941    String(String),
942}
943
944/// A response represents an HTTP response.
945#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
946#[serde(untagged)]
947pub enum Response {
948    //AnythingArray(Vec<Option<serde_json::Value>>),
949
950    //Bool(bool),
951
952    //Double(f64),
953
954    //Integer(i64),
955    ResponseClass(Box<ResponseClass>),
956
957    String(String),
958}
959
960#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
961#[serde(untagged)]
962pub enum Headers {
963    String(String),
964
965    UnionArray(Vec<HeaderElement>),
966}
967
968/// No HTTP request is complete without its headers, and the same is true for a Postman
969/// request. This field is an array containing all the headers.
970#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
971#[serde(untagged)]
972pub enum HeaderElement {
973    Header(Header),
974
975    String(String),
976}
977
978/// The time taken by the request to complete. If a number, the unit is milliseconds. If the
979/// response is manually created, this can be set to `null`.
980#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
981#[serde(untagged)]
982pub enum ResponseTime {
983    Number(u64),
984
985    String(String),
986}
987
988#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
989#[serde(untagged)]
990pub enum GraphQlBody {
991    String(String),
992
993    GraphQlBodyClass(GraphQlBodyClass),
994}
995
996#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
997pub enum AuthType {
998    #[serde(rename = "awsv4")]
999    Awsv4,
1000
1001    #[serde(rename = "basic")]
1002    Basic,
1003
1004    #[serde(rename = "bearer")]
1005    Bearer,
1006
1007    #[serde(rename = "digest")]
1008    Digest,
1009
1010    #[serde(rename = "jwt")]
1011    Jwt,
1012
1013    #[serde(rename = "hawk")]
1014    Hawk,
1015
1016    #[serde(rename = "noauth")]
1017    Noauth,
1018
1019    #[serde(rename = "ntlm")]
1020    Ntlm,
1021
1022    #[serde(rename = "oauth1")]
1023    Oauth1,
1024
1025    #[serde(rename = "oauth2")]
1026    Oauth2,
1027
1028    #[serde(rename = "apikey")]
1029    Apikey,
1030}
1031
1032/// Returns `Noauth` for AuthType by default
1033impl Default for AuthType {
1034    fn default() -> AuthType {
1035        AuthType::Noauth
1036    }
1037}
1038
1039/// A variable may have multiple types. This field specifies the type of the variable.
1040#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
1041pub enum VariableType {
1042    #[serde(rename = "any")]
1043    Any,
1044
1045    #[serde(rename = "boolean")]
1046    Boolean,
1047
1048    #[serde(rename = "number")]
1049    Number,
1050
1051    #[serde(rename = "string")]
1052    String,
1053}
1054
1055/// Postman stores the type of data associated with this request in this field.
1056#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
1057pub enum Mode {
1058    #[serde(rename = "file")]
1059    File,
1060
1061    #[serde(rename = "formdata")]
1062    Formdata,
1063
1064    #[serde(rename = "raw")]
1065    Raw,
1066
1067    #[serde(rename = "urlencoded")]
1068    Urlencoded,
1069
1070    #[serde(rename = "graphql")]
1071    GraphQl,
1072}
1073
1074#[cfg(not(target_arch = "wasm32"))]
1075#[cfg(test)]
1076mod tests {
1077    use super::*;
1078
1079    #[test]
1080    fn deserializes_oauth2() {
1081        let spec: Spec =
1082            serde_json::from_str(get_fixture("oauth2-code.postman.json").as_ref()).unwrap();
1083        let oauth2 = spec.auth.unwrap().oauth2.unwrap();
1084
1085        assert_eq!(oauth2.grant_type, Oauth2GrantType::AuthorizationCode);
1086        assert_eq!(
1087            oauth2.auth_url,
1088            Some("https://example.com/oauth2/authorization".to_string())
1089        );
1090        assert_eq!(
1091            oauth2.access_token_url,
1092            Some("https://example.com/oauth2/token".to_string())
1093        );
1094    }
1095
1096    #[test]
1097    fn deserializes_apikey() {
1098        let spec: Spec =
1099            serde_json::from_str(get_fixture("api-key.postman.json").as_ref()).unwrap();
1100        let apikey = spec.auth.unwrap().apikey.unwrap();
1101
1102        assert_eq!(apikey.key, Some("Authorization".to_string()));
1103        assert_eq!(apikey.location, ApiKeyLocation::Header);
1104        assert_eq!(apikey.value, None);
1105    }
1106
1107    fn get_fixture(filename: &str) -> String {
1108        use std::fs;
1109
1110        let filename: std::path::PathBuf =
1111            [env!("CARGO_MANIFEST_DIR"), "./tests/fixtures/", filename]
1112                .iter()
1113                .collect();
1114        let file = filename.into_os_string().into_string().unwrap();
1115        fs::read_to_string(file).unwrap()
1116    }
1117}