github Effect-TS/effect @effect/platform@0.72.2

Patch Changes

  • #4226 212e784 Thanks @gcanti! - Ensure the encoding kind of success responses is respected in the OpenAPI spec.

    Before

    When generating an OpenAPI spec for a request with a success schema of type `HttpApiSchema.Text()``, the response content type was incorrectly set to "application/json" instead of "text/plain".

    import {
      HttpApi,
      HttpApiEndpoint,
      HttpApiGroup,
      HttpApiSchema,
      OpenApi
    } from "@effect/platform"
    
    const api = HttpApi.make("api").add(
      HttpApiGroup.make("group").add(
        HttpApiEndpoint.get("get", "/").addSuccess(HttpApiSchema.Text())
      )
    )
    
    const spec = OpenApi.fromApi(api)
    
    console.log(JSON.stringify(spec.paths, null, 2))
    /*
    Output:
    {
      "/": {
        "get": {
          "tags": [
            "group"
          ],
          "operationId": "group.get",
          "parameters": [],
          "security": [],
          "responses": {
            "200": {
              "description": "a string",
              "content": {
                "application/json": {
                  "schema": {
                    "type": "string"
                  }
                }
              }
            },
            "400": {
              "description": "The request did not match the expected schema",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/HttpApiDecodeError"
                  }
                }
              }
            }
          }
        }
      }
    }
    */

    After

    import {
      HttpApi,
      HttpApiEndpoint,
      HttpApiGroup,
      HttpApiSchema,
      OpenApi
    } from "@effect/platform"
    
    const api = HttpApi.make("api").add(
      HttpApiGroup.make("group").add(
        HttpApiEndpoint.get("get", "/").addSuccess(HttpApiSchema.Text())
      )
    )
    
    const spec = OpenApi.fromApi(api)
    
    console.log(JSON.stringify(spec.paths, null, 2))
    /*
    Output:
    {
      "/": {
        "get": {
          "tags": [
            "group"
          ],
          "operationId": "group.get",
          "parameters": [],
          "security": [],
          "responses": {
            "200": {
              "description": "a string",
              "content": {
    -            "application/json": {
    +            "text/plain": {
                  "schema": {
                    "type": "string"
                  }
                }
              }
            },
            "400": {
              "description": "The request did not match the expected schema",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/HttpApiDecodeError"
                  }
                }
              }
            }
          }
        }
      }
    }
    */
  • #4234 f852cb0 Thanks @gcanti! - Deduplicate errors in OpenApi.fromApi.

    When multiple identical errors were added to the same endpoint, group, or API, they were all included in the generated OpenAPI specification, leading to redundant entries in the anyOf array for error schemas.

    Identical errors are now deduplicated in the OpenAPI specification. This ensures that each error schema is included only once, simplifying the generated spec and improving readability.

    Before

    import {
      HttpApi,
      HttpApiEndpoint,
      HttpApiGroup,
      OpenApi
    } from "@effect/platform"
    import { Schema } from "effect"
    
    const err = Schema.String.annotations({ identifier: "err" })
    const api = HttpApi.make("api")
      .add(
        HttpApiGroup.make("group1")
          .add(
            HttpApiEndpoint.get("get1", "/1")
              .addSuccess(Schema.String)
              .addError(err)
              .addError(err)
          )
          .addError(err)
          .addError(err)
      )
      .addError(err)
      .addError(err)
    
    const spec = OpenApi.fromApi(api)
    
    console.log(JSON.stringify(spec.paths, null, 2))
    /*
    Output:
    {
      "/1": {
        "get": {
          "tags": [
            "group1"
          ],
          "operationId": "group1.get1",
          "parameters": [],
          "security": [],
          "responses": {
            "200": {
              "description": "a string",
              "content": {
                "application/json": {
                  "schema": {
                    "type": "string"
                  }
                }
              }
            },
            "400": {
              "description": "The request did not match the expected schema",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/HttpApiDecodeError"
                  }
                }
              }
            },
            "500": {
              "description": "a string",
              "content": {
                "application/json": {
                  "schema": "schema": {
                    "anyOf": [
                      {
                        "$ref": "#/components/schemas/err"
                      },
                      {
                        "$ref": "#/components/schemas/err"
                      },
                      {
                        "$ref": "#/components/schemas/err"
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    }
    */

    After

    import {
      HttpApi,
      HttpApiEndpoint,
      HttpApiGroup,
      OpenApi
    } from "@effect/platform"
    import { Schema } from "effect"
    
    const err = Schema.String.annotations({ identifier: "err" })
    const api = HttpApi.make("api")
      .add(
        HttpApiGroup.make("group1")
          .add(
            HttpApiEndpoint.get("get1", "/1")
              .addSuccess(Schema.String)
              .addError(err)
              .addError(err)
          )
          .addError(err)
          .addError(err)
      )
      .addError(err)
      .addError(err)
    
    const spec = OpenApi.fromApi(api)
    
    console.log(JSON.stringify(spec.paths, null, 2))
    /*
    Output:
    {
      "/1": {
        "get": {
          "tags": [
            "group1"
          ],
          "operationId": "group1.get1",
          "parameters": [],
          "security": [],
          "responses": {
            "200": {
              "description": "a string",
              "content": {
                "application/json": {
                  "schema": {
                    "type": "string"
                  }
                }
              }
            },
            "400": {
              "description": "The request did not match the expected schema",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/HttpApiDecodeError"
                  }
                }
              }
            },
            "500": {
              "description": "a string",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/err"
                  }
                }
              }
            }
          }
        }
      }
    }
    */
  • #4233 7276ae2 Thanks @gcanti! - Ensure the encoding kind of error responses is respected in the OpenAPI spec.

    Before

    When generating an OpenAPI spec for a request with an error schema of type `HttpApiSchema.Text()``, the response content type was incorrectly set to "application/json" instead of "text/plain".

    import {
      HttpApi,
      HttpApiEndpoint,
      HttpApiGroup,
      HttpApiSchema,
      OpenApi
    } from "@effect/platform"
    
    const api = HttpApi.make("api").add(
      HttpApiGroup.make("group").add(
        HttpApiEndpoint.get("get", "/").addError(HttpApiSchema.Text())
      )
    )
    
    const spec = OpenApi.fromApi(api)
    
    console.log(JSON.stringify(spec.paths, null, 2))
    /*
    Output:
    {
      "/": {
        "get": {
          "tags": [
            "group"
          ],
          "operationId": "group.get",
          "parameters": [],
          "security": [],
          "responses": {
            "204": {
              "description": "Success"
            },
            "400": {
              "description": "The request did not match the expected schema",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/HttpApiDecodeError"
                  }
                }
              }
            },
            "500": {
              "description": "a string",
              "content": {
                "application/json": {
                  "schema": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    }
    */

    After

    import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "@effect/platform"
    
    const api = HttpApi.make("api").add(
      HttpApiGroup.make("group").add(
        HttpApiEndpoint.get("get", "/").addError(HttpApiSchema.Text())
      )
    )
    
    const spec = OpenApi.fromApi(api)
    
    console.log(JSON.stringify(spec.paths, null, 2))
    /*
    Output:
    {
      "/": {
        "get": {
          "tags": [
            "group"
          ],
          "operationId": "group.get",
          "parameters": [],
          "security": [],
          "responses": {
            "204": {
              "description": "Success"
            },
            "400": {
              "description": "The request did not match the expected schema",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/HttpApiDecodeError"
                  }
                }
              }
            },
            "500": {
              "description": "a string",
              "content": {
    +            "text/plain": {
    -            "application/json": {
                  "schema": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    }
    */
  • #4226 212e784 Thanks @gcanti! - Add missing deprecated key to OpenApi.annotations API.

  • #4226 212e784 Thanks @gcanti! - Fix: Prevent request body from being added to the OpenAPI spec for GET methods in OpenApi.fromApi.

    When creating a GET endpoint with a request payload, the requestBody was incorrectly added to the OpenAPI specification, which is invalid for GET methods.

    Before

    import {
      HttpApi,
      HttpApiEndpoint,
      HttpApiGroup,
      OpenApi
    } from "@effect/platform"
    import { Schema } from "effect"
    
    const api = HttpApi.make("api").add(
      HttpApiGroup.make("group").add(
        HttpApiEndpoint.get("get", "/")
          .addSuccess(Schema.String)
          .setPayload(
            Schema.Struct({
              a: Schema.String
            })
          )
      )
    )
    
    const spec = OpenApi.fromApi(api)
    
    console.log(JSON.stringify(spec.paths, null, 2))
    /*
    Output:
    {
      "/": {
        "get": {
          "tags": [
            "group"
          ],
          "operationId": "group.get",
          "parameters": [
            {
              "name": "a",
              "in": "query",
              "schema": {
                "type": "string"
              },
              "required": true
            }
          ],
          "security": [],
          "responses": {
            "200": {
              "description": "a string",
              "content": {
                "application/json": {
                  "schema": {
                    "type": "string"
                  }
                }
              }
            },
            "400": {
              "description": "The request did not match the expected schema",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/HttpApiDecodeError"
                  }
                }
              }
            }
          },
          "requestBody": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "a"
                  ],
                  "properties": {
                    "a": {
                      "type": "string"
                    }
                  },
                  "additionalProperties": false
                }
              }
            },
            "required": true
          }
        }
      }
    }
    */

    After

    import {
      HttpApi,
      HttpApiEndpoint,
      HttpApiGroup,
      OpenApi
    } from "@effect/platform"
    import { Schema } from "effect"
    
    const api = HttpApi.make("api").add(
      HttpApiGroup.make("group").add(
        HttpApiEndpoint.get("get", "/")
          .addSuccess(Schema.String)
          .setPayload(
            Schema.Struct({
              a: Schema.String
            })
          )
      )
    )
    
    const spec = OpenApi.fromApi(api)
    
    console.log(JSON.stringify(spec.paths, null, 2))
    /*
    Output:
    {
      "/": {
        "get": {
          "tags": [
            "group"
          ],
          "operationId": "group.get",
          "parameters": [
            {
              "name": "a",
              "in": "query",
              "schema": {
                "type": "string"
              },
              "required": true
            }
          ],
          "security": [],
          "responses": {
            "200": {
              "description": "a string",
              "content": {
                "application/json": {
                  "schema": {
                    "type": "string"
                  }
                }
              }
            },
            "400": {
              "description": "The request did not match the expected schema",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/HttpApiDecodeError"
                  }
                }
              }
            }
          }
        }
      }
    }
    */
  • #4226 212e784 Thanks @gcanti! - Add "application/x-www-form-urlencoded" to OpenApiSpecContentType type as it is generated by the system when using HttpApiSchema.withEncoding({ kind: "UrlParams" })

    Example

    import {
      HttpApi,
      HttpApiEndpoint,
      HttpApiGroup,
      HttpApiSchema,
      OpenApi
    } from "@effect/platform"
    import { Schema } from "effect"
    
    const api = HttpApi.make("api").add(
      HttpApiGroup.make("group").add(
        HttpApiEndpoint.post("post", "/")
          .addSuccess(Schema.String)
          .setPayload(
            Schema.Struct({ foo: Schema.String }).pipe(
              HttpApiSchema.withEncoding({ kind: "UrlParams" })
            )
          )
      )
    )
    
    const spec = OpenApi.fromApi(api)
    
    console.log(JSON.stringify(spec.paths, null, 2))
    /*
    Output:
    {
      "/": {
        "post": {
          "tags": [
            "group"
          ],
          "operationId": "group.post",
          "parameters": [],
          "security": [],
          "responses": {
            "200": {
              "description": "a string",
              "content": {
                "application/json": {
                  "schema": {
                    "type": "string"
                  }
                }
              }
            },
            "400": {
              "description": "The request did not match the expected schema",
              "content": {
                "application/json": {
                  "schema": {
                    "$ref": "#/components/schemas/HttpApiDecodeError"
                  }
                }
              }
            }
          },
          "requestBody": {
            "content": {
              "application/x-www-form-urlencoded": {
                "schema": {
                  "type": "object",
                  "required": [
                    "foo"
                  ],
                  "properties": {
                    "foo": {
                      "type": "string"
                    }
                  },
                  "additionalProperties": false
                }
              }
            },
            "required": true
          }
        }
      }
    }
    */
  • Updated dependencies [734af82, b63c780, c640d77, 0def088]:

    • effect@3.12.2

Don't miss a new effect release

NewReleases is sending notifications on new releases.