Skip to content

Commit 8518940

Browse files
authored
Merge pull request #179 from notJoon/fix/issue-177
fix(api): Accept null values for optional fields in /api/v1/statuses endpoin
2 parents c3f3c1f + 212cdbc commit 8518940

3 files changed

Lines changed: 55 additions & 10 deletions

File tree

src/api/v1/statuses.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,45 @@ describe.sequential("/api/v1/accounts/verify_credentials", () => {
169169
expect(typeof updateJson).toBe("object");
170170
expect(updateJson.content).toBe("<p>Test Update</p>\n");
171171
});
172+
173+
it("Issue 177: successfully creates a status with null values, setting appropriate defaults", async () => {
174+
const body = JSON.stringify({
175+
language: null,
176+
status: "Awoo!",
177+
in_reply_to_id: null,
178+
sensitive: false,
179+
spoiler_text: null,
180+
media_ids: null,
181+
visibility: null,
182+
poll: null,
183+
});
184+
185+
const response = await app.request("/api/v1/statuses", {
186+
method: "POST",
187+
headers: {
188+
authorization: bearerAuthorization(accessToken),
189+
"Content-Type": "application/json",
190+
},
191+
body: body,
192+
});
193+
194+
expect(response.status).toBe(200);
195+
expect(response.headers.get("content-type")).toBe("application/json");
196+
197+
const json = await response.json();
198+
expect(typeof json).toBe("object");
199+
200+
// Basic creation success
201+
expect(json.content).toBe("<p>Awoo!</p>\n");
202+
expect(json.account.id).toBe(account.id);
203+
204+
// Verify null values are replaced with appropriate defaults
205+
expect(json.visibility).not.toBeNull();
206+
expect(json.visibility).toBe("public");
207+
expect(json.spoiler_text).toBe("");
208+
expect(json.media_attachments).toEqual([]);
209+
expect(json.sensitive).toBe(false);
210+
expect(json.language).not.toBeNull();
211+
expect(json.poll).toBeNull(); // This one stays null as expected
212+
});
172213
});

src/api/v1/statuses.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ function buildMuteAndBlockConditions(viewerAccountId: Uuid | null | undefined) {
160160
}
161161

162162
const statusSchema = z.object({
163-
status: z.string().min(1).optional(),
164-
media_ids: z.array(uuid).optional(),
163+
status: z.string().min(1).optional().nullable(),
164+
media_ids: z.array(uuid).optional().nullable(),
165165
poll: z
166166
.object({
167167
options: z.array(z.string()),
@@ -175,18 +175,22 @@ const statusSchema = z.object({
175175
multiple: z.boolean().default(false),
176176
hide_totals: z.boolean().default(false),
177177
})
178-
.optional(),
178+
.optional()
179+
.nullable(),
179180
sensitive: z.boolean().default(false),
180-
spoiler_text: z.string().optional(),
181-
language: z.string().min(2).optional(),
181+
spoiler_text: z.string().optional().nullable(),
182+
language: z.string().min(2).optional().nullable(),
182183
});
183184

184185
const createStatusSchema = statusSchema.merge(
185186
z.object({
186-
in_reply_to_id: uuid.optional(),
187-
quote_id: uuid.optional(),
188-
visibility: z.enum(["public", "unlisted", "private", "direct"]).optional(),
189-
scheduled_at: z.string().datetime().optional(),
187+
in_reply_to_id: uuid.optional().nullable(),
188+
quote_id: uuid.optional().nullable(),
189+
visibility: z
190+
.enum(["public", "unlisted", "private", "direct"])
191+
.optional()
192+
.nullable(),
193+
scheduled_at: z.string().datetime().optional().nullable(),
190194
}),
191195
);
192196

src/text.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ export async function formatPostContent(
272272
ExtractTablesWithRelations<typeof schema>
273273
>,
274274
text: string,
275-
language: string | undefined,
275+
language: string | null | undefined,
276276
options: {
277277
url: URL | string;
278278
contextLoader?: DocumentLoader;

0 commit comments

Comments
 (0)