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

librematch/opg

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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%