diff --git a/packages/cli/cli/versions.yml b/packages/cli/cli/versions.yml index 1a1ba0f8d80..0d875f32f04 100644 --- a/packages/cli/cli/versions.yml +++ b/packages/cli/cli/versions.yml @@ -1,3 +1,27 @@ +- changelogEntry: + - summary: | + The Fern Definition now supports `conten-type` on multipart request properties. + For example, to specify an `application/octet-stream` and `application/json` + contnet types, use the snippet below: + + ```ts + service: + endpoints: + upload: + request: + body: + properties: + file: + type: file + content-type: application/octet-stream + metadata: + type: unknown + content-type: application/json + ``` + type: feat + irVersion: 53 + version: 0.42.0-rc0 + - changelogEntry: - summary: Remove bang operator and fix eslint warning in `compatible-ir-versions.ts`. type: internal diff --git a/packages/cli/ete-tests/src/tests/ir/__snapshots__/ir.test.ts.snap b/packages/cli/ete-tests/src/tests/ir/__snapshots__/ir.test.ts.snap index c20e47747fe..af59e6f5370 100644 --- a/packages/cli/ete-tests/src/tests/ir/__snapshots__/ir.test.ts.snap +++ b/packages/cli/ete-tests/src/tests/ir/__snapshots__/ir.test.ts.snap @@ -1514,6 +1514,7 @@ exports[`ir > {"name":"file-upload"} 1`] = ` "properties": [ { "type": "bodyProperty", + "contentType": null, "name": { "name": { "originalName": "foo", @@ -1576,7 +1577,8 @@ exports[`ir > {"name":"file-upload"} 1`] = ` }, "wireValue": "file" }, - "isOptional": false + "isOptional": false, + "contentType": null } }, { @@ -1605,11 +1607,13 @@ exports[`ir > {"name":"file-upload"} 1`] = ` }, "wireValue": "optionalFile" }, - "isOptional": true + "isOptional": true, + "contentType": null } }, { "type": "bodyProperty", + "contentType": null, "name": { "name": { "originalName": "bar", diff --git a/packages/cli/fern-definition/schema/src/schemas/HttpInlineRequestBodyPropertySchema.ts b/packages/cli/fern-definition/schema/src/schemas/HttpInlineRequestBodyPropertySchema.ts new file mode 100644 index 00000000000..24492ee0626 --- /dev/null +++ b/packages/cli/fern-definition/schema/src/schemas/HttpInlineRequestBodyPropertySchema.ts @@ -0,0 +1,12 @@ +import { z } from "zod"; +import { DeclarationWithNameSchema } from "./DeclarationWithNameSchema"; +import { extendTypeReferenceSchema } from "./TypeReferenceSchema"; + +export const HttpInlineRequestBodyPropertySchema = extendTypeReferenceSchema( + DeclarationWithNameSchema.extend({ + // For multipart form uploads + ["content-type"]: z.string().optional() + }).shape +); + +export type HttpInlineRequestBodyPropertySchema = z.infer; diff --git a/packages/cli/fern-definition/schema/src/schemas/HttpInlineRequestBodySchema.ts b/packages/cli/fern-definition/schema/src/schemas/HttpInlineRequestBodySchema.ts index 11a26c28b5d..3ce5ec035b1 100644 --- a/packages/cli/fern-definition/schema/src/schemas/HttpInlineRequestBodySchema.ts +++ b/packages/cli/fern-definition/schema/src/schemas/HttpInlineRequestBodySchema.ts @@ -1,17 +1,18 @@ import { z } from "zod"; import { ObjectExtendsSchema } from "./ObjectExtendsSchema"; import { ObjectPropertySchema } from "./ObjectPropertySchema"; +import { HttpInlineRequestBodyPropertySchema } from "./HttpInlineRequestBodyPropertySchema"; // for inline request schemas, you need either extends/properties (or both). export const HttpInlineRequestBodySchema = z.union([ z.strictObject({ extends: ObjectExtendsSchema, - properties: z.optional(z.record(ObjectPropertySchema)), + properties: z.optional(z.record(HttpInlineRequestBodyPropertySchema)), ["extra-properties"]: z.optional(z.boolean()) }), z.strictObject({ extends: z.optional(ObjectExtendsSchema), - properties: z.record(ObjectPropertySchema), + properties: z.record(HttpInlineRequestBodyPropertySchema), ["extra-properties"]: z.optional(z.boolean()) }) ]); diff --git a/packages/cli/fern-definition/schema/src/utils/parseFileUploadRequest.ts b/packages/cli/fern-definition/schema/src/utils/parseFileUploadRequest.ts index 6a1a880de21..b4a296835b7 100644 --- a/packages/cli/fern-definition/schema/src/utils/parseFileUploadRequest.ts +++ b/packages/cli/fern-definition/schema/src/utils/parseFileUploadRequest.ts @@ -32,6 +32,7 @@ export declare namespace RawFileUploadRequest { docs: string | undefined; availability?: AvailabilityUnionSchema | undefined; key: string; + contentType?: string; } } @@ -82,6 +83,7 @@ function createRawFileUploadRequest( const properties = Object.entries(requestBody.properties ?? []).reduce( (acc, [key, propertyType]) => { const docs = typeof propertyType !== "string" ? propertyType.docs : undefined; + const contentType = typeof propertyType !== "string" ? propertyType["content-type"] : undefined; const maybeParsedFileType = parseRawFileType( typeof propertyType === "string" ? propertyType : propertyType.type ); @@ -91,10 +93,11 @@ function createRawFileUploadRequest( key, docs, isOptional: maybeParsedFileType.isOptional, - isArray: maybeParsedFileType.isArray + isArray: maybeParsedFileType.isArray, + contentType }); } else { - acc.push({ isFile: false, key, propertyType, docs }); + acc.push({ isFile: false, key, propertyType, docs, contentType }); } return acc; }, diff --git a/packages/cli/fern-definition/validator/src/ast/visitors/services/visitHttpService.ts b/packages/cli/fern-definition/validator/src/ast/visitors/services/visitHttpService.ts index 612eb31ba51..6c42ef03d87 100644 --- a/packages/cli/fern-definition/validator/src/ast/visitors/services/visitHttpService.ts +++ b/packages/cli/fern-definition/validator/src/ast/visitors/services/visitHttpService.ts @@ -198,6 +198,7 @@ async function visitEndpoint({ validation: property.validation }); }, + "content-type": noop, audiences: noop, encoding: noop, default: noop, diff --git a/packages/cli/fern-definition/validator/src/getAllRules.ts b/packages/cli/fern-definition/validator/src/getAllRules.ts index c1cc2c9ecc5..8b21c641a4f 100644 --- a/packages/cli/fern-definition/validator/src/getAllRules.ts +++ b/packages/cli/fern-definition/validator/src/getAllRules.ts @@ -42,6 +42,7 @@ import { ValidStreamConditionRule } from "./rules/valid-stream-condition"; import { ValidTypeNameRule } from "./rules/valid-type-name"; import { ValidTypeReferenceWithDefaultAndValidationRule } from "./rules/valid-type-reference-with-default-and-validation"; import { ValidVersionRule } from "./rules/valid-version"; +import { ContentTypeOnlyForMultipartRule } from "./rules/content-type-only-for-multipart"; export function getAllRules(): Rule[] { return [ @@ -87,7 +88,8 @@ export function getAllRules(): Rule[] { ValidVersionRule, NoUnusedGenericRule, ValidGenericRule, - CompatibleIrVersionsRule + CompatibleIrVersionsRule, + ContentTypeOnlyForMultipartRule ]; } diff --git a/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/__snapshots__/content-type-only-for-multipart.test.ts.snap b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/__snapshots__/content-type-only-for-multipart.test.ts.snap new file mode 100644 index 00000000000..650f7c0234e --- /dev/null +++ b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/__snapshots__/content-type-only-for-multipart.test.ts.snap @@ -0,0 +1,16 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`compatible-ir-versions > simple failure 1`] = ` +[ + { + "message": "baz has content-type, but the request is not multipart", + "nodePath": [ + "service", + "endpoints", + "json", + ], + "relativeFilepath": "simple.yml", + "severity": "error", + }, +] +`; diff --git a/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/content-type-only-for-multipart.test.ts b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/content-type-only-for-multipart.test.ts new file mode 100644 index 00000000000..f4418b61121 --- /dev/null +++ b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/content-type-only-for-multipart.test.ts @@ -0,0 +1,18 @@ +import { AbsoluteFilePath, join, RelativeFilePath } from "@fern-api/fs-utils"; +import { getViolationsForRule } from "../../../testing-utils/getViolationsForRule"; +import { ContentTypeOnlyForMultipartRule } from "../content-type-only-for-multipart"; + +describe("compatible-ir-versions", () => { + it("simple failure", async () => { + const violations = await getViolationsForRule({ + rule: ContentTypeOnlyForMultipartRule, + absolutePathToWorkspace: join( + AbsoluteFilePath.of(__dirname), + RelativeFilePath.of("fixtures"), + RelativeFilePath.of("simple") + ) + }); + + expect(violations).toMatchSnapshot(); + }); +}); diff --git a/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/fixtures/simple/definition/api.yml b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/fixtures/simple/definition/api.yml new file mode 100644 index 00000000000..eee3f038239 --- /dev/null +++ b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/fixtures/simple/definition/api.yml @@ -0,0 +1 @@ +name: simple-api diff --git a/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/fixtures/simple/definition/simple.yml b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/fixtures/simple/definition/simple.yml new file mode 100644 index 00000000000..c20345be6db --- /dev/null +++ b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/fixtures/simple/definition/simple.yml @@ -0,0 +1,27 @@ +service: + base-path: / + auth: false + endpoints: + json: + path: "" + method: POST + request: + name: ExampleReq + body: + properties: + foo: integer + baz: + type: string + content-type: "application/json" + + multipart: + path: "" + method: PUT + request: + name: MultipartReq + body: + properties: + foo: file + baz: + type: string + content-type: "application/json" \ No newline at end of file diff --git a/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/fixtures/simple/generators.yml b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/fixtures/simple/generators.yml new file mode 100644 index 00000000000..fa2bc311291 --- /dev/null +++ b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/__test__/fixtures/simple/generators.yml @@ -0,0 +1,16 @@ +groups: + python-sdk: + audiences: + - external + generators: + - name: fernapi/fern-python-sdk + version: 2.0.0 + output: + location: pypi + package-name: fern-api + token: ${PYPI_TOKEN} + github: + repository: fern-api/python-sdk + license: MIT + config: + client_class_name: Fern \ No newline at end of file diff --git a/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/content-type-only-for-multipart.ts b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/content-type-only-for-multipart.ts new file mode 100644 index 00000000000..16ddcc32c37 --- /dev/null +++ b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/content-type-only-for-multipart.ts @@ -0,0 +1,47 @@ +import { parseFileUploadRequest, isInlineRequestBody } from "@fern-api/fern-definition-schema"; +import { Rule, RuleViolation } from "../../Rule"; + +export const ContentTypeOnlyForMultipartRule: Rule = { + name: "content-type-only-for-multipart", + DISABLE_RULE: false, + create: () => { + return { + definitionFile: { + httpEndpoint: ({ endpoint }) => { + if (endpoint.request == null) { + return []; + } + + const parsedFileUploadRequest = parseFileUploadRequest(endpoint.request); + if (parsedFileUploadRequest != null) { + return []; + } + + if ( + typeof endpoint.request !== "string" && + endpoint.request.body != null && + isInlineRequestBody(endpoint.request.body) + ) { + const violations: RuleViolation[] = []; + for (const [propertyName, propertyDeclaration] of Object.entries( + endpoint.request.body.properties ?? {} + )) { + if (typeof propertyDeclaration === "string") { + continue; + } + if (propertyDeclaration["content-type"] != null) { + violations.push({ + severity: "error", + message: `${propertyName} has content-type, but the request is not multipart` + }); + } + } + return violations; + } + + return []; + } + } + }; + } +}; diff --git a/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/index.ts b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/index.ts new file mode 100644 index 00000000000..8cb4b65a05a --- /dev/null +++ b/packages/cli/fern-definition/validator/src/rules/content-type-only-for-multipart/index.ts @@ -0,0 +1 @@ +export { ContentTypeOnlyForMultipartRule } from "./content-type-only-for-multipart"; diff --git a/packages/cli/generation/ir-generator/src/__test__/test-definitions/file-upload.json b/packages/cli/generation/ir-generator/src/__test__/test-definitions/file-upload.json index 5d12e4a69db..e0050adebae 100644 --- a/packages/cli/generation/ir-generator/src/__test__/test-definitions/file-upload.json +++ b/packages/cli/generation/ir-generator/src/__test__/test-definitions/file-upload.json @@ -516,6 +516,7 @@ "properties": [ { "type": "bodyProperty", + "contentType": null, "name": { "name": { "originalName": "maybeString", @@ -560,6 +561,7 @@ }, { "type": "bodyProperty", + "contentType": null, "name": { "name": { "originalName": "integer", @@ -622,7 +624,8 @@ }, "wireValue": "file" }, - "isOptional": false + "isOptional": false, + "contentType": null } }, { @@ -651,7 +654,8 @@ }, "wireValue": "fileList" }, - "isOptional": false + "isOptional": false, + "contentType": null } }, { @@ -680,7 +684,8 @@ }, "wireValue": "maybeFile" }, - "isOptional": true + "isOptional": true, + "contentType": null } }, { @@ -709,11 +714,13 @@ }, "wireValue": "maybeFileList" }, - "isOptional": true + "isOptional": true, + "contentType": null } }, { "type": "bodyProperty", + "contentType": null, "name": { "name": { "originalName": "maybeInteger", @@ -758,6 +765,7 @@ }, { "type": "bodyProperty", + "contentType": null, "name": { "name": { "originalName": "optionalListOfStrings", @@ -808,6 +816,7 @@ }, { "type": "bodyProperty", + "contentType": null, "name": { "name": { "originalName": "listOfObjects", @@ -909,6 +918,7 @@ }, { "type": "bodyProperty", + "contentType": null, "name": { "name": { "originalName": "optionalMetadata", @@ -945,6 +955,7 @@ }, { "type": "bodyProperty", + "contentType": null, "name": { "name": { "originalName": "optionalObjectType", @@ -1046,6 +1057,7 @@ }, { "type": "bodyProperty", + "contentType": null, "name": { "name": { "originalName": "optionalId", @@ -1330,7 +1342,8 @@ }, "wireValue": "file" }, - "isOptional": false + "isOptional": false, + "contentType": null } } ] @@ -1727,7 +1740,8 @@ }, "wireValue": "file" }, - "isOptional": false + "isOptional": false, + "contentType": null } } ] @@ -2080,6 +2094,330 @@ "pagination": null, "availability": null, "docs": null + }, + { + "id": "endpoint_service.withContentType", + "name": { + "originalName": "withContentType", + "camelCase": { + "unsafeName": "withContentType", + "safeName": "withContentType" + }, + "snakeCase": { + "unsafeName": "with_content_type", + "safeName": "with_content_type" + }, + "screamingSnakeCase": { + "unsafeName": "WITH_CONTENT_TYPE", + "safeName": "WITH_CONTENT_TYPE" + }, + "pascalCase": { + "unsafeName": "WithContentType", + "safeName": "WithContentType" + } + }, + "displayName": null, + "auth": false, + "idempotent": false, + "baseUrl": null, + "method": "POST", + "path": { + "head": "/with-content-type", + "parts": [] + }, + "fullPath": { + "head": "/with-content-type", + "parts": [] + }, + "pathParameters": [], + "allPathParameters": [], + "queryParameters": [], + "headers": [], + "requestBody": { + "type": "fileUpload", + "name": { + "originalName": "WithContentTypeRequest", + "camelCase": { + "unsafeName": "withContentTypeRequest", + "safeName": "withContentTypeRequest" + }, + "snakeCase": { + "unsafeName": "with_content_type_request", + "safeName": "with_content_type_request" + }, + "screamingSnakeCase": { + "unsafeName": "WITH_CONTENT_TYPE_REQUEST", + "safeName": "WITH_CONTENT_TYPE_REQUEST" + }, + "pascalCase": { + "unsafeName": "WithContentTypeRequest", + "safeName": "WithContentTypeRequest" + } + }, + "properties": [ + { + "type": "file", + "value": { + "type": "file", + "key": { + "name": { + "originalName": "file", + "camelCase": { + "unsafeName": "file", + "safeName": "file" + }, + "snakeCase": { + "unsafeName": "file", + "safeName": "file" + }, + "screamingSnakeCase": { + "unsafeName": "FILE", + "safeName": "FILE" + }, + "pascalCase": { + "unsafeName": "File", + "safeName": "File" + } + }, + "wireValue": "file" + }, + "isOptional": false, + "contentType": null + } + }, + { + "type": "bodyProperty", + "contentType": null, + "name": { + "name": { + "originalName": "foo", + "camelCase": { + "unsafeName": "foo", + "safeName": "foo" + }, + "snakeCase": { + "unsafeName": "foo", + "safeName": "foo" + }, + "screamingSnakeCase": { + "unsafeName": "FOO", + "safeName": "FOO" + }, + "pascalCase": { + "unsafeName": "Foo", + "safeName": "Foo" + } + }, + "wireValue": "foo" + }, + "valueType": { + "_type": "primitive", + "primitive": { + "v1": "STRING", + "v2": { + "type": "string", + "default": null, + "validation": null + } + } + }, + "availability": null, + "docs": null + }, + { + "type": "bodyProperty", + "contentType": "application/json", + "name": { + "name": { + "originalName": "bar", + "camelCase": { + "unsafeName": "bar", + "safeName": "bar" + }, + "snakeCase": { + "unsafeName": "bar", + "safeName": "bar" + }, + "screamingSnakeCase": { + "unsafeName": "BAR", + "safeName": "BAR" + }, + "pascalCase": { + "unsafeName": "Bar", + "safeName": "Bar" + } + }, + "wireValue": "bar" + }, + "valueType": { + "_type": "named", + "name": { + "originalName": "MyObject", + "camelCase": { + "unsafeName": "myObject", + "safeName": "myObject" + }, + "snakeCase": { + "unsafeName": "my_object", + "safeName": "my_object" + }, + "screamingSnakeCase": { + "unsafeName": "MY_OBJECT", + "safeName": "MY_OBJECT" + }, + "pascalCase": { + "unsafeName": "MyObject", + "safeName": "MyObject" + } + }, + "fernFilepath": { + "allParts": [ + { + "originalName": "service", + "camelCase": { + "unsafeName": "service", + "safeName": "service" + }, + "snakeCase": { + "unsafeName": "service", + "safeName": "service" + }, + "screamingSnakeCase": { + "unsafeName": "SERVICE", + "safeName": "SERVICE" + }, + "pascalCase": { + "unsafeName": "Service", + "safeName": "Service" + } + } + ], + "packagePath": [], + "file": { + "originalName": "service", + "camelCase": { + "unsafeName": "service", + "safeName": "service" + }, + "snakeCase": { + "unsafeName": "service", + "safeName": "service" + }, + "screamingSnakeCase": { + "unsafeName": "SERVICE", + "safeName": "SERVICE" + }, + "pascalCase": { + "unsafeName": "Service", + "safeName": "Service" + } + } + }, + "typeId": "type_service:MyObject", + "default": null, + "inline": null + }, + "availability": null, + "docs": null + } + ] + }, + "sdkRequest": { + "shape": { + "type": "wrapper", + "wrapperName": { + "originalName": "WithContentTypeRequest", + "camelCase": { + "unsafeName": "withContentTypeRequest", + "safeName": "withContentTypeRequest" + }, + "snakeCase": { + "unsafeName": "with_content_type_request", + "safeName": "with_content_type_request" + }, + "screamingSnakeCase": { + "unsafeName": "WITH_CONTENT_TYPE_REQUEST", + "safeName": "WITH_CONTENT_TYPE_REQUEST" + }, + "pascalCase": { + "unsafeName": "WithContentTypeRequest", + "safeName": "WithContentTypeRequest" + } + }, + "bodyKey": { + "originalName": "body", + "camelCase": { + "unsafeName": "body", + "safeName": "body" + }, + "snakeCase": { + "unsafeName": "body", + "safeName": "body" + }, + "screamingSnakeCase": { + "unsafeName": "BODY", + "safeName": "BODY" + }, + "pascalCase": { + "unsafeName": "Body", + "safeName": "Body" + } + } + }, + "requestParameterName": { + "originalName": "request", + "camelCase": { + "unsafeName": "request", + "safeName": "request" + }, + "snakeCase": { + "unsafeName": "request", + "safeName": "request" + }, + "screamingSnakeCase": { + "unsafeName": "REQUEST", + "safeName": "REQUEST" + }, + "pascalCase": { + "unsafeName": "Request", + "safeName": "Request" + } + }, + "streamParameter": null + }, + "response": { + "body": null, + "status-code": null + }, + "errors": [], + "userSpecifiedExamples": [], + "autogeneratedExamples": [ + { + "example": { + "url": "/with-content-type", + "rootPathParameters": [], + "servicePathParameters": [], + "endpointPathParameters": [], + "serviceHeaders": [], + "endpointHeaders": [], + "queryParameters": [], + "request": null, + "name": null, + "response": { + "type": "ok", + "value": { + "type": "body", + "value": null + } + }, + "id": "b0765b3588f9e7638200b3085cbdde56e6b79d1c", + "docs": null + } + } + ], + "pagination": null, + "availability": null, + "docs": null } ] } diff --git a/packages/cli/generation/ir-generator/src/converters/services/convertHttpRequestBody.ts b/packages/cli/generation/ir-generator/src/converters/services/convertHttpRequestBody.ts index 59e9003a0db..f2a0b18e4f5 100644 --- a/packages/cli/generation/ir-generator/src/converters/services/convertHttpRequestBody.ts +++ b/packages/cli/generation/ir-generator/src/converters/services/convertHttpRequestBody.ts @@ -58,7 +58,8 @@ export function convertHttpRequestBody({ wireValue: property.key, name: property.key }), - isOptional: property.isOptional + isOptional: property.isOptional, + contentType: property.contentType }) ); } else { @@ -68,20 +69,22 @@ export function convertHttpRequestBody({ wireValue: property.key, name: property.key }), - isOptional: property.isOptional + isOptional: property.isOptional, + contentType: property.contentType }) ); } } else { - return FileUploadRequestProperty.bodyProperty( - convertInlinedRequestProperty({ + return FileUploadRequestProperty.bodyProperty({ + ...convertInlinedRequestProperty({ propertyKey: property.key, propertyDefinition: property.propertyType, docs: property.docs, availability: convertAvailability(property.availability), file - }) - ); + }), + contentType: property.contentType + }); } }) }); diff --git a/packages/cli/register/src/ir-to-fdr-converter/__test__/__snapshots__/convertIrToFdrApi.test.ts.snap b/packages/cli/register/src/ir-to-fdr-converter/__test__/__snapshots__/convertIrToFdrApi.test.ts.snap index 31b10dfb2c4..e5d9ca25dc2 100644 --- a/packages/cli/register/src/ir-to-fdr-converter/__test__/__snapshots__/convertIrToFdrApi.test.ts.snap +++ b/packages/cli/register/src/ir-to-fdr-converter/__test__/__snapshots__/convertIrToFdrApi.test.ts.snap @@ -1505,141 +1505,6 @@ exports[`fdr test definitions > auth-environment-variables 1`] = ` } `; -exports[`fdr test definitions > availability 1`] = ` -{ - "auth": undefined, - "globalHeaders": [], - "rootPackage": { - "endpoints": [], - "pointsTo": undefined, - "subpackages": [ - "subpackage_service", - ], - "types": [], - "webhooks": [], - "websockets": [], - }, - "snippetsConfiguration": {}, - "subpackages": { - "subpackage_service": { - "description": undefined, - "displayName": undefined, - "endpoints": [ - { - "auth": false, - "availability": undefined, - "defaultEnvironment": undefined, - "description": undefined, - "environments": undefined, - "errors": undefined, - "errorsV2": [], - "examples": [], - "headers": [], - "id": "test-availability", - "method": "POST", - "name": "Test Availability", - "originalEndpointId": "endpoint_service.test-availability", - "path": { - "parts": [ - { - "type": "literal", - "value": "", - }, - { - "type": "literal", - "value": "/test-availability", - }, - ], - "pathParameters": [], - }, - "queryParameters": [], - "request": { - "type": { - "contentType": "application/json", - "shape": { - "extends": [], - "properties": [ - { - "availability": "Beta", - "description": undefined, - "key": "random", - "valueType": { - "type": "primitive", - "value": { - "default": undefined, - "maxLength": undefined, - "minLength": undefined, - "regex": undefined, - "type": "string", - }, - }, - }, - ], - "type": "object", - }, - "type": "json", - }, - }, - "response": { - "statusCode": undefined, - "type": { - "type": "reference", - "value": { - "type": "primitive", - "value": { - "default": undefined, - "maxLength": undefined, - "minLength": undefined, - "regex": undefined, - "type": "string", - }, - }, - }, - }, - }, - ], - "name": "service", - "pointsTo": undefined, - "subpackageId": "subpackage_service", - "subpackages": [], - "types": [ - "type_service:Object", - ], - "webhooks": [], - "websockets": [], - }, - }, - "types": { - "type_service:Object": { - "availability": undefined, - "description": undefined, - "name": "Object", - "shape": { - "extends": [], - "properties": [ - { - "availability": "Beta", - "description": undefined, - "key": "id", - "valueType": { - "type": "primitive", - "value": { - "default": undefined, - "maxLength": undefined, - "minLength": undefined, - "regex": undefined, - "type": "string", - }, - }, - }, - ], - "type": "object", - }, - }, - }, -} -`; - exports[`fdr test definitions > basic-auth 1`] = ` { "auth": { @@ -11195,6 +11060,82 @@ exports[`fdr test definitions > file-upload 1`] = ` }, "response": undefined, }, + { + "auth": false, + "availability": undefined, + "defaultEnvironment": undefined, + "description": undefined, + "environments": undefined, + "errors": undefined, + "errorsV2": [], + "examples": [], + "headers": [], + "id": "withContentType", + "method": "POST", + "name": "With Content Type", + "originalEndpointId": "endpoint_service.withContentType", + "path": { + "parts": [ + { + "type": "literal", + "value": "/", + }, + { + "type": "literal", + "value": "/with-content-type", + }, + ], + "pathParameters": [], + }, + "queryParameters": [], + "request": { + "type": { + "type": "fileUpload", + "value": { + "availability": undefined, + "description": undefined, + "name": "WithContentTypeRequest", + "properties": [ + { + "type": "file", + "value": { + "isOptional": false, + "key": "file", + "type": "file", + }, + }, + { + "availability": undefined, + "description": undefined, + "key": "foo", + "type": "bodyProperty", + "valueType": { + "type": "primitive", + "value": { + "default": undefined, + "maxLength": undefined, + "minLength": undefined, + "regex": undefined, + "type": "string", + }, + }, + }, + { + "availability": undefined, + "description": undefined, + "key": "bar", + "type": "bodyProperty", + "valueType": { + "type": "id", + "value": "type_service:MyObject", + }, + }, + ], + }, + }, + }, + "response": undefined, + }, ], "name": "service", "pointsTo": undefined, diff --git a/packages/ir-sdk/fern/apis/ir-types-latest/VERSION b/packages/ir-sdk/fern/apis/ir-types-latest/VERSION index a8ef2225ca0..44d1b23a0ed 100644 --- a/packages/ir-sdk/fern/apis/ir-types-latest/VERSION +++ b/packages/ir-sdk/fern/apis/ir-types-latest/VERSION @@ -1 +1 @@ -53.11.0 +53.12.0 diff --git a/packages/ir-sdk/fern/apis/ir-types-latest/changelog/CHANGELOG.md b/packages/ir-sdk/fern/apis/ir-types-latest/changelog/CHANGELOG.md index 4a09cd84699..85acee16873 100644 --- a/packages/ir-sdk/fern/apis/ir-types-latest/changelog/CHANGELOG.md +++ b/packages/ir-sdk/fern/apis/ir-types-latest/changelog/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v53.12.0] - 2024-08-13 + +- Feature: Add `contentType` to file upload body properties. + ## [v53.11.0] - 2024-08-13 - Fix: Add availability to inline websocket, webhook, and http body parameter properties. diff --git a/packages/ir-sdk/fern/apis/ir-types-latest/definition/http.yml b/packages/ir-sdk/fern/apis/ir-types-latest/definition/http.yml index cc1cb4f2537..60ff0fd0676 100644 --- a/packages/ir-sdk/fern/apis/ir-types-latest/definition/http.yml +++ b/packages/ir-sdk/fern/apis/ir-types-latest/definition/http.yml @@ -129,7 +129,11 @@ types: FileUploadRequestProperty: union: file: FileProperty - bodyProperty: InlinedRequestBodyProperty + bodyProperty: FileUploadBodyProperty + FileUploadBodyProperty: + extends: InlinedRequestBodyProperty + properties: + contentType: optional FileProperty: union: file: FilePropertySingle @@ -138,10 +142,12 @@ types: properties: key: commons.NameAndWireValue isOptional: boolean + contentType: optional FilePropertyArray: properties: key: commons.NameAndWireValue isOptional: boolean + contentType: optional HttpRequestBodyReference: extends: commons.WithDocs properties: diff --git a/packages/ir-sdk/src/sdk/api/resources/http/types/FilePropertyArray.ts b/packages/ir-sdk/src/sdk/api/resources/http/types/FilePropertyArray.ts index 7fd0dbcfe2e..7748b187367 100644 --- a/packages/ir-sdk/src/sdk/api/resources/http/types/FilePropertyArray.ts +++ b/packages/ir-sdk/src/sdk/api/resources/http/types/FilePropertyArray.ts @@ -7,4 +7,5 @@ import * as FernIr from "../../../index"; export interface FilePropertyArray { key: FernIr.NameAndWireValue; isOptional: boolean; + contentType: string | undefined; } diff --git a/packages/ir-sdk/src/sdk/api/resources/http/types/FilePropertySingle.ts b/packages/ir-sdk/src/sdk/api/resources/http/types/FilePropertySingle.ts index 467d1940b4c..73ff0a25c10 100644 --- a/packages/ir-sdk/src/sdk/api/resources/http/types/FilePropertySingle.ts +++ b/packages/ir-sdk/src/sdk/api/resources/http/types/FilePropertySingle.ts @@ -7,4 +7,5 @@ import * as FernIr from "../../../index"; export interface FilePropertySingle { key: FernIr.NameAndWireValue; isOptional: boolean; + contentType: string | undefined; } diff --git a/packages/ir-sdk/src/sdk/api/resources/http/types/FileUploadBodyProperty.ts b/packages/ir-sdk/src/sdk/api/resources/http/types/FileUploadBodyProperty.ts new file mode 100644 index 00000000000..9fbb2f9a9ef --- /dev/null +++ b/packages/ir-sdk/src/sdk/api/resources/http/types/FileUploadBodyProperty.ts @@ -0,0 +1,9 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as FernIr from "../../../index"; + +export interface FileUploadBodyProperty extends FernIr.InlinedRequestBodyProperty { + contentType: string | undefined; +} diff --git a/packages/ir-sdk/src/sdk/api/resources/http/types/FileUploadRequestProperty.ts b/packages/ir-sdk/src/sdk/api/resources/http/types/FileUploadRequestProperty.ts index 84db7e4d192..03ef451e455 100644 --- a/packages/ir-sdk/src/sdk/api/resources/http/types/FileUploadRequestProperty.ts +++ b/packages/ir-sdk/src/sdk/api/resources/http/types/FileUploadRequestProperty.ts @@ -14,7 +14,7 @@ export declare namespace FileUploadRequestProperty { value: FernIr.FileProperty; } - interface BodyProperty extends FernIr.InlinedRequestBodyProperty, _Utils { + interface BodyProperty extends FernIr.FileUploadBodyProperty, _Utils { type: "bodyProperty"; } @@ -24,7 +24,7 @@ export declare namespace FileUploadRequestProperty { interface _Visitor<_Result> { file: (value: FernIr.FileProperty) => _Result; - bodyProperty: (value: FernIr.InlinedRequestBodyProperty) => _Result; + bodyProperty: (value: FernIr.FileUploadBodyProperty) => _Result; _other: (value: { type: string }) => _Result; } } @@ -43,7 +43,7 @@ export const FileUploadRequestProperty = { }; }, - bodyProperty: (value: FernIr.InlinedRequestBodyProperty): FernIr.FileUploadRequestProperty.BodyProperty => { + bodyProperty: (value: FernIr.FileUploadBodyProperty): FernIr.FileUploadRequestProperty.BodyProperty => { return { ...value, type: "bodyProperty", diff --git a/packages/ir-sdk/src/sdk/api/resources/http/types/index.ts b/packages/ir-sdk/src/sdk/api/resources/http/types/index.ts index ab7637a21e9..ecc9c093dc5 100644 --- a/packages/ir-sdk/src/sdk/api/resources/http/types/index.ts +++ b/packages/ir-sdk/src/sdk/api/resources/http/types/index.ts @@ -17,6 +17,7 @@ export * from "./InlinedRequestBodyProperty"; export * from "./FileUploadRequest"; export * from "./BytesRequest"; export * from "./FileUploadRequestProperty"; +export * from "./FileUploadBodyProperty"; export * from "./FileProperty"; export * from "./FilePropertySingle"; export * from "./FilePropertyArray"; diff --git a/packages/ir-sdk/src/sdk/serialization/resources/http/types/FilePropertyArray.ts b/packages/ir-sdk/src/sdk/serialization/resources/http/types/FilePropertyArray.ts index fc996f495c7..be69de72b70 100644 --- a/packages/ir-sdk/src/sdk/serialization/resources/http/types/FilePropertyArray.ts +++ b/packages/ir-sdk/src/sdk/serialization/resources/http/types/FilePropertyArray.ts @@ -13,11 +13,13 @@ export const FilePropertyArray: core.serialization.ObjectSchema< > = core.serialization.objectWithoutOptionalProperties({ key: NameAndWireValue, isOptional: core.serialization.boolean(), + contentType: core.serialization.string().optional(), }); export declare namespace FilePropertyArray { interface Raw { key: NameAndWireValue.Raw; isOptional: boolean; + contentType?: string | null; } } diff --git a/packages/ir-sdk/src/sdk/serialization/resources/http/types/FilePropertySingle.ts b/packages/ir-sdk/src/sdk/serialization/resources/http/types/FilePropertySingle.ts index 68ec0a30371..aa180e8abb1 100644 --- a/packages/ir-sdk/src/sdk/serialization/resources/http/types/FilePropertySingle.ts +++ b/packages/ir-sdk/src/sdk/serialization/resources/http/types/FilePropertySingle.ts @@ -13,11 +13,13 @@ export const FilePropertySingle: core.serialization.ObjectSchema< > = core.serialization.objectWithoutOptionalProperties({ key: NameAndWireValue, isOptional: core.serialization.boolean(), + contentType: core.serialization.string().optional(), }); export declare namespace FilePropertySingle { interface Raw { key: NameAndWireValue.Raw; isOptional: boolean; + contentType?: string | null; } } diff --git a/packages/ir-sdk/src/sdk/serialization/resources/http/types/FileUploadBodyProperty.ts b/packages/ir-sdk/src/sdk/serialization/resources/http/types/FileUploadBodyProperty.ts new file mode 100644 index 00000000000..4746fc61de4 --- /dev/null +++ b/packages/ir-sdk/src/sdk/serialization/resources/http/types/FileUploadBodyProperty.ts @@ -0,0 +1,23 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as serializers from "../../../index"; +import * as FernIr from "../../../../api/index"; +import * as core from "../../../../core"; +import { InlinedRequestBodyProperty } from "./InlinedRequestBodyProperty"; + +export const FileUploadBodyProperty: core.serialization.ObjectSchema< + serializers.FileUploadBodyProperty.Raw, + FernIr.FileUploadBodyProperty +> = core.serialization + .objectWithoutOptionalProperties({ + contentType: core.serialization.string().optional(), + }) + .extend(InlinedRequestBodyProperty); + +export declare namespace FileUploadBodyProperty { + interface Raw extends InlinedRequestBodyProperty.Raw { + contentType?: string | null; + } +} diff --git a/packages/ir-sdk/src/sdk/serialization/resources/http/types/FileUploadRequestProperty.ts b/packages/ir-sdk/src/sdk/serialization/resources/http/types/FileUploadRequestProperty.ts index 3a716698fea..6aa0d159ded 100644 --- a/packages/ir-sdk/src/sdk/serialization/resources/http/types/FileUploadRequestProperty.ts +++ b/packages/ir-sdk/src/sdk/serialization/resources/http/types/FileUploadRequestProperty.ts @@ -6,7 +6,7 @@ import * as serializers from "../../../index"; import * as FernIr from "../../../../api/index"; import * as core from "../../../../core"; import { FileProperty } from "./FileProperty"; -import { InlinedRequestBodyProperty } from "./InlinedRequestBodyProperty"; +import { FileUploadBodyProperty } from "./FileUploadBodyProperty"; export const FileUploadRequestProperty: core.serialization.Schema< serializers.FileUploadRequestProperty.Raw, @@ -16,7 +16,7 @@ export const FileUploadRequestProperty: core.serialization.Schema< file: core.serialization.object({ value: FileProperty, }), - bodyProperty: InlinedRequestBodyProperty, + bodyProperty: FileUploadBodyProperty, }) .transform({ transform: (value) => { @@ -40,7 +40,7 @@ export declare namespace FileUploadRequestProperty { value: FileProperty.Raw; } - interface BodyProperty extends InlinedRequestBodyProperty.Raw { + interface BodyProperty extends FileUploadBodyProperty.Raw { type: "bodyProperty"; } } diff --git a/packages/ir-sdk/src/sdk/serialization/resources/http/types/index.ts b/packages/ir-sdk/src/sdk/serialization/resources/http/types/index.ts index ab7637a21e9..ecc9c093dc5 100644 --- a/packages/ir-sdk/src/sdk/serialization/resources/http/types/index.ts +++ b/packages/ir-sdk/src/sdk/serialization/resources/http/types/index.ts @@ -17,6 +17,7 @@ export * from "./InlinedRequestBodyProperty"; export * from "./FileUploadRequest"; export * from "./BytesRequest"; export * from "./FileUploadRequestProperty"; +export * from "./FileUploadBodyProperty"; export * from "./FileProperty"; export * from "./FilePropertySingle"; export * from "./FilePropertyArray"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 63905aac902..bd0feb7e9aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3322,6 +3322,8 @@ importers: specifier: ^2.0.5 version: 2.0.5(@types/node@18.7.18)(jsdom@20.0.3)(sass@1.72.0)(terser@5.31.5) + packages/cli/cli/dist/dev: {} + packages/cli/cli/dist/prod: {} packages/cli/configuration: diff --git a/seed/csharp-model/file-upload/.mock/definition/service.yml b/seed/csharp-model/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/csharp-model/file-upload/.mock/definition/service.yml +++ b/seed/csharp-model/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/csharp-sdk/file-upload/.mock/definition/service.yml b/seed/csharp-sdk/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/csharp-sdk/file-upload/.mock/definition/service.yml +++ b/seed/csharp-sdk/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Service/Requests/WithContentTypeRequest.cs b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Service/Requests/WithContentTypeRequest.cs new file mode 100644 index 00000000000..5b74237c2ae --- /dev/null +++ b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Service/Requests/WithContentTypeRequest.cs @@ -0,0 +1,13 @@ +using SeedFileUpload.Core; + +#nullable enable + +namespace SeedFileUpload; + +public record WithContentTypeRequest +{ + public override string ToString() + { + return JsonUtils.Serialize(this); + } +} diff --git a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Service/ServiceClient.cs b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Service/ServiceClient.cs index 735f2f22264..729219a24fc 100644 --- a/seed/csharp-sdk/file-upload/src/SeedFileUpload/Service/ServiceClient.cs +++ b/seed/csharp-sdk/file-upload/src/SeedFileUpload/Service/ServiceClient.cs @@ -112,4 +112,32 @@ public async Task JustFileWithQueryParamsAsync( responseBody ); } + + public async Task WithContentTypeAsync( + WithContentTypeRequest request, + RequestOptions? options = null, + CancellationToken cancellationToken = default + ) + { + var response = await _client.MakeRequestAsync( + new RawClient.JsonApiRequest + { + BaseUrl = _client.Options.BaseUrl, + Method = HttpMethod.Post, + Path = "/with-content-type", + Options = options, + }, + cancellationToken + ); + if (response.StatusCode is >= 200 and < 400) + { + return; + } + var responseBody = await response.Raw.Content.ReadAsStringAsync(); + throw new SeedFileUploadApiException( + $"Error with status code {response.StatusCode}", + response.StatusCode, + responseBody + ); + } } diff --git a/seed/go-fiber/file-upload/.mock/definition/service.yml b/seed/go-fiber/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/go-fiber/file-upload/.mock/definition/service.yml +++ b/seed/go-fiber/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/go-fiber/file-upload/service.go b/seed/go-fiber/file-upload/service.go index 44f1faedda7..e95c3784afd 100644 --- a/seed/go-fiber/file-upload/service.go +++ b/seed/go-fiber/file-upload/service.go @@ -84,3 +84,8 @@ func NewObjectTypeFromString(s string) (ObjectType, error) { func (o ObjectType) Ptr() *ObjectType { return &o } + +type WithContentTypeRequest struct { + Foo string `json:"foo" url:"-"` + Bar *MyObject `json:"bar,omitempty" url:"-"` +} diff --git a/seed/go-model/file-upload/.mock/definition/service.yml b/seed/go-model/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/go-model/file-upload/.mock/definition/service.yml +++ b/seed/go-model/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/go-sdk/file-upload/.mock/definition/service.yml b/seed/go-sdk/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/go-sdk/file-upload/.mock/definition/service.yml +++ b/seed/go-sdk/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/go-sdk/file-upload/service.go b/seed/go-sdk/file-upload/service.go index 8a485c70635..4b3316194d8 100644 --- a/seed/go-sdk/file-upload/service.go +++ b/seed/go-sdk/file-upload/service.go @@ -91,3 +91,8 @@ func NewObjectTypeFromString(s string) (ObjectType, error) { func (o ObjectType) Ptr() *ObjectType { return &o } + +type WithContentTypeRequest struct { + Foo string `json:"foo" url:"-"` + Bar *MyObject `json:"bar,omitempty" url:"-"` +} diff --git a/seed/go-sdk/file-upload/service/client.go b/seed/go-sdk/file-upload/service/client.go index 1f9c29289b0..09ab0ca7fe9 100644 --- a/seed/go-sdk/file-upload/service/client.go +++ b/seed/go-sdk/file-upload/service/client.go @@ -283,3 +283,64 @@ func (c *Client) JustFileWithQueryParams( } return nil } + +func (c *Client) WithContentType( + ctx context.Context, + file io.Reader, + request *fern.WithContentTypeRequest, + opts ...option.RequestOption, +) error { + options := core.NewRequestOptions(opts...) + + baseURL := "" + if c.baseURL != "" { + baseURL = c.baseURL + } + if options.BaseURL != "" { + baseURL = options.BaseURL + } + endpointURL := baseURL + "/with-content-type" + + headers := core.MergeHeaders(c.header.Clone(), options.ToHeader()) + + requestBuffer := bytes.NewBuffer(nil) + writer := multipart.NewWriter(requestBuffer) + fileFilename := "file_filename" + if named, ok := file.(interface{ Name() string }); ok { + fileFilename = named.Name() + } + filePart, err := writer.CreateFormFile("file", fileFilename) + if err != nil { + return err + } + if _, err := io.Copy(filePart, file); err != nil { + return err + } + if err := writer.WriteField("foo", fmt.Sprintf("%v", request.Foo)); err != nil { + return err + } + if err := core.WriteMultipartJSON(writer, "bar", request.Bar); err != nil { + return err + } + if err := writer.Close(); err != nil { + return err + } + headers.Set("Content-Type", writer.FormDataContentType()) + + if err := c.caller.Call( + ctx, + &core.CallParams{ + URL: endpointURL, + Method: http.MethodPost, + MaxAttempts: options.MaxAttempts, + Headers: headers, + BodyProperties: options.BodyProperties, + QueryParameters: options.QueryParameters, + Client: options.HTTPClient, + Request: requestBuffer, + }, + ); err != nil { + return err + } + return nil +} diff --git a/seed/go-sdk/file-upload/snippet.json b/seed/go-sdk/file-upload/snippet.json index ef01547093f..f4a73ad1e62 100644 --- a/seed/go-sdk/file-upload/snippet.json +++ b/seed/go-sdk/file-upload/snippet.json @@ -32,6 +32,17 @@ "type": "go", "client": "import (\n\tcontext \"context\"\n\tfernclient \"github.com/file-upload/fern/client\"\n)\n\nclient := fernclient.NewClient()\nerr := client.Service.JustFile(\n\tcontext.TODO(),\n)\n" } + }, + { + "id": { + "path": "/with-content-type", + "method": "POST", + "identifier_override": "endpoint_service.withContentType" + }, + "snippet": { + "type": "go", + "client": "import (\n\tcontext \"context\"\n\tfern \"github.com/file-upload/fern\"\n\tfernclient \"github.com/file-upload/fern/client\"\n)\n\nclient := fernclient.NewClient()\nerr := client.Service.WithContentType(\n\tcontext.TODO(),\n\t\u0026fern.WithContentTypeRequest{},\n)\n" + } } ] } \ No newline at end of file diff --git a/seed/java-model/file-upload/.mock/definition/service.yml b/seed/java-model/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/java-model/file-upload/.mock/definition/service.yml +++ b/seed/java-model/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/java-sdk/file-upload/.mock/definition/service.yml b/seed/java-sdk/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/java-sdk/file-upload/.mock/definition/service.yml +++ b/seed/java-sdk/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/java-sdk/file-upload/src/main/java/com/seed/fileUpload/resources/service/ServiceClient.java b/seed/java-sdk/file-upload/src/main/java/com/seed/fileUpload/resources/service/ServiceClient.java index e55d170ec06..e59eb7b29e0 100644 --- a/seed/java-sdk/file-upload/src/main/java/com/seed/fileUpload/resources/service/ServiceClient.java +++ b/seed/java-sdk/file-upload/src/main/java/com/seed/fileUpload/resources/service/ServiceClient.java @@ -11,6 +11,7 @@ import com.seed.fileUpload.resources.service.requests.JustFileRequet; import com.seed.fileUpload.resources.service.requests.JustFileWithQueryParamsRequet; import com.seed.fileUpload.resources.service.requests.MyRequest; +import com.seed.fileUpload.resources.service.requests.WithContentTypeRequest; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -227,4 +228,47 @@ public void justFileWithQueryParams( throw new SeedFileUploadException("Network error executing HTTP request", e); } } + + public void withContentType(File file, WithContentTypeRequest request) { + withContentType(file, request, null); + } + + public void withContentType(File file, WithContentTypeRequest request, RequestOptions requestOptions) { + HttpUrl httpUrl = HttpUrl.parse(this.clientOptions.environment().getUrl()) + .newBuilder() + .addPathSegments("with-content-type") + .build(); + MultipartBody.Builder body = new MultipartBody.Builder().setType(MultipartBody.FORM); + try { + String fileMimeType = Files.probeContentType(file.toPath()); + MediaType fileMimeTypeMediaType = fileMimeType != null ? MediaType.parse(fileMimeType) : null; + body.addFormDataPart("file", file.getName(), RequestBody.create(fileMimeTypeMediaType, file)); + body.addFormDataPart("foo", ObjectMappers.JSON_MAPPER.writeValueAsString(request.getFoo())); + body.addFormDataPart("bar", ObjectMappers.JSON_MAPPER.writeValueAsString(request.getBar())); + } catch (Exception e) { + throw new RuntimeException(e); + } + Request.Builder _requestBuilder = new Request.Builder() + .url(httpUrl) + .method("POST", body.build()) + .headers(Headers.of(clientOptions.headers(requestOptions))); + Request okhttpRequest = _requestBuilder.build(); + OkHttpClient client = clientOptions.httpClient(); + if (requestOptions != null && requestOptions.getTimeout().isPresent()) { + client = clientOptions.httpClientWithTimeout(requestOptions); + } + try (Response response = client.newCall(okhttpRequest).execute()) { + ResponseBody responseBody = response.body(); + if (response.isSuccessful()) { + return; + } + String responseBodyString = responseBody != null ? responseBody.string() : "{}"; + throw new SeedFileUploadApiException( + "Error with status code " + response.code(), + response.code(), + ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class)); + } catch (IOException e) { + throw new SeedFileUploadException("Network error executing HTTP request", e); + } + } } diff --git a/seed/java-sdk/file-upload/src/main/java/com/seed/fileUpload/resources/service/requests/WithContentTypeRequest.java b/seed/java-sdk/file-upload/src/main/java/com/seed/fileUpload/resources/service/requests/WithContentTypeRequest.java new file mode 100644 index 00000000000..898761d410b --- /dev/null +++ b/seed/java-sdk/file-upload/src/main/java/com/seed/fileUpload/resources/service/requests/WithContentTypeRequest.java @@ -0,0 +1,125 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ +package com.seed.fileUpload.resources.service.requests; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.seed.fileUpload.core.ObjectMappers; +import com.seed.fileUpload.resources.service.types.MyObject; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +@JsonInclude(JsonInclude.Include.NON_ABSENT) +@JsonDeserialize(builder = WithContentTypeRequest.Builder.class) +public final class WithContentTypeRequest { + private final String foo; + + private final MyObject bar; + + private final Map additionalProperties; + + private WithContentTypeRequest(String foo, MyObject bar, Map additionalProperties) { + this.foo = foo; + this.bar = bar; + this.additionalProperties = additionalProperties; + } + + @JsonProperty("foo") + public String getFoo() { + return foo; + } + + @JsonProperty("bar") + public MyObject getBar() { + return bar; + } + + @java.lang.Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof WithContentTypeRequest && equalTo((WithContentTypeRequest) other); + } + + @JsonAnyGetter + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + private boolean equalTo(WithContentTypeRequest other) { + return foo.equals(other.foo) && bar.equals(other.bar); + } + + @java.lang.Override + public int hashCode() { + return Objects.hash(this.foo, this.bar); + } + + @java.lang.Override + public String toString() { + return ObjectMappers.stringify(this); + } + + public static FooStage builder() { + return new Builder(); + } + + public interface FooStage { + BarStage foo(@NotNull String foo); + + Builder from(WithContentTypeRequest other); + } + + public interface BarStage { + _FinalStage bar(@NotNull MyObject bar); + } + + public interface _FinalStage { + WithContentTypeRequest build(); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static final class Builder implements FooStage, BarStage, _FinalStage { + private String foo; + + private MyObject bar; + + @JsonAnySetter + private Map additionalProperties = new HashMap<>(); + + private Builder() {} + + @java.lang.Override + public Builder from(WithContentTypeRequest other) { + foo(other.getFoo()); + bar(other.getBar()); + return this; + } + + @java.lang.Override + @JsonSetter("foo") + public BarStage foo(@NotNull String foo) { + this.foo = Objects.requireNonNull(foo, "foo must not be null"); + return this; + } + + @java.lang.Override + @JsonSetter("bar") + public _FinalStage bar(@NotNull MyObject bar) { + this.bar = Objects.requireNonNull(bar, "bar must not be null"); + return this; + } + + @java.lang.Override + public WithContentTypeRequest build() { + return new WithContentTypeRequest(foo, bar, additionalProperties); + } + } +} diff --git a/seed/openapi/file-upload/.mock/definition/service.yml b/seed/openapi/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/openapi/file-upload/.mock/definition/service.yml +++ b/seed/openapi/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/openapi/file-upload/openapi.yml b/seed/openapi/file-upload/openapi.yml index 7d69b9f252c..0c61bfe4186 100644 --- a/seed/openapi/file-upload/openapi.yml +++ b/seed/openapi/file-upload/openapi.yml @@ -126,6 +126,29 @@ paths: file: type: string format: binary + /with-content-type: + post: + operationId: service_withContentType + tags: + - Service + parameters: [] + responses: + '204': + description: '' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + foo: + type: string + bar: + $ref: '#/components/schemas/MyObject' components: schemas: Id: diff --git a/seed/php-model/file-upload/.mock/definition/service.yml b/seed/php-model/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/php-model/file-upload/.mock/definition/service.yml +++ b/seed/php-model/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/php-sdk/file-upload/.mock/definition/service.yml b/seed/php-sdk/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/php-sdk/file-upload/.mock/definition/service.yml +++ b/seed/php-sdk/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/postman/file-upload/.mock/definition/service.yml b/seed/postman/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/postman/file-upload/.mock/definition/service.yml +++ b/seed/postman/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/postman/file-upload/collection.json b/seed/postman/file-upload/collection.json index f32f5902f66..8c329259536 100644 --- a/seed/postman/file-upload/collection.json +++ b/seed/postman/file-upload/collection.json @@ -251,6 +251,68 @@ "_postman_previewlanguage": "json" } ] + }, + { + "_type": "endpoint", + "name": "With Content Type", + "request": { + "description": null, + "url": { + "raw": "{{baseUrl}}/with-content-type", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "with-content-type" + ], + "query": [], + "variable": [] + }, + "header": [ + { + "type": "text", + "key": "Content-Type", + "value": "application/json" + } + ], + "method": "POST", + "auth": null, + "body": null + }, + "response": [ + { + "name": "Success", + "status": "OK", + "code": 200, + "originalRequest": { + "description": null, + "url": { + "raw": "{{baseUrl}}/with-content-type", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "with-content-type" + ], + "query": [], + "variable": [] + }, + "header": [ + { + "type": "text", + "key": "Content-Type", + "value": "application/json" + } + ], + "method": "POST", + "auth": null, + "body": null + }, + "description": null, + "body": "", + "_postman_previewlanguage": "json" + } + ] } ] } diff --git a/seed/pydantic/file-upload/.mock/definition/service.yml b/seed/pydantic/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/pydantic/file-upload/.mock/definition/service.yml +++ b/seed/pydantic/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/python-sdk/file-upload/.mock/definition/service.yml b/seed/python-sdk/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/python-sdk/file-upload/.mock/definition/service.yml +++ b/seed/python-sdk/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/python-sdk/file-upload/reference.md b/seed/python-sdk/file-upload/reference.md index ab2021823a9..cd398282ea4 100644 --- a/seed/python-sdk/file-upload/reference.md +++ b/seed/python-sdk/file-upload/reference.md @@ -308,3 +308,75 @@ core.File` — See core.File for more documentation +
client.service.with_content_type(...) +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```python +from seed import SeedFileUpload + +client = SeedFileUpload( + base_url="https://yourhost.com/path/to/api", +) +client.service.with_content_type() + +``` +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**file:** `from __future__ import annotations + +core.File` — See core.File for more documentation + +
+
+ +
+
+ +**foo:** `str` + +
+
+ +
+
+ +**bar:** `MyObject` + +
+
+ +
+
+ +**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. + +
+
+
+
+ + +
+
+
+ diff --git a/seed/python-sdk/file-upload/resolved-snippet-templates.md b/seed/python-sdk/file-upload/resolved-snippet-templates.md index 7fd36ca9431..a2b54adc0b9 100644 --- a/seed/python-sdk/file-upload/resolved-snippet-templates.md +++ b/seed/python-sdk/file-upload/resolved-snippet-templates.md @@ -31,3 +31,12 @@ client.service.just_file_with_query_params( ``` +```python + + +client = SeedFileUpload(base_url="https://yourhost.com/path/to/api", ) +undefined + +``` + + diff --git a/seed/python-sdk/file-upload/snippet-templates.json b/seed/python-sdk/file-upload/snippet-templates.json index deeecef39b8..a66d6282bc8 100644 --- a/seed/python-sdk/file-upload/snippet-templates.json +++ b/seed/python-sdk/file-upload/snippet-templates.json @@ -898,5 +898,187 @@ "type": "v1" } } + }, + { + "sdk": { + "package": "fern_file-upload", + "version": "0.0.1", + "type": "python" + }, + "endpointId": { + "path": "/with-content-type", + "method": "POST", + "identifierOverride": "endpoint_service.withContentType" + }, + "snippetTemplate": { + "clientInstantiation": { + "imports": [ + "from seed import SeedFileUpload" + ], + "isOptional": true, + "templateString": "client = SeedFileUpload(base_url=\"https://yourhost.com/path/to/api\", )", + "templateInputs": [], + "inputDelimiter": ",", + "type": "generic" + }, + "functionInvocation": { + "imports": [], + "isOptional": true, + "templateString": "client.service.with_content_type(\n\t$FERN_INPUT\n)", + "templateInputs": [ + { + "type": "template", + "value": { + "imports": [], + "isOptional": true, + "templateString": "file=$FERN_INPUT", + "templateInputs": [ + { + "location": "BODY", + "path": "file", + "type": "payload" + } + ], + "type": "generic" + } + }, + { + "type": "template", + "value": { + "imports": [], + "isOptional": true, + "templateString": "foo=$FERN_INPUT", + "templateInputs": [ + { + "location": "BODY", + "path": "foo", + "type": "payload" + } + ], + "type": "generic" + } + }, + { + "type": "template", + "value": { + "imports": [ + "from seed.service import MyObject" + ], + "isOptional": true, + "templateString": "bar=MyObject(\n\t\t$FERN_INPUT\n\t)", + "templateInputs": [ + { + "type": "template", + "value": { + "imports": [], + "isOptional": true, + "templateString": "foo=$FERN_INPUT", + "templateInputs": [ + { + "location": "BODY", + "path": "bar.foo", + "type": "payload" + } + ], + "type": "generic" + } + } + ], + "inputDelimiter": ",\n\t\t", + "type": "generic" + } + } + ], + "inputDelimiter": ",\n\t", + "type": "generic" + }, + "type": "v1" + }, + "additionalTemplates": { + "async": { + "clientInstantiation": { + "imports": [ + "from seed import AsyncSeedFileUpload" + ], + "isOptional": true, + "templateString": "client = AsyncSeedFileUpload(base_url=\"https://yourhost.com/path/to/api\", )", + "templateInputs": [], + "inputDelimiter": ",", + "type": "generic" + }, + "functionInvocation": { + "imports": [], + "isOptional": true, + "templateString": "await client.service.with_content_type(\n\t$FERN_INPUT\n)", + "templateInputs": [ + { + "type": "template", + "value": { + "imports": [], + "isOptional": true, + "templateString": "file=$FERN_INPUT", + "templateInputs": [ + { + "location": "BODY", + "path": "file", + "type": "payload" + } + ], + "type": "generic" + } + }, + { + "type": "template", + "value": { + "imports": [], + "isOptional": true, + "templateString": "foo=$FERN_INPUT", + "templateInputs": [ + { + "location": "BODY", + "path": "foo", + "type": "payload" + } + ], + "type": "generic" + } + }, + { + "type": "template", + "value": { + "imports": [ + "from seed.service import MyObject" + ], + "isOptional": true, + "templateString": "bar=MyObject(\n\t\t$FERN_INPUT\n\t)", + "templateInputs": [ + { + "type": "template", + "value": { + "imports": [], + "isOptional": true, + "templateString": "foo=$FERN_INPUT", + "templateInputs": [ + { + "location": "BODY", + "path": "bar.foo", + "type": "payload" + } + ], + "type": "generic" + } + } + ], + "inputDelimiter": ",\n\t\t", + "type": "generic" + } + } + ], + "inputDelimiter": ",\n\t", + "type": "generic" + }, + "type": "v1" + } + } } ] \ No newline at end of file diff --git a/seed/python-sdk/file-upload/snippet.json b/seed/python-sdk/file-upload/snippet.json index 0b9f70ea1a7..6d9b604aee1 100644 --- a/seed/python-sdk/file-upload/snippet.json +++ b/seed/python-sdk/file-upload/snippet.json @@ -39,6 +39,19 @@ "async_client": "import asyncio\n\nfrom seed import AsyncSeedFileUpload\n\nclient = AsyncSeedFileUpload(\n base_url=\"https://yourhost.com/path/to/api\",\n)\n\n\nasync def main() -> None:\n await client.service.just_file_with_query_params(\n maybe_string=\"string\",\n integer=1,\n maybe_integer=1,\n list_of_strings=\"string\",\n optional_list_of_strings=\"string\",\n )\n\n\nasyncio.run(main())\n", "type": "python" } + }, + { + "example_identifier": "default", + "id": { + "path": "/with-content-type", + "method": "POST", + "identifier_override": "endpoint_service.withContentType" + }, + "snippet": { + "sync_client": "from seed import SeedFileUpload\n\nclient = SeedFileUpload(\n base_url=\"https://yourhost.com/path/to/api\",\n)\nclient.service.with_content_type()\n", + "async_client": "import asyncio\n\nfrom seed import AsyncSeedFileUpload\n\nclient = AsyncSeedFileUpload(\n base_url=\"https://yourhost.com/path/to/api\",\n)\n\n\nasync def main() -> None:\n await client.service.with_content_type()\n\n\nasyncio.run(main())\n", + "type": "python" + } } ] } \ No newline at end of file diff --git a/seed/python-sdk/file-upload/src/seed/service/client.py b/seed/python-sdk/file-upload/src/seed/service/client.py index abdebb1dbf6..484eb95b5b5 100644 --- a/seed/python-sdk/file-upload/src/seed/service/client.py +++ b/seed/python-sdk/file-upload/src/seed/service/client.py @@ -227,6 +227,56 @@ def just_file_with_query_params( raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + def with_content_type( + self, *, file: core.File, foo: str, bar: MyObject, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Parameters + ---------- + file : core.File + See core.File for more documentation + + foo : str + + bar : MyObject + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from seed import SeedFileUpload + + client = SeedFileUpload( + base_url="https://yourhost.com/path/to/api", + ) + client.service.with_content_type() + """ + _response = self._client_wrapper.httpx_client.request( + "with-content-type", + method="POST", + data={ + "foo": foo, + "bar": bar, + }, + files={ + "file": file, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) + class AsyncServiceClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): @@ -463,3 +513,61 @@ async def main() -> None: except JSONDecodeError: raise ApiError(status_code=_response.status_code, body=_response.text) raise ApiError(status_code=_response.status_code, body=_response_json) + + async def with_content_type( + self, *, file: core.File, foo: str, bar: MyObject, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Parameters + ---------- + file : core.File + See core.File for more documentation + + foo : str + + bar : MyObject + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from seed import AsyncSeedFileUpload + + client = AsyncSeedFileUpload( + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.service.with_content_type() + + + asyncio.run(main()) + """ + _response = await self._client_wrapper.httpx_client.request( + "with-content-type", + method="POST", + data={ + "foo": foo, + "bar": bar, + }, + files={ + "file": file, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return + _response_json = _response.json() + except JSONDecodeError: + raise ApiError(status_code=_response.status_code, body=_response.text) + raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/seed/ruby-model/file-upload/.mock/definition/service.yml b/seed/ruby-model/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/ruby-model/file-upload/.mock/definition/service.yml +++ b/seed/ruby-model/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/ruby-model/file-upload/lib/core/file_utilities.rb b/seed/ruby-model/file-upload/lib/core/file_utilities.rb new file mode 100644 index 00000000000..e039543620e --- /dev/null +++ b/seed/ruby-model/file-upload/lib/core/file_utilities.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require "faraday/multipart" +require "mini_mime" + +module SeedFileUploadClient + # Utility class for managing files. + class FileUtilities + # @param file_like [String, IO] The file to be uploaded, or a string path to the file. + # @return [Faraday::Multipart::FilePart] + def self.as_faraday_multipart(file_like:) + path = if file_like.is_a?(String) + file_like + else + file_like.path + end + mime_type = MiniMime.lookup_by_filename(path) + mime_type = if mime_type.nil? + "application/octet-stream" + else + mime_type.content_type + end + Faraday::Multipart::FilePart.new(file_like, mime_type) + end + end +end diff --git a/seed/ruby-model/file-upload/lib/requests.rb b/seed/ruby-model/file-upload/lib/requests.rb new file mode 100644 index 00000000000..93e759dc812 --- /dev/null +++ b/seed/ruby-model/file-upload/lib/requests.rb @@ -0,0 +1,135 @@ +# frozen_string_literal: true + +require "faraday" +require "faraday/multipart" +require "faraday/retry" +require "async/http/faraday" + +module SeedFileUploadClient + class RequestClient + # @return [Faraday] + attr_reader :conn + # @return [String] + attr_reader :base_url + + # @param base_url [String] + # @param max_retries [Long] The number of times to retry a failed request, defaults to 2. + # @param timeout_in_seconds [Long] + # @return [SeedFileUploadClient::RequestClient] + def initialize(base_url: nil, max_retries: nil, timeout_in_seconds: nil) + @base_url = base_url + @conn = Faraday.new do |faraday| + faraday.request :multipart + faraday.request :json + faraday.response :raise_error, include_request: true + faraday.request :retry, { max: max_retries } unless max_retries.nil? + faraday.options.timeout = timeout_in_seconds unless timeout_in_seconds.nil? + end + end + + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [String] + def get_url(request_options: nil) + request_options&.base_url || @base_url + end + + # @return [Hash{String => String}] + def get_headers + { "X-Fern-Language": "Ruby", "X-Fern-SDK-Name": "seed_file_upload_client" } + end + end + + class AsyncRequestClient + # @return [Faraday] + attr_reader :conn + # @return [String] + attr_reader :base_url + + # @param base_url [String] + # @param max_retries [Long] The number of times to retry a failed request, defaults to 2. + # @param timeout_in_seconds [Long] + # @return [SeedFileUploadClient::AsyncRequestClient] + def initialize(base_url: nil, max_retries: nil, timeout_in_seconds: nil) + @base_url = base_url + @conn = Faraday.new do |faraday| + faraday.request :multipart + faraday.request :json + faraday.response :raise_error, include_request: true + faraday.adapter :async_http + faraday.request :retry, { max: max_retries } unless max_retries.nil? + faraday.options.timeout = timeout_in_seconds unless timeout_in_seconds.nil? + end + end + + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [String] + def get_url(request_options: nil) + request_options&.base_url || @base_url + end + + # @return [Hash{String => String}] + def get_headers + { "X-Fern-Language": "Ruby", "X-Fern-SDK-Name": "seed_file_upload_client" } + end + end + + # Additional options for request-specific configuration when calling APIs via the + # SDK. + class RequestOptions + # @return [String] + attr_reader :base_url + # @return [Hash{String => Object}] + attr_reader :additional_headers + # @return [Hash{String => Object}] + attr_reader :additional_query_parameters + # @return [Hash{String => Object}] + attr_reader :additional_body_parameters + # @return [Long] + attr_reader :timeout_in_seconds + + # @param base_url [String] + # @param additional_headers [Hash{String => Object}] + # @param additional_query_parameters [Hash{String => Object}] + # @param additional_body_parameters [Hash{String => Object}] + # @param timeout_in_seconds [Long] + # @return [SeedFileUploadClient::RequestOptions] + def initialize(base_url: nil, additional_headers: nil, additional_query_parameters: nil, + additional_body_parameters: nil, timeout_in_seconds: nil) + @base_url = base_url + @additional_headers = additional_headers + @additional_query_parameters = additional_query_parameters + @additional_body_parameters = additional_body_parameters + @timeout_in_seconds = timeout_in_seconds + end + end + + # Additional options for request-specific configuration when calling APIs via the + # SDK. + class IdempotencyRequestOptions + # @return [String] + attr_reader :base_url + # @return [Hash{String => Object}] + attr_reader :additional_headers + # @return [Hash{String => Object}] + attr_reader :additional_query_parameters + # @return [Hash{String => Object}] + attr_reader :additional_body_parameters + # @return [Long] + attr_reader :timeout_in_seconds + + # @param base_url [String] + # @param additional_headers [Hash{String => Object}] + # @param additional_query_parameters [Hash{String => Object}] + # @param additional_body_parameters [Hash{String => Object}] + # @param timeout_in_seconds [Long] + # @return [SeedFileUploadClient::IdempotencyRequestOptions] + def initialize(base_url: nil, additional_headers: nil, additional_query_parameters: nil, + additional_body_parameters: nil, timeout_in_seconds: nil) + @base_url = base_url + @additional_headers = additional_headers + @additional_query_parameters = additional_query_parameters + @additional_body_parameters = additional_body_parameters + @timeout_in_seconds = timeout_in_seconds + end + end +end diff --git a/seed/ruby-model/file-upload/lib/seed_file_upload_client.rb b/seed/ruby-model/file-upload/lib/seed_file_upload_client.rb index c887b5119e9..30d440dbf4a 100644 --- a/seed/ruby-model/file-upload/lib/seed_file_upload_client.rb +++ b/seed/ruby-model/file-upload/lib/seed_file_upload_client.rb @@ -1,4 +1,43 @@ # frozen_string_literal: true -require_relative "seed_file_upload_client/service/types/my_object" -require_relative "seed_file_upload_client/service/types/object_type" +require_relative "types_export" +require_relative "requests" +require_relative "seed_file_upload_client/service/client" + +module SeedFileUploadClient + class Client + # @return [SeedFileUploadClient::ServiceClient] + attr_reader :service + + # @param base_url [String] + # @param max_retries [Long] The number of times to retry a failed request, defaults to 2. + # @param timeout_in_seconds [Long] + # @return [SeedFileUploadClient::Client] + def initialize(base_url: nil, max_retries: nil, timeout_in_seconds: nil) + @request_client = SeedFileUploadClient::RequestClient.new( + base_url: base_url, + max_retries: max_retries, + timeout_in_seconds: timeout_in_seconds + ) + @service = SeedFileUploadClient::ServiceClient.new(request_client: @request_client) + end + end + + class AsyncClient + # @return [SeedFileUploadClient::AsyncServiceClient] + attr_reader :service + + # @param base_url [String] + # @param max_retries [Long] The number of times to retry a failed request, defaults to 2. + # @param timeout_in_seconds [Long] + # @return [SeedFileUploadClient::AsyncClient] + def initialize(base_url: nil, max_retries: nil, timeout_in_seconds: nil) + @async_request_client = SeedFileUploadClient::AsyncRequestClient.new( + base_url: base_url, + max_retries: max_retries, + timeout_in_seconds: timeout_in_seconds + ) + @service = SeedFileUploadClient::AsyncServiceClient.new(request_client: @async_request_client) + end + end +end diff --git a/seed/ruby-model/file-upload/lib/seed_file_upload_client/service/client.rb b/seed/ruby-model/file-upload/lib/seed_file_upload_client/service/client.rb new file mode 100644 index 00000000000..75a6b1b0e7f --- /dev/null +++ b/seed/ruby-model/file-upload/lib/seed_file_upload_client/service/client.rb @@ -0,0 +1,351 @@ +# frozen_string_literal: true + +require_relative "../../requests" +require_relative "types/my_object" +require_relative "types/object_type" +require_relative "../../core/file_utilities" +require "async" + +module SeedFileUploadClient + class ServiceClient + # @return [SeedFileUploadClient::RequestClient] + attr_reader :request_client + + # @param request_client [SeedFileUploadClient::RequestClient] + # @return [SeedFileUploadClient::ServiceClient] + def initialize(request_client:) + @request_client = request_client + end + + # @param maybe_string [String] + # @param integer [Integer] + # @param file [String, IO] + # @param file_list [String, IO] + # @param maybe_file [String, IO] + # @param maybe_file_list [String, IO] + # @param maybe_integer [Integer] + # @param optional_list_of_strings [Array] + # @param list_of_objects [Array] Request of type Array, as a Hash + # * :foo (String) + # @param optional_metadata [Object] + # @param optional_object_type [SeedFileUploadClient::Service::ObjectType] + # @param optional_id [String] + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [Void] + # @example + # file_upload = SeedFileUploadClient::Client.new(base_url: "https://api.example.com") + # file_upload.service.post( + # file: my_file.txt, + # file_list: my_file.txt, + # maybe_file: my_file.txt, + # maybe_file_list: my_file.txt + # ) + def post(integer:, file:, file_list:, list_of_objects:, maybe_string: nil, maybe_file: nil, maybe_file_list: nil, maybe_integer: nil, + optional_list_of_strings: nil, optional_metadata: nil, optional_object_type: nil, optional_id: nil, request_options: nil) + @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers = { + **(req.headers || {}), + **@request_client.get_headers, + **(request_options&.additional_headers || {}) + }.compact + unless request_options.nil? || request_options&.additional_query_parameters.nil? + req.params = { **(request_options&.additional_query_parameters || {}) }.compact + end + req.body = { + **(request_options&.additional_body_parameters || {}), + maybeString: maybe_string, + integer: integer, + file: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file), + fileList: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file_list), + maybeFile: unless maybe_file.nil? + SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: maybe_file) + end, + maybeFileList: unless maybe_file_list.nil? + SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: maybe_file_list) + end, + maybeInteger: maybe_integer, + optionalListOfStrings: optional_list_of_strings, + listOfObjects: list_of_objects, + optionalMetadata: optional_metadata, + optionalObjectType: optional_object_type, + optionalId: optional_id + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/" + end + end + + # @param file [String, IO] + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [Void] + # @example + # file_upload = SeedFileUploadClient::Client.new(base_url: "https://api.example.com") + # file_upload.service.just_file(file: my_file.txt) + def just_file(file:, request_options: nil) + @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers = { + **(req.headers || {}), + **@request_client.get_headers, + **(request_options&.additional_headers || {}) + }.compact + unless request_options.nil? || request_options&.additional_query_parameters.nil? + req.params = { **(request_options&.additional_query_parameters || {}) }.compact + end + req.body = { + **(request_options&.additional_body_parameters || {}), + file: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file) + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/just-file" + end + end + + # @param maybe_string [String] + # @param integer [Integer] + # @param maybe_integer [Integer] + # @param list_of_strings [String] + # @param optional_list_of_strings [String] + # @param file [String, IO] + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [Void] + # @example + # file_upload = SeedFileUploadClient::Client.new(base_url: "https://api.example.com") + # file_upload.service.just_file_with_query_params( + # maybe_string: "string", + # integer: 1, + # maybe_integer: 1, + # list_of_strings: "string", + # optional_list_of_strings: "string", + # file: my_file.txt + # ) + def just_file_with_query_params(integer:, list_of_strings:, file:, maybe_string: nil, maybe_integer: nil, + optional_list_of_strings: nil, request_options: nil) + @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers = { + **(req.headers || {}), + **@request_client.get_headers, + **(request_options&.additional_headers || {}) + }.compact + req.params = { + **(request_options&.additional_query_parameters || {}), + "maybeString": maybe_string, + "integer": integer, + "maybeInteger": maybe_integer, + "listOfStrings": list_of_strings, + "optionalListOfStrings": optional_list_of_strings + }.compact + req.body = { + **(request_options&.additional_body_parameters || {}), + file: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file) + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/just-file-with-query-params" + end + end + + # @param file [String, IO] + # @param foo [String] + # @param bar [Hash] Request of type SeedFileUploadClient::Service::MyObject, as a Hash + # * :foo (String) + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [Void] + # @example + # file_upload = SeedFileUploadClient::Client.new(base_url: "https://api.example.com") + # file_upload.service.with_content_type(file: my_file.txt) + def with_content_type(file:, foo:, bar:, request_options: nil) + @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers = { + **(req.headers || {}), + **@request_client.get_headers, + **(request_options&.additional_headers || {}) + }.compact + unless request_options.nil? || request_options&.additional_query_parameters.nil? + req.params = { **(request_options&.additional_query_parameters || {}) }.compact + end + req.body = { + **(request_options&.additional_body_parameters || {}), + file: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file), + foo: foo, + bar: bar + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/with-content-type" + end + end + end + + class AsyncServiceClient + # @return [SeedFileUploadClient::AsyncRequestClient] + attr_reader :request_client + + # @param request_client [SeedFileUploadClient::AsyncRequestClient] + # @return [SeedFileUploadClient::AsyncServiceClient] + def initialize(request_client:) + @request_client = request_client + end + + # @param maybe_string [String] + # @param integer [Integer] + # @param file [String, IO] + # @param file_list [String, IO] + # @param maybe_file [String, IO] + # @param maybe_file_list [String, IO] + # @param maybe_integer [Integer] + # @param optional_list_of_strings [Array] + # @param list_of_objects [Array] Request of type Array, as a Hash + # * :foo (String) + # @param optional_metadata [Object] + # @param optional_object_type [SeedFileUploadClient::Service::ObjectType] + # @param optional_id [String] + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [Void] + # @example + # file_upload = SeedFileUploadClient::Client.new(base_url: "https://api.example.com") + # file_upload.service.post( + # file: my_file.txt, + # file_list: my_file.txt, + # maybe_file: my_file.txt, + # maybe_file_list: my_file.txt + # ) + def post(integer:, file:, file_list:, list_of_objects:, maybe_string: nil, maybe_file: nil, maybe_file_list: nil, maybe_integer: nil, + optional_list_of_strings: nil, optional_metadata: nil, optional_object_type: nil, optional_id: nil, request_options: nil) + Async do + @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers = { + **(req.headers || {}), + **@request_client.get_headers, + **(request_options&.additional_headers || {}) + }.compact + unless request_options.nil? || request_options&.additional_query_parameters.nil? + req.params = { **(request_options&.additional_query_parameters || {}) }.compact + end + req.body = { + **(request_options&.additional_body_parameters || {}), + maybeString: maybe_string, + integer: integer, + file: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file), + fileList: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file_list), + maybeFile: unless maybe_file.nil? + SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: maybe_file) + end, + maybeFileList: unless maybe_file_list.nil? + SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: maybe_file_list) + end, + maybeInteger: maybe_integer, + optionalListOfStrings: optional_list_of_strings, + listOfObjects: list_of_objects, + optionalMetadata: optional_metadata, + optionalObjectType: optional_object_type, + optionalId: optional_id + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/" + end + end + end + + # @param file [String, IO] + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [Void] + # @example + # file_upload = SeedFileUploadClient::Client.new(base_url: "https://api.example.com") + # file_upload.service.just_file(file: my_file.txt) + def just_file(file:, request_options: nil) + Async do + @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers = { + **(req.headers || {}), + **@request_client.get_headers, + **(request_options&.additional_headers || {}) + }.compact + unless request_options.nil? || request_options&.additional_query_parameters.nil? + req.params = { **(request_options&.additional_query_parameters || {}) }.compact + end + req.body = { + **(request_options&.additional_body_parameters || {}), + file: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file) + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/just-file" + end + end + end + + # @param maybe_string [String] + # @param integer [Integer] + # @param maybe_integer [Integer] + # @param list_of_strings [String] + # @param optional_list_of_strings [String] + # @param file [String, IO] + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [Void] + # @example + # file_upload = SeedFileUploadClient::Client.new(base_url: "https://api.example.com") + # file_upload.service.just_file_with_query_params( + # maybe_string: "string", + # integer: 1, + # maybe_integer: 1, + # list_of_strings: "string", + # optional_list_of_strings: "string", + # file: my_file.txt + # ) + def just_file_with_query_params(integer:, list_of_strings:, file:, maybe_string: nil, maybe_integer: nil, + optional_list_of_strings: nil, request_options: nil) + Async do + @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers = { + **(req.headers || {}), + **@request_client.get_headers, + **(request_options&.additional_headers || {}) + }.compact + req.params = { + **(request_options&.additional_query_parameters || {}), + "maybeString": maybe_string, + "integer": integer, + "maybeInteger": maybe_integer, + "listOfStrings": list_of_strings, + "optionalListOfStrings": optional_list_of_strings + }.compact + req.body = { + **(request_options&.additional_body_parameters || {}), + file: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file) + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/just-file-with-query-params" + end + end + end + + # @param file [String, IO] + # @param foo [String] + # @param bar [Hash] Request of type SeedFileUploadClient::Service::MyObject, as a Hash + # * :foo (String) + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [Void] + # @example + # file_upload = SeedFileUploadClient::Client.new(base_url: "https://api.example.com") + # file_upload.service.with_content_type(file: my_file.txt) + def with_content_type(file:, foo:, bar:, request_options: nil) + Async do + @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers = { + **(req.headers || {}), + **@request_client.get_headers, + **(request_options&.additional_headers || {}) + }.compact + unless request_options.nil? || request_options&.additional_query_parameters.nil? + req.params = { **(request_options&.additional_query_parameters || {}) }.compact + end + req.body = { + **(request_options&.additional_body_parameters || {}), + file: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file), + foo: foo, + bar: bar + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/with-content-type" + end + end + end + end +end diff --git a/seed/ruby-model/file-upload/lib/types_export.rb b/seed/ruby-model/file-upload/lib/types_export.rb new file mode 100644 index 00000000000..c887b5119e9 --- /dev/null +++ b/seed/ruby-model/file-upload/lib/types_export.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require_relative "seed_file_upload_client/service/types/my_object" +require_relative "seed_file_upload_client/service/types/object_type" diff --git a/seed/ruby-model/file-upload/seed_file_upload_client.gemspec b/seed/ruby-model/file-upload/seed_file_upload_client.gemspec index 45e8acadfe4..ec5f53ca0b7 100644 --- a/seed/ruby-model/file-upload/seed_file_upload_client.gemspec +++ b/seed/ruby-model/file-upload/seed_file_upload_client.gemspec @@ -18,4 +18,10 @@ Gem::Specification.new do |spec| spec.bindir = "exe" spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] + spec.add_dependency "async-http-faraday", ">= 0.0", "< 1.0" + spec.add_dependency "faraday", ">= 1.10", "< 3.0" + spec.add_dependency "faraday-multipart", ">= 0.0", "< 2.0" + spec.add_dependency "faraday-net_http", ">= 1.0", "< 4.0" + spec.add_dependency "faraday-retry", ">= 1.0", "< 3.0" + spec.add_dependency "mini_mime" end diff --git a/seed/ruby-sdk/file-upload/.mock/definition/service.yml b/seed/ruby-sdk/file-upload/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/ruby-sdk/file-upload/.mock/definition/service.yml +++ b/seed/ruby-sdk/file-upload/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/ruby-sdk/file-upload/lib/fern_file_upload/service/client.rb b/seed/ruby-sdk/file-upload/lib/fern_file_upload/service/client.rb index 925eed04f03..75a6b1b0e7f 100644 --- a/seed/ruby-sdk/file-upload/lib/fern_file_upload/service/client.rb +++ b/seed/ruby-sdk/file-upload/lib/fern_file_upload/service/client.rb @@ -142,6 +142,36 @@ def just_file_with_query_params(integer:, list_of_strings:, file:, maybe_string: req.url "#{@request_client.get_url(request_options: request_options)}/just-file-with-query-params" end end + + # @param file [String, IO] + # @param foo [String] + # @param bar [Hash] Request of type SeedFileUploadClient::Service::MyObject, as a Hash + # * :foo (String) + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [Void] + # @example + # file_upload = SeedFileUploadClient::Client.new(base_url: "https://api.example.com") + # file_upload.service.with_content_type(file: my_file.txt) + def with_content_type(file:, foo:, bar:, request_options: nil) + @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers = { + **(req.headers || {}), + **@request_client.get_headers, + **(request_options&.additional_headers || {}) + }.compact + unless request_options.nil? || request_options&.additional_query_parameters.nil? + req.params = { **(request_options&.additional_query_parameters || {}) }.compact + end + req.body = { + **(request_options&.additional_body_parameters || {}), + file: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file), + foo: foo, + bar: bar + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/with-content-type" + end + end end class AsyncServiceClient @@ -285,5 +315,37 @@ def just_file_with_query_params(integer:, list_of_strings:, file:, maybe_string: end end end + + # @param file [String, IO] + # @param foo [String] + # @param bar [Hash] Request of type SeedFileUploadClient::Service::MyObject, as a Hash + # * :foo (String) + # @param request_options [SeedFileUploadClient::RequestOptions] + # @return [Void] + # @example + # file_upload = SeedFileUploadClient::Client.new(base_url: "https://api.example.com") + # file_upload.service.with_content_type(file: my_file.txt) + def with_content_type(file:, foo:, bar:, request_options: nil) + Async do + @request_client.conn.post do |req| + req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil? + req.headers = { + **(req.headers || {}), + **@request_client.get_headers, + **(request_options&.additional_headers || {}) + }.compact + unless request_options.nil? || request_options&.additional_query_parameters.nil? + req.params = { **(request_options&.additional_query_parameters || {}) }.compact + end + req.body = { + **(request_options&.additional_body_parameters || {}), + file: SeedFileUploadClient::FileUtilities.as_faraday_multipart(file_like: file), + foo: foo, + bar: bar + }.compact + req.url "#{@request_client.get_url(request_options: request_options)}/with-content-type" + end + end + end end end diff --git a/seed/ruby-sdk/file-upload/snippet.json b/seed/ruby-sdk/file-upload/snippet.json index 58737203e27..c19e39ece5e 100644 --- a/seed/ruby-sdk/file-upload/snippet.json +++ b/seed/ruby-sdk/file-upload/snippet.json @@ -33,6 +33,17 @@ "type": "ruby" } }, + { + "id": { + "path": "/with-content-type", + "method": "POST", + "identifierOverride": "endpoint_service.withContentType" + }, + "snippet": { + "client": "require \"fern_file_upload\"\n\nfile_upload = SeedFileUploadClient::Client.new(base_url: \"https://api.example.com\")\nfile_upload.service.with_content_type(file: my_file.txt)", + "type": "ruby" + } + }, { "id": { "path": "/", @@ -65,6 +76,17 @@ "client": "require \"fern_file_upload\"\n\nfile_upload = SeedFileUploadClient::Client.new(base_url: \"https://api.example.com\")\nfile_upload.service.just_file_with_query_params(\n maybe_string: \"string\",\n integer: 1,\n maybe_integer: 1,\n list_of_strings: \"string\",\n optional_list_of_strings: \"string\",\n file: my_file.txt\n)", "type": "ruby" } + }, + { + "id": { + "path": "/with-content-type", + "method": "POST", + "identifierOverride": "endpoint_service.withContentType" + }, + "snippet": { + "client": "require \"fern_file_upload\"\n\nfile_upload = SeedFileUploadClient::Client.new(base_url: \"https://api.example.com\")\nfile_upload.service.with_content_type(file: my_file.txt)", + "type": "ruby" + } } ], "types": {} diff --git a/seed/ts-sdk/file-upload/no-custom-config/.mock/definition/service.yml b/seed/ts-sdk/file-upload/no-custom-config/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/ts-sdk/file-upload/no-custom-config/.mock/definition/service.yml +++ b/seed/ts-sdk/file-upload/no-custom-config/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/ts-sdk/file-upload/no-custom-config/reference.md b/seed/ts-sdk/file-upload/no-custom-config/reference.md index 51e99ab0b0a..5630c32da6b 100644 --- a/seed/ts-sdk/file-upload/no-custom-config/reference.md +++ b/seed/ts-sdk/file-upload/no-custom-config/reference.md @@ -197,3 +197,59 @@ await client.service.justFileWithQueryParams(fs.createReadStream("/path/to/your/ + +
client.service.withContentType(file, { ...params }) -> void +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.service.withContentType(fs.createReadStream("/path/to/your/file"), {}); +``` + +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**file:** `File | fs.ReadStream | Blob` + +
+
+ +
+
+ +**request:** `SeedFileUpload.WithContentTypeRequest` + +
+
+ +
+
+ +**requestOptions:** `Service.RequestOptions` + +
+
+
+
+ +
+
+
diff --git a/seed/ts-sdk/file-upload/no-custom-config/resolved-snippet-templates.md b/seed/ts-sdk/file-upload/no-custom-config/resolved-snippet-templates.md index e7480fd9a21..330887cc924 100644 --- a/seed/ts-sdk/file-upload/no-custom-config/resolved-snippet-templates.md +++ b/seed/ts-sdk/file-upload/no-custom-config/resolved-snippet-templates.md @@ -31,3 +31,12 @@ await client.service.justFileWithQueryParams({ ``` +```typescript +import { SeedFileUploadClient } from "@fern/file-upload"; + +const client = new SeedFileUploadClient({ environment: "YOUR_BASE_URL" }); +undefined; + +``` + + diff --git a/seed/ts-sdk/file-upload/no-custom-config/snippet-templates.json b/seed/ts-sdk/file-upload/no-custom-config/snippet-templates.json index a2765554691..0d09def9054 100644 --- a/seed/ts-sdk/file-upload/no-custom-config/snippet-templates.json +++ b/seed/ts-sdk/file-upload/no-custom-config/snippet-templates.json @@ -577,5 +577,135 @@ }, "type": "v1" } + }, + { + "sdk": { + "package": "@fern/file-upload", + "version": "0.0.1", + "type": "typescript" + }, + "endpointId": { + "path": "/with-content-type", + "method": "POST", + "identifierOverride": "endpoint_service.withContentType" + }, + "snippetTemplate": { + "clientInstantiation": { + "imports": [ + "import { SeedFileUploadClient } from \"@fern/file-upload\";" + ], + "templateString": "const client = new SeedFileUploadClient($FERN_INPUT);", + "isOptional": false, + "inputDelimiter": ",", + "templateInputs": [ + { + "value": { + "imports": [], + "templateString": "{ $FERN_INPUT }", + "isOptional": true, + "templateInputs": [ + { + "value": { + "imports": [], + "templateString": "environment: \"YOUR_BASE_URL\"", + "isOptional": false, + "templateInputs": [], + "type": "generic" + }, + "type": "template" + } + ], + "type": "generic" + }, + "type": "template" + } + ], + "type": "generic" + }, + "functionInvocation": { + "imports": [], + "templateString": "await client.service.withContentType(\n\t$FERN_INPUT\n)", + "isOptional": false, + "inputDelimiter": ",\n\t", + "templateInputs": [ + { + "value": { + "imports": [], + "templateString": "$FERN_INPUT", + "isOptional": false, + "inputDelimiter": ",\n\t", + "templateInputs": [ + { + "value": { + "imports": [ + "import fs from \"fs\";" + ], + "templateString": "fs.createReadStream('$FERN_INPUT')", + "isOptional": false, + "templateInputs": [ + { + "location": "BODY", + "path": "file", + "type": "payload" + } + ], + "type": "generic" + }, + "type": "template" + }, + { + "value": { + "imports": [], + "templateString": "foo: $FERN_INPUT", + "isOptional": true, + "templateInputs": [ + { + "location": "BODY", + "path": "foo", + "type": "payload" + } + ], + "type": "generic" + }, + "type": "template" + }, + { + "value": { + "imports": [], + "templateString": "bar: {\n\t\t\t$FERN_INPUT\n\t\t}", + "isOptional": true, + "inputDelimiter": ",\n\t\t\t", + "templateInputs": [ + { + "value": { + "imports": [], + "templateString": "foo: $FERN_INPUT", + "isOptional": true, + "templateInputs": [ + { + "location": "BODY", + "path": "bar.foo", + "type": "payload" + } + ], + "type": "generic" + }, + "type": "template" + } + ], + "type": "generic" + }, + "type": "template" + } + ], + "type": "generic" + }, + "type": "template" + } + ], + "type": "generic" + }, + "type": "v1" + } } ] \ No newline at end of file diff --git a/seed/ts-sdk/file-upload/no-custom-config/snippet.json b/seed/ts-sdk/file-upload/no-custom-config/snippet.json index b5b200a592b..bd64a620da8 100644 --- a/seed/ts-sdk/file-upload/no-custom-config/snippet.json +++ b/seed/ts-sdk/file-upload/no-custom-config/snippet.json @@ -32,6 +32,17 @@ "type": "typescript", "client": "import { SeedFileUploadClient } from \"@fern/file-upload\";\nimport * as fs from \"fs\";\n\nconst client = new SeedFileUploadClient({ environment: \"YOUR_BASE_URL\" });\nawait client.service.justFileWithQueryParams(fs.createReadStream(\"/path/to/your/file\"), {\n maybeString: \"string\",\n integer: 1,\n maybeInteger: 1,\n listOfStrings: \"string\",\n optionalListOfStrings: \"string\"\n});\n" } + }, + { + "id": { + "path": "/with-content-type", + "method": "POST", + "identifier_override": "endpoint_service.withContentType" + }, + "snippet": { + "type": "typescript", + "client": "import { SeedFileUploadClient } from \"@fern/file-upload\";\nimport * as fs from \"fs\";\n\nconst client = new SeedFileUploadClient({ environment: \"YOUR_BASE_URL\" });\nawait client.service.withContentType(fs.createReadStream(\"/path/to/your/file\"), {});\n" + } } ], "types": {} diff --git a/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/Client.ts b/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/Client.ts index efa178203d2..c93359af6d0 100644 --- a/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/Client.ts +++ b/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/Client.ts @@ -292,4 +292,67 @@ export class Service { }); } } + + /** + * @param {File | fs.ReadStream | Blob} file + * @param {SeedFileUpload.WithContentTypeRequest} request + * @param {Service.RequestOptions} requestOptions - Request-specific configuration. + * + * @example + * await client.service.withContentType(fs.createReadStream("/path/to/your/file"), {}) + */ + public async withContentType( + file: File | fs.ReadStream | Blob, + request: SeedFileUpload.WithContentTypeRequest, + requestOptions?: Service.RequestOptions + ): Promise { + const _request = await core.newFormData(); + await _request.appendFile("file", file); + await _request.append("foo", request.foo); + await _request.append("bar", JSON.stringify(request.bar)); + const _maybeEncodedRequest = await _request.getRequest(); + const _response = await core.fetcher({ + url: urlJoin(await core.Supplier.get(this._options.environment), "/with-content-type"), + method: "POST", + headers: { + "X-Fern-Language": "JavaScript", + "X-Fern-SDK-Name": "@fern/file-upload", + "X-Fern-SDK-Version": "0.0.1", + "User-Agent": "@fern/file-upload/0.0.1", + "X-Fern-Runtime": core.RUNTIME.type, + "X-Fern-Runtime-Version": core.RUNTIME.version, + ..._maybeEncodedRequest.headers, + }, + requestType: "file", + duplex: _maybeEncodedRequest.duplex, + body: _maybeEncodedRequest.body, + timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 60000, + maxRetries: requestOptions?.maxRetries, + abortSignal: requestOptions?.abortSignal, + }); + if (_response.ok) { + return; + } + + if (_response.error.reason === "status-code") { + throw new errors.SeedFileUploadError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + }); + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.SeedFileUploadError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + }); + case "timeout": + throw new errors.SeedFileUploadTimeoutError(); + case "unknown": + throw new errors.SeedFileUploadError({ + message: _response.error.errorMessage, + }); + } + } } diff --git a/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/requests/WithContentTypeRequest.ts b/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/requests/WithContentTypeRequest.ts new file mode 100644 index 00000000000..39412ff8cba --- /dev/null +++ b/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/requests/WithContentTypeRequest.ts @@ -0,0 +1,14 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as SeedFileUpload from "../../../../index"; + +/** + * @example + * {} + */ +export interface WithContentTypeRequest { + foo: string; + bar: SeedFileUpload.MyObject; +} diff --git a/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/requests/index.ts b/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/requests/index.ts index be8a3111621..f7394273ab4 100644 --- a/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/requests/index.ts +++ b/seed/ts-sdk/file-upload/no-custom-config/src/api/resources/service/client/requests/index.ts @@ -1,3 +1,4 @@ export { type MyRequest } from "./MyRequest"; export { type JustFileRequet } from "./JustFileRequet"; export { type JustFileWithQueryParamsRequet } from "./JustFileWithQueryParamsRequet"; +export { type WithContentTypeRequest } from "./WithContentTypeRequest"; diff --git a/seed/ts-sdk/file-upload/no-custom-config/src/index.ts b/seed/ts-sdk/file-upload/no-custom-config/src/index.ts index 4f25f9eb15c..46990513b69 100644 --- a/seed/ts-sdk/file-upload/no-custom-config/src/index.ts +++ b/seed/ts-sdk/file-upload/no-custom-config/src/index.ts @@ -1,4 +1,3 @@ export * as SeedFileUpload from "./api"; export { SeedFileUploadClient } from "./Client"; export { SeedFileUploadError, SeedFileUploadTimeoutError } from "./errors"; -export * as serializers from "./serialization"; diff --git a/seed/ts-sdk/file-upload/wrap-file-properties/.mock/definition/service.yml b/seed/ts-sdk/file-upload/wrap-file-properties/.mock/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/seed/ts-sdk/file-upload/wrap-file-properties/.mock/definition/service.yml +++ b/seed/ts-sdk/file-upload/wrap-file-properties/.mock/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string diff --git a/seed/ts-sdk/file-upload/wrap-file-properties/reference.md b/seed/ts-sdk/file-upload/wrap-file-properties/reference.md index df566867b59..dd259a4c971 100644 --- a/seed/ts-sdk/file-upload/wrap-file-properties/reference.md +++ b/seed/ts-sdk/file-upload/wrap-file-properties/reference.md @@ -157,3 +157,53 @@ await client.service.justFileWithQueryParams({ + +
client.service.withContentType({ ...params }) -> void +
+
+ +#### 🔌 Usage + +
+
+ +
+
+ +```typescript +await client.service.withContentType({ + file: fs.createReadStream("/path/to/your/file"), +}); +``` + +
+
+
+
+ +#### ⚙️ Parameters + +
+
+ +
+
+ +**request:** `SeedFileUpload.WithContentTypeRequest` + +
+
+ +
+
+ +**requestOptions:** `Service.RequestOptions` + +
+
+
+
+ +
+
+
diff --git a/seed/ts-sdk/file-upload/wrap-file-properties/resolved-snippet-templates.md b/seed/ts-sdk/file-upload/wrap-file-properties/resolved-snippet-templates.md index e7480fd9a21..330887cc924 100644 --- a/seed/ts-sdk/file-upload/wrap-file-properties/resolved-snippet-templates.md +++ b/seed/ts-sdk/file-upload/wrap-file-properties/resolved-snippet-templates.md @@ -31,3 +31,12 @@ await client.service.justFileWithQueryParams({ ``` +```typescript +import { SeedFileUploadClient } from "@fern/file-upload"; + +const client = new SeedFileUploadClient({ environment: "YOUR_BASE_URL" }); +undefined; + +``` + + diff --git a/seed/ts-sdk/file-upload/wrap-file-properties/snippet-templates.json b/seed/ts-sdk/file-upload/wrap-file-properties/snippet-templates.json index b220a87eda1..b1c7537ed7e 100644 --- a/seed/ts-sdk/file-upload/wrap-file-properties/snippet-templates.json +++ b/seed/ts-sdk/file-upload/wrap-file-properties/snippet-templates.json @@ -565,5 +565,135 @@ }, "type": "v1" } + }, + { + "sdk": { + "package": "@fern/file-upload", + "version": "0.0.1", + "type": "typescript" + }, + "endpointId": { + "path": "/with-content-type", + "method": "POST", + "identifierOverride": "endpoint_service.withContentType" + }, + "snippetTemplate": { + "clientInstantiation": { + "imports": [ + "import { SeedFileUploadClient } from \"@fern/file-upload\";" + ], + "templateString": "const client = new SeedFileUploadClient($FERN_INPUT);", + "isOptional": false, + "inputDelimiter": ",", + "templateInputs": [ + { + "value": { + "imports": [], + "templateString": "{ $FERN_INPUT }", + "isOptional": true, + "templateInputs": [ + { + "value": { + "imports": [], + "templateString": "environment: \"YOUR_BASE_URL\"", + "isOptional": false, + "templateInputs": [], + "type": "generic" + }, + "type": "template" + } + ], + "type": "generic" + }, + "type": "template" + } + ], + "type": "generic" + }, + "functionInvocation": { + "imports": [], + "templateString": "await client.service.withContentType(\n\t$FERN_INPUT\n)", + "isOptional": false, + "inputDelimiter": ",\n\t", + "templateInputs": [ + { + "value": { + "imports": [], + "templateString": "{\n\t\t$FERN_INPUT\n\t}", + "isOptional": true, + "inputDelimiter": ",\n\t\t", + "templateInputs": [ + { + "value": { + "imports": [ + "import fs from \"fs\";" + ], + "templateString": "file: fs.createReadStream('$FERN_INPUT')", + "isOptional": false, + "templateInputs": [ + { + "location": "BODY", + "path": "file", + "type": "payload" + } + ], + "type": "generic" + }, + "type": "template" + }, + { + "value": { + "imports": [], + "templateString": "foo: $FERN_INPUT", + "isOptional": true, + "templateInputs": [ + { + "location": "BODY", + "path": "foo", + "type": "payload" + } + ], + "type": "generic" + }, + "type": "template" + }, + { + "value": { + "imports": [], + "templateString": "bar: {\n\t\t\t$FERN_INPUT\n\t\t}", + "isOptional": true, + "inputDelimiter": ",\n\t\t\t", + "templateInputs": [ + { + "value": { + "imports": [], + "templateString": "foo: $FERN_INPUT", + "isOptional": true, + "templateInputs": [ + { + "location": "BODY", + "path": "bar.foo", + "type": "payload" + } + ], + "type": "generic" + }, + "type": "template" + } + ], + "type": "generic" + }, + "type": "template" + } + ], + "type": "generic" + }, + "type": "template" + } + ], + "type": "generic" + }, + "type": "v1" + } } ] \ No newline at end of file diff --git a/seed/ts-sdk/file-upload/wrap-file-properties/snippet.json b/seed/ts-sdk/file-upload/wrap-file-properties/snippet.json index 1124dd377c9..2105335623d 100644 --- a/seed/ts-sdk/file-upload/wrap-file-properties/snippet.json +++ b/seed/ts-sdk/file-upload/wrap-file-properties/snippet.json @@ -32,6 +32,17 @@ "type": "typescript", "client": "import { SeedFileUploadClient } from \"@fern/file-upload\";\nimport * as fs from \"fs\";\n\nconst client = new SeedFileUploadClient({ environment: \"YOUR_BASE_URL\" });\nawait client.service.justFileWithQueryParams({\n file: fs.createReadStream(\"/path/to/your/file\"),\n maybeString: \"string\",\n integer: 1,\n maybeInteger: 1,\n listOfStrings: \"string\",\n optionalListOfStrings: \"string\"\n});\n" } + }, + { + "id": { + "path": "/with-content-type", + "method": "POST", + "identifier_override": "endpoint_service.withContentType" + }, + "snippet": { + "type": "typescript", + "client": "import { SeedFileUploadClient } from \"@fern/file-upload\";\nimport * as fs from \"fs\";\n\nconst client = new SeedFileUploadClient({ environment: \"YOUR_BASE_URL\" });\nawait client.service.withContentType({\n file: fs.createReadStream(\"/path/to/your/file\")\n});\n" + } } ], "types": {} diff --git a/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/Client.ts b/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/Client.ts index 09c5fb4d43c..fdcf7355512 100644 --- a/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/Client.ts +++ b/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/Client.ts @@ -287,4 +287,67 @@ export class Service { }); } } + + /** + * @param {SeedFileUpload.WithContentTypeRequest} request + * @param {Service.RequestOptions} requestOptions - Request-specific configuration. + * + * @example + * await client.service.withContentType({ + * file: fs.createReadStream("/path/to/your/file") + * }) + */ + public async withContentType( + request: SeedFileUpload.WithContentTypeRequest, + requestOptions?: Service.RequestOptions + ): Promise { + const _request = await core.newFormData(); + await _request.appendFile("file", request.file); + await _request.append("foo", request.foo); + await _request.append("bar", JSON.stringify(request.bar)); + const _maybeEncodedRequest = await _request.getRequest(); + const _response = await core.fetcher({ + url: urlJoin(await core.Supplier.get(this._options.environment), "/with-content-type"), + method: "POST", + headers: { + "X-Fern-Language": "JavaScript", + "X-Fern-SDK-Name": "@fern/file-upload", + "X-Fern-SDK-Version": "0.0.1", + "User-Agent": "@fern/file-upload/0.0.1", + "X-Fern-Runtime": core.RUNTIME.type, + "X-Fern-Runtime-Version": core.RUNTIME.version, + ..._maybeEncodedRequest.headers, + }, + requestType: "file", + duplex: _maybeEncodedRequest.duplex, + body: _maybeEncodedRequest.body, + timeoutMs: requestOptions?.timeoutInSeconds != null ? requestOptions.timeoutInSeconds * 1000 : 60000, + maxRetries: requestOptions?.maxRetries, + abortSignal: requestOptions?.abortSignal, + }); + if (_response.ok) { + return; + } + + if (_response.error.reason === "status-code") { + throw new errors.SeedFileUploadError({ + statusCode: _response.error.statusCode, + body: _response.error.body, + }); + } + + switch (_response.error.reason) { + case "non-json": + throw new errors.SeedFileUploadError({ + statusCode: _response.error.statusCode, + body: _response.error.rawBody, + }); + case "timeout": + throw new errors.SeedFileUploadTimeoutError(); + case "unknown": + throw new errors.SeedFileUploadError({ + message: _response.error.errorMessage, + }); + } + } } diff --git a/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/requests/WithContentTypeRequest.ts b/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/requests/WithContentTypeRequest.ts new file mode 100644 index 00000000000..9f4d8bbe5be --- /dev/null +++ b/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/requests/WithContentTypeRequest.ts @@ -0,0 +1,18 @@ +/** + * This file was auto-generated by Fern from our API Definition. + */ + +import * as fs from "fs"; +import * as SeedFileUpload from "../../../../index"; + +/** + * @example + * { + * file: fs.createReadStream("/path/to/your/file") + * } + */ +export interface WithContentTypeRequest { + file: File | fs.ReadStream | Blob; + foo: string; + bar: SeedFileUpload.MyObject; +} diff --git a/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/requests/index.ts b/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/requests/index.ts index be8a3111621..f7394273ab4 100644 --- a/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/requests/index.ts +++ b/seed/ts-sdk/file-upload/wrap-file-properties/src/api/resources/service/client/requests/index.ts @@ -1,3 +1,4 @@ export { type MyRequest } from "./MyRequest"; export { type JustFileRequet } from "./JustFileRequet"; export { type JustFileWithQueryParamsRequet } from "./JustFileWithQueryParamsRequet"; +export { type WithContentTypeRequest } from "./WithContentTypeRequest"; diff --git a/seed/ts-sdk/file-upload/wrap-file-properties/src/index.ts b/seed/ts-sdk/file-upload/wrap-file-properties/src/index.ts index 4f25f9eb15c..46990513b69 100644 --- a/seed/ts-sdk/file-upload/wrap-file-properties/src/index.ts +++ b/seed/ts-sdk/file-upload/wrap-file-properties/src/index.ts @@ -1,4 +1,3 @@ export * as SeedFileUpload from "./api"; export { SeedFileUploadClient } from "./Client"; export { SeedFileUploadError, SeedFileUploadTimeoutError } from "./errors"; -export * as serializers from "./serialization"; diff --git a/seed/ts-sdk/seed.yml b/seed/ts-sdk/seed.yml index 79b2c9f3a8c..d0bf132779f 100644 --- a/seed/ts-sdk/seed.yml +++ b/seed/ts-sdk/seed.yml @@ -210,7 +210,6 @@ scripts: - docker: fernapi/ts-seed commands: - mkdir cache - - cp -r /yarn-cache-template ./cache - yarn install --cache-folder ./cache - yarn build - if grep -q '"test"' package.json && grep -q 'exhaustive' package.json; then yarn test --passWithNoTests --testPathPattern='exhaustive.*\.test\.ts$'; fi diff --git a/test-definitions/fern/apis/file-upload/definition/service.yml b/test-definitions/fern/apis/file-upload/definition/service.yml index cdd6a993b6b..6902d24f3ff 100644 --- a/test-definitions/fern/apis/file-upload/definition/service.yml +++ b/test-definitions/fern/apis/file-upload/definition/service.yml @@ -49,6 +49,19 @@ service: body: properties: file: file + + withContentType: + path: "/with-content-type" + method: POST + request: + name: WithContentTypeRequest + body: + properties: + file: file + foo: string + bar: + type: MyObject + content-type: application/json types: Id: string