Skip to content
/ opg Public
forked from Rexagon/opg

Rust OpenAPI 3.0 docs generator

License

Notifications You must be signed in to change notification settings

MrWad3r/opg

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

83 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

opg

Rust OpenAPI 3.0 docs generator

GitHub GitHub Workflow Status Crates.io Version Docs.rs

Example:

Or see more here

use opg::*;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, OpgModel)]
#[serde(rename_all = "camelCase")]
#[opg("Simple enum")]
enum SimpleEnum {
    Test,
    Another,
    Yay,
}

#[derive(Serialize, Deserialize, OpgModel)]
#[opg("newtype string", format = "id", example = "abcd0001")]
struct NewType(String);

#[derive(Serialize, Deserialize, OpgModel)]
struct SimpleStruct {
    first_field: i32,
    #[opg("Field description")]
    second: String,
}

#[derive(Serialize, Deserialize, OpgModel)]
#[serde(rename_all = "kebab-case")]
enum ExternallyTaggedEnum {
    Test(String),
    AnotherTest(String, #[opg("Second")] String),
}

#[derive(Serialize, Deserialize, OpgModel)]
#[serde(untagged)]
enum UntaggedEnum {
    First {
        value: NewType,
    },
    #[opg("Variant description")]
    Second {
        #[opg("Inlined struct", inline)]
        another: SimpleStruct,
    },
}

#[derive(Serialize, Deserialize, OpgModel)]
#[serde(tag = "tag", rename_all = "lowercase")]
enum InternallyTaggedEnum {
    First(SimpleStruct),
    Second { field: String },
}

#[derive(Serialize, Deserialize, OpgModel)]
#[serde(tag = "tag", content = "content", rename_all = "lowercase")]
enum AdjacentlyTaggedEnum {
    First(String),
    Second(NewType, NewType),
}

#[derive(Serialize, Deserialize, OpgModel)]
#[serde(rename_all = "camelCase")]
struct TypeChangedStruct {
    #[serde(with = "chrono::naive::serde::ts_milliseconds")]
    #[opg("UTC timestamp in milliseconds", integer, format = "int64")]
    pub timestamp: chrono::NaiveDateTime,
}

#[derive(Serialize, Deserialize, OpgModel)]
struct StructWithComplexObjects {
    #[serde(skip_serializing_if = "Option::is_none")]
    #[opg(optional)]
    super_optional: Option<Option<String>>,
    field: Option<String>,
    boxed: Box<Option<i32>>,
}

#[derive(Serialize, OpgModel)]
struct GenericStructWithRef<'a, T> {
    message: &'a str,
    test: T,
}

#[derive(Serialize, OpgModel)]
struct SuperResponse {
    simple_enum: SimpleEnum,
    #[serde(rename = "new_type")]
    newtype: NewType,
    externally_tagged_enum: ExternallyTaggedEnum,
    untagged_enum: UntaggedEnum,
    internally_tagged_enum: InternallyTaggedEnum,
    adjacently_tagged_enum: AdjacentlyTaggedEnum,
    type_changed_struct: TypeChangedStruct,
    struct_with_complex_objects: StructWithComplexObjects,
}

#[test]
fn print_api() {
    let test = describe_api! {
        info: {
            title: "My super API",
            version: "0.0.0",
        },
        tags: {internal, admin("Super admin methods")},
        servers: {
            "https://my.super.server.com/v1",
        },
        security_schemes: {
            (http "bearerAuth"): {
                scheme: Bearer,
                bearer_format: "JWT",
            },
        },
        paths: {
            ("hello" / "world" / { paramTest: String }): {
                summary: "Some test group of requests",
                description: "Another test description",
                parameters: {
                    (header "x-request-id"): {
                        description: "Test",
                        required: true,
                    },
                },
                GET: {
                    tags: {internal},
                    summary: "Small summary",
                    description: "Small description",
                    deprecated: true,
                    parameters: {
                        (query someParam: u32): {
                            description: "Test",
                        }
                    },
                    200: String,
                    418 ("Optional response description"): String
                },
                POST: {
                    tags: {admin},
                    security: {"bearerAuth"},
                    body: {
                        description: "Some interesting description",
                        schema: GenericStructWithRef<'static, i64>,
                        required: true,
                    },
                    200: SuperResponse,
                    callbacks: {
                        callbackUrl: {
                            ("callbackUrl"): {
                                POST: {
                                    200: std::vec::Vec<String>,
                                }
                            }
                        }
                    }
                }
            }
        }
    };

    println!("{}", serde_yaml::to_string(&test).unwrap());
}
Result:

---
openapi: 3.0.3
info:
  title: My super API
  version: 0.0.0
tags:
  - name: admin
    description: Super admin methods
  - name: internal
servers:
  - url: "https://my.super.server.com/v1"
paths:
  "/hello/world/{paramTest}":
    summary: Some test group of requests
    description: Another test description
    get:
      tags:
        - internal
      summary: Small summary
      description: Small description
      deprecated: true
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: string
        418:
          description: Optional response description
          content:
            application/json:
              schema:
                type: string
      parameters:
        - name: someParam
          description: Test
          in: query
          schema:
            type: integer
            format: uint32
    post:
      tags:
        - admin
      security:
        - bearerAuth: []
      requestBody:
        required: true
        description: Some interesting description
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GenericStructWithRef"
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuperResponse"
      callbacks:
        callbackUrl:
          /callbackUrl:
            post:
              responses:
                200:
                  description: OK
                  content:
                    application/json:
                      schema:
                        type: array
                        items:
                          type: string
    parameters:
      - name: paramTest
        in: path
        required: true
        schema:
          type: string
      - name: x-request-id
        description: Test
        in: header
        required: true
        schema:
          type: string
components:
  schemas:
    AdjacentlyTaggedEnum:
      type: object
      properties:
        content:
          oneOf:
            - type: string
            - type: array
              items:
                oneOf:
                  - $ref: "#/components/schemas/NewType"
                  - $ref: "#/components/schemas/NewType"
        tag:
          description: AdjacentlyTaggedEnum type variant
          type: string
          enum:
            - first
            - second
          example: first
      required:
        - tag
        - content
    ExternallyTaggedEnum:
      type: object
      additionalProperties:
        oneOf:
          - type: string
          - type: array
            items:
              oneOf:
                - type: string
                - description: Second
                  type: string
    GenericStructWithRef:
      type: object
      properties:
        message:
          type: string
        test:
          type: integer
          format: int64
      required:
        - message
        - test
    InternallyTaggedEnum:
      oneOf:
        - type: object
          properties:
            first_field:
              type: integer
              format: int32
            second:
              description: Field description
              type: string
            tag:
              description: InternallyTaggedEnum type variant
              type: string
              enum:
                - first
              example: first
          required:
            - first_field
            - second
            - tag
        - type: object
          properties:
            field:
              type: string
            tag:
              description: InternallyTaggedEnum type variant
              type: string
              enum:
                - second
              example: second
          required:
            - field
            - tag
    NewType:
      description: newtype string
      type: string
      format: id
      example: abcd0001
    SimpleEnum:
      description: Simple enum
      type: string
      enum:
        - test
        - another
        - yay
      example: test
    StructWithComplexObjects:
      type: object
      properties:
        boxed:
          nullable: true
          type: integer
          format: int32
        field:
          nullable: true
          type: string
        super_optional:
          nullable: true
          type: string
      required:
        - field
        - boxed
    SuperResponse:
      type: object
      properties:
        adjacently_tagged_enum:
          $ref: "#/components/schemas/AdjacentlyTaggedEnum"
        externally_tagged_enum:
          $ref: "#/components/schemas/ExternallyTaggedEnum"
        internally_tagged_enum:
          $ref: "#/components/schemas/InternallyTaggedEnum"
        new_type:
          $ref: "#/components/schemas/NewType"
        simple_enum:
          $ref: "#/components/schemas/SimpleEnum"
        struct_with_complex_objects:
          $ref: "#/components/schemas/StructWithComplexObjects"
        type_changed_struct:
          $ref: "#/components/schemas/TypeChangedStruct"
        untagged_enum:
          $ref: "#/components/schemas/UntaggedEnum"
      required:
        - simple_enum
        - new_type
        - externally_tagged_enum
        - untagged_enum
        - internally_tagged_enum
        - adjacently_tagged_enum
        - type_changed_struct
        - struct_with_complex_objects
    TypeChangedStruct:
      type: object
      properties:
        timestamp:
          description: UTC timestamp in milliseconds
          type: integer
          format: int64
      required:
        - timestamp
    UntaggedEnum:
      oneOf:
        - type: object
          properties:
            value:
              $ref: "#/components/schemas/NewType"
          required:
            - value
        - description: Variant description
          type: object
          properties:
            another:
              description: Inlined struct
              type: object
              properties:
                first_field:
                  type: integer
                  format: int32
                second:
                  description: Field description
                  type: string
              required:
                - first_field
                - second
          required:
            - another
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

About

Rust OpenAPI 3.0 docs generator

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Rust 100.0%