Category: REST API

  • How I Built WordUp: A Guide to Creating a macOS App

    I realized recently that I don’t do nearly enough about sharing some of the cool things I build. Or blogging. I don’t do nearly enough of either.

    TL;DR: I just shipped my very first macOS desktop app called WordUp.

    https://github.com/georgestephanis/WordUp/releases/tag/v0.2.1

    I’ve used some desktop apps, such as CloudApp (now Zight) and CloudUp (which was acquired shortly after I joined Automattic) in years past. The basic gist is, they live in your computer’s menu bar, and when you either take a screenshot or drag an image onto the icon, it will upload it to their service and give you a handy URL that you can use to share the asset with a client, or a user, or whatever you may need.

    Hugely useful! A modern-day analogue may be something like Loom, I suppose?

    Anyway, at their most basic, these programs do a few relatively trivial things:

    1. Notice when a screenshot is taken or an image is requested to be uploaded,
    2. Upload it to a cloud server for sharing, and
    3. Automatically drop a link to the asset onto your clipboard.

    Well, I’ve wondered for years why this is something that folks need an external company to do. I work with WordPress daily, and I love open-source software! Why can’t an app just connect to your WordPress site and use that as the remote server for hosting the assets?

    No image limits, you own your own data and content, and no need for your usage or credentials to pass through anyone else’s servers.

    My only problem? I’m a web developer, and I have no idea how to work with building desktop apps.

    So I’ve spent the past decade periodically starting conversations with folks in the Apps teams while I worked at Automattic, asking if anyone would be interested in throwing it together or porting over the CloudUp desktop app functionality to also connect to self-hosted WordPress sites. Didn’t get any takers. So I stopped asking, as I really didn’t want to turn into Glootie.

    The other week when it happened to come up and I mentioned it to (fellow ex-Automattician) Jorge Leandro Perez, he suggested that I try to make it myself, using AI-based tooling with Cursor.

    A minor digression: Thoughts and feelings on large language models and generative AI are complex, with outspoken individuals on all sides. I tend to be middle-of-the-road and may use them here and there — but selectively. I should probably write a bigger post on my thoughts when it comes to generative AI soon.

    I wound up delving in, and through a lot of refinement and debugging (including a decent bit of learning Swift and manually rewriting bits where AI got the APIs it was trying to use wrong), I finally got something in a state that I was pleased with.

    A couple of caveats, though:

    • Authentication currently works with self-hosted sites and leverages the WordPress REST API through Application Passwords.
      • As it uses Application Passwords for authentication, if you’re using a security plugin such as Wordfence or others, they may be disabling Application Passwords on your website by default — you’ll need to re-enable it in their settings panel for this to work.
      • I’d like to eventually integrate it with WordPress.com’s REST API, but that’ll involve app keys and secrets for its authentication system, as WordPress.com doesn’t support the same implementation of Application Passwords that the open-source WordPress project provides (and also doesn’t support the authorize-application.php workflow that I’m using). So, maybe in the near future.
    • It can’t upload any media that your WordPress site isn’t configured to allow. So, by default, no SVG assets (as an example).
    • You can only authenticate to a single WordPress site. I’d like to eventually let you authenticate to multiple, and then you can change which one it uploads to in settings, but that’s not there currently (as I wanted to keep the UX simple).
    • I’m not a UX designer. At all! I made something functional that I thought looked … good enough? If anyone else would like to chip in, feel free! I’d gladly welcome input.

    How Using Generative AI / “Vibe” Coding Worked Out

    Honestly, it worked alright. There were numerous sequential prompts to develop an idea, telling it that its code was generating errors, and sometimes it would get balled up into a loop, and I’d have to go in and manually debug.

    But it worked pretty well to get a quick first pass built. I think I’d have had a much harder time with it if I wasn’t already comfortable with the system it was trying to integrate with, as well as other programming languages. Plenty of concepts translate well between programming languages; it’s just different syntax to implement them — so being able to leverage generative AI to take something I’m able to be very specific with and describe clearly and then build it out into a functional project was hugely beneficial.

    It feels like it’s shifting from the importance of being an expert in the programming language itself to being able to think through problems and use pseudo-code to describe the problem and solution well enough and let generative AI handle the implementation (even if it often gets it wrong).

    It’s an interesting time to be in software development, and I’m curious to see how else this sort of tech impacts the ecosystem. Just as StackOverflow and Google shifted the importance of “knowing” things to being able to find the answer, it feels like generative AI is going to emphasize the ability to think about a problem and find novel solutions and using developers to review code to polish it up for performance and security, instead of the nitty-gritty of implementations.

    Is this useful to you? Are there other ways that you’d like to be able to integrate things with your WordPress site but aren’t sure how to build a linkage? Let’s talk about the options in the comments below! 👇🏼

  • WP REST API vs GraphQL Performance

    A client had recently pointed out to me a post detailing performance differences between the REST API that ships in WordPress Core, and WPGraphQL —

    https://www.wpgraphql.com/docs/wpgraphql-vs-wp-rest-api#performance

    In it, it asserts that the difference between two similar queries running the REST API and WPGraphQL yields vastly different performance impacts:

    Below are screenshots of the same WordPress site asking for 100 posts from the WP REST API and 100 posts from WPGraphQL with the Chrome network tab open.

    REST:

    • Download size: 335 kb
    • Time: 7.91s

    WPGraphQL

    • Download size: 6.4 kb
    • Time: 67 ms

    That seemed like an unrealistic difference from an initial glance — the REST API takes over 100x longer to return data than WPGraphQL? I wanted to check and see if I could duplicate the test and find out what accounted for the orders of magnitude difference between the two.

    (more…)
    Fediverse Reactions
  • On Core REST API Authentication

    Having an API is well and good, but if there are no ways for third-party apps to actually authenticate and use the API, it’s not very useful.

    Background

    While the framework for the REST API was merged into WordPress Core with the 4.4 release, the only means of using any endpoints that currently require authentication are what is known as ‘cookie authentication’ — that is, piggybacking off of the authentication cookies (plus a nonce) that WordPress Core sets in the browser when you log in traditionally to your WordPress site.  Unfortunately, that leaves the REST API as little more useful than the legacy `admin-ajax.php` file.

    Fortunately, there are several authentication methods being worked on at the moment, in plugin form, for consideration of merging in to Core.

    I’m heading up one of them, called Application Passwords.  In short, it lets a user generate as many single-application passwords as desired — one for each phone, desktop app, or other integration desired — and later revoke any application password whenever desired without affecting other applications or the user’s normal authentication.  The passwords are then passed with each request as Basic Authentication, encoded in the header of each request, as per RFC2617.

    The other plugin is OAuth 1.0a authentication (spec).  Most OAuth usage across the internet is actually OAuth 2.0 — however, OAuth 2.0 requires HTTPS on the server side.  Ordinarily for most hosted services, this is not a problem.  However, for a distributed platform like WordPress, this is untenable due to the majority of sites not supporting HTTPS.  So an older, more complex specification — designed to not require HTTPS — had to be used.

    For the record, I’m fully expecting to see an OAuth 2.0 plugin be built in the near future for use on sites that have a SSL certificate and support HTTPS.  However, that may not be very useful for app developers that want a ‘build once, run everywhere’ authentication method that will always be available.

    Limiting Permissions

    One of the discussions that came up with regard to Application Passwords is whether a REST API request that uses Application Password authentication should be able to modify Application Password endpoints.

    Now, this is a very interesting question, and it can lead to many more questions — such as if an Application Password shouldn’t be usable to create or delete other Application Passwords, whether they should be allowed to do other user-administrative tasks (providing the relevant user has those permissions).  After all, if we’re preventing them from making a new Application Password, but they can just go and change the user’s actual password or email address, it’s a rather silly restriction.

    So, there are several possiblilities.

    First, you can just say “Any ways in to your account give full access to everything your account can do.  Be careful what applications and websites you give access to.” — the most basic, relatively easy to understand way.  Honestly, this is my preference.

    Secondly, when creating a new Application Password or connecting a new client via oAuth, you could do something like … selecting what ‘role’ you’d like to give that connection.  For example, if your normal user account as an Administrator, but you’re connecting an app that’s intended just for writing blog posts, you may want to downscale your role for that authentication key to either an Author or perhaps an Editor.  An advantage to this is that it would be more cross-API — that is, it would work just as well with the legacy XML-RPC API, as with the new REST API.

    This ‘role restriction’ method may be somewhat fragile, as it would need to only filter `current_user_can` and `user_can` — but only when checking the current user’s ID.  However, that may goof up some cron tasks that may run on the same request as the REST API request or other incendtal things.

    Thirdly, we could do something REST API specific — either whitelist or blacklist REST API endpoints based on authentication key.  So, when either creating a new Application Password or authorizing a new OAuth connection, you would set rules as to what endpoints it can be used to hit.  Perhaps you’d want to allow all `wp/v2` namespaced endpoints, but no endpoints added by plugins to custom namespaces.  Or you want to only allow it to access core `posts` and `taxonomies` endpoints.  Or even something like allowing it to access anything but `plugins`, `themes`, `users`, or `options` endpoints.

    The downside of this is that it won’t work with the legacy XML-RPC API and the user interface for it would likely be far more confusing for users.  It also could get problematic as permissions may vary for who can read `options` endpoints and who can write to them — or the like.  So then it may further complicate to allowing GET requests but not POST, PUT, DELETE requests to certain endpoints.

    Your Thoughts?

    In the end, I’m not sure what the best path forward is.  Maybe I’ve missed something.  But I am confident that we need to start paying more attention to authentication and permissions for the forthcoming REST API.  If you have any thoughts or remarks, please leave them in the comments.