Skip to content

Add a JSON API to list and create social media snippets - #43

Merged
etagwerker merged 3 commits into
mainfrom
feature/social-media-snippets-api
Nov 9, 2026
Merged

etagwerker merged 3 commits into
mainfrom
feature/social-media-snippets-api

Conversation

@etagwerker

@etagwerker etagwerker commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Closes #42.

Since #39 removed the ChatGPT step, nothing writes new social media snippets, and there is no API for them. This gives snippets the same Bearer-token JSON API that shares already have, so a client can store copy next to the article it belongs to. The table already has the columns it needs, so there is no migration.

What it adds

  • GET /links/:link_id/social_media_snippets.json lists a link's snippets, oldest first. ?social_media_type=LinkedIn narrows it to one network.
  • POST /links/:link_id/social_media_snippets.json creates one. It takes social_media_type and content. A JSON body works with or without the social_media_snippet wrapper key.
  • Both endpoints are on the Bearer-token whitelist in ApplicationController, the same way shares is. A cookie-authenticated browser still gets a 401 on JSON.
  • The link page no longer says its snippets "are created by Open AI". That stopped being true when Remove ChatGPT integration and stop generating social media snippets #39 removed the ChatGPT step, and snippets can now come from the API. The copy now reads "Suggested copy for posting this article. Pair each snippet with one of the shortened links above." It's a one-line change in links/show.html.erb, with a small view spec.

Responses follow what shares do: 201 with the snippet, 422 with { "errors": [...] }.

{ "id": 1, "link_id": 7, "social_media_type": "LinkedIn", "content": "...", "created_at": "..." }

What gets a 422

  • a missing or unknown social_media_type (it has to be one of Bluesky, GoogleBusiness, LinkedIn, Mastodon, Twitter, spelled that way)
  • blank content
  • an exact duplicate: the same content for the same link and type, so a client can retry a request safely

Things I'd like a second opinion on

  • No unique index for duplicates. The check is a model validation. The table already holds snippets from the old ChatGPT step, and a unique index could fail on duplicates in production. The catch is that two identical requests sent at the same instant could both pass. Is that fine?
  • social_media_type is now required. The model allowed it to be blank before. Copy varies by network (length, style, tone), and the link page groups snippets by network, so one without a network doesn't make sense for new snippets.
  • The new checks run on create only, like Share's UTM checks, so existing snippets, whatever their type, can still be edited.
  • The list of types is the five from the issue. Share::UTM_SOURCES has more networks. Happy to align them if you'd rather.

Not in this PR

Updating or deleting snippets, and any HTML view (these endpoints are JSON only).

Testing

bundle exec rspec spec: 83 examples, 0 failures (54 before, 29 new). The request specs cover auth (no token, bad token, cookie only), validation, filtering, and JSON bodies, and a view spec covers the link page section. In the test environment Rails raises for an unknown link (RecordNotFound) or missing params (ParameterMissing) instead of rendering a 404 or 400, so those specs assert the exception.

🤖 Generated with Claude Code

etagwerker and others added 3 commits November 8, 2026 22:58
Since #39 removed the ChatGPT step, nothing writes new social media
snippets and there is no API for them. This adds the same Bearer-token
JSON API shares already have:

  GET  /links/:link_id/social_media_snippets.json
       (optional ?social_media_type= filter)
  POST /links/:link_id/social_media_snippets.json

A snippet takes social_media_type (Bluesky, GoogleBusiness, LinkedIn,
Mastodon, Twitter), content, and an optional share_id that ties the copy
to the tracked short URL it was posted with. share_id is a new nullable
reference on social_media_snippets; deleting a share nullifies it.

Creating a snippet is rejected with a 422 when the type is missing or
unknown, when the same content already exists for that link and type, or
when share_id points at a share that doesn't exist or belongs to another
link. The type, duplicate, and presence checks run on create only, so
snippets saved before this change stay editable.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The Social Media Snippets section told readers the snippets are created
by Open AI. That stopped being true when #39 removed the ChatGPT step,
and snippets can now be stored over the JSON API, so it's wrong for new
ones too. The copy no longer says where a snippet came from, and points
to the shortened links in the Shares section above it.

Adds a view spec for the section: snippets are listed under their social
media type, the Open AI claim is gone, and the section is left out when
a link has no snippets.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
social_media_snippets already has the columns the API needs
(social_media_type, content, link_id), so this PR shouldn't change the
table. Removes the share_id migration and schema change, the share
association and its validations, the share_id param and JSON key, and
the specs that covered them.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@etagwerker
etagwerker marked this pull request as ready for review November 9, 2026 04:13
@etagwerker
etagwerker merged commit c5a37c9 into main Nov 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a JSON API to create social media snippets for a link

1 participant