Search code examples
jsonresthttpswaggerswagger-ui

How can I describe a nameless query parameter with Swagger?


I have an API endpoint that responds to POST requests with a query parameter of the form:

json_string = '{"items":%20[{"name":%20"chicken",%20"quantity":%201,%20"basePrice":%20499,%20"priceWithModifiers":%20499},%20{"name":%20"soda",%20"quantity":%201,%20"basePrice":%20399,%20"priceWithModifiers":%20399}],%20"salesTax":%20{"id":%20"T8JKFEVBE6F30",%20"name":%20"Sales%20Tax",%20"rate":%20900000,%20"isDefault":%20true},%20"orderType":%20{"id":%20"ZJQ5ND5FZAAVP",%20"taxable":%20true,%20"isDefault":%20true,%20"filterCategories":%20false,%20"isHidden":%20false,%20"hoursAvailable":%20"BUSINESS",%20"isDeleted":%20false}}'

So, the complete url is "endpoint/?{json_string}". I have tried to use content -> application/json -> schema to describe the parameter as a string, but since I must give the parameter a name, there will always be an unwanted "=" somewhere in the query parameter. I do not want to rewrite the api itself.

You can create a similar string in Javascript with

const my_dict = {"items": [5,6,7], "SalesTax": {"id": "foobar"}, "orderType": {"id": "Takeout"}}

query_param = JSON.stringify(my_dict)

or in Python

import json
my_dict = {"items": [5,6,7], "SalesTax": {"id": "foobar"}, "orderType": {"id": "Takeout"}}
query_param = json.dumps(my_dict)

Solution

  • Is there a reason you wouldn't use a POST with a request body? What's the purpose of maintaining the json string in the query? The url is character limited to 2048. If your json string grows past this number, you'll have much bigger problems. The other advantage is you don't need to encode a request body.

    POST /endpoint HTTP/1.1
    content-type: application/json
    
    {
        "items": [
            {
                "name": "chicken",
                "quantity": 1,
                "basePrice": 499,
                "priceWithModifiers": 499
            },
            {
                "name": "soda",
                "quantity": 1,
                "basePrice": 399,
                "priceWithModifiers": 399
            }
        ],
        "salesTax": {
            "id": "T8JKFEVBE6F30",
            "name": "Sales Tax",
            "rate": 900000,
            "isDefault": true
        },
        "orderType": {
            "id": "ZJQ5ND5FZAAVP",
            "taxable": true,
            "isDefault": true,
            "filterCategories": false,
            "isHidden": false,
            "hoursAvailable": "BUSINESS",
            "isDeleted": false
        }
    }
    
    

    This is defined as a JSON Schema as follows:

    {
        "$id": "itemWithPricing",
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "type": "object",
        "properties": {
            "items": {
                "type": "array",
                "uniqueItems": true,
                "items": {
                    "type": "object",
                    "properties": {
                        "name": {
                            "type": "string"
                        },
                        "quantity": {
                            "type": "number"
                        },
                        "basePrice": {
                            "type": "number"
                        },
                        "priceWithModifiers": {
                            "type": "number"
                        }
                    }
                }
            },
            "salesTax": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    },
                    "rate": {
                        "type": "number"
                    },
                    "isDefault": {
                        "type": "boolean"
                    }
                }
            },
            "orderType": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "taxable": {
                        "type": "boolean"
                    },
                    "isDefault": {
                        "type": "boolean"
                    },
                    "filterCategories": {
                        "type": "boolean"
                    },
                    "isHidden": {
                        "type": "boolean"
                    },
                    "hoursAvailable": {
                        "type": "string"
                    },
                    "isDeleted": {
                        "type": "boolean"
                    }
                }
            }
        }
    }
    

    Then you can use it in your OpenAPI description

    {
        "openapi": "3.1.0",
        "info": {},
        "servers": [],
        "paths": {
            "/endpoint": {
                "post": {
                    "summary": "create a new item with pricing",
                    "parameters": [],
                    "requestBody": {
                        "$ref": "#/components/requestBodies/itemsWithPricing"
                    },
                    "responses": {
                        "201": {
                            "description": "Created",
                            "headers": {
                                "location": {
                                    "schema": {
                                        "type": "string"
                                    }
                                }
                            },
                            "content": {
                                "application/json": {
                                    "schema": {}
                                }
                            }
                        }
                    }
                }
            }
        },
        "components": {
            "schemas": {
                "itemsWithPricing": {
                    "$id": "itemWithPricing",
                    "$schema": "https://json-schema.org/draft/2020-12/schema",
                    "type": "object",
                    "properties": {
                        "items": {
                            "type": "array",
                            "uniqueItems": true,
                            "items": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string"
                                    },
                                    "quantity": {
                                        "type": "number"
                                    },
                                    "basePrice": {
                                        "type": "number"
                                    },
                                    "priceWithModifiers": {
                                        "type": "number"
                                    }
                                }
                            }
                        },
                        "salesTax": {
                            "type": "object",
                            "properties": {
                                "id": {
                                    "type": "string"
                                },
                                "name": {
                                    "type": "string"
                                },
                                "rate": {
                                    "type": "number"
                                },
                                "isDefault": {
                                    "type": "boolean"
                                }
                            }
                        },
                        "orderType": {
                            "type": "object",
                            "properties": {
                                "id": {
                                    "type": "string"
                                },
                                "taxable": {
                                    "type": "boolean"
                                },
                                "isDefault": {
                                    "type": "boolean"
                                },
                                "filterCategories": {
                                    "type": "boolean"
                                },
                                "isHidden": {
                                    "type": "boolean"
                                },
                                "hoursAvailable": {
                                    "type": "string"
                                },
                                "isDeleted": {
                                    "type": "boolean"
                                }
                            }
                        }
                    }
                }
            },
            "requestBodies": {
                "itemsWithPricing": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/itemsWithPricing"
                            }
                        }
                    },
                    "required": true
                }
            }
        }
    }