Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Necessity to have a RESTful API #1

Open
sarbogast opened this issue Sep 9, 2020 · 8 comments
Open

Necessity to have a RESTful API #1

sarbogast opened this issue Sep 9, 2020 · 8 comments

Comments

@sarbogast
Copy link

sarbogast commented Sep 9, 2020

HTTP APIs are complex because you can do pretty much anything and it's hard to specify and document. And that's why conventions are important. And in the case of podcastindex, I think that leveraging the HTTP standard and designing a truly RESTful API is particularly important. This way, it would be more likely to become a standard built on top of another standard, something with a solid foundation, that's easy to extend and evolve.

In that regard, it's important to:

  • identify what "resources" are part of your API: in this case "podcasts" and "episodes" are the main types of resources, and "episodes" only exist within "podcasts" so they are hierarchically related (or not, if you also want to be able to retrieve episodes individually, outside of their feeds)
  • use HTTP verbs: instead of using GET everywhere and just change the URL, you should only use GET to retrieve resources, POST to create new resources, PUT or PATCH to update existing resources and so on

That's the minimum, but there are a lot of other considerations, which are perfectly summed up in this video.

Those conventions don't give an answer for every single edge case, but they give a good basis for a highly standard API that is easy to navigate, document, interact with and grow over time.

Here are some examples of how this would change the current API:

  • Retrieve all podcasts: GET /api/1.0/podcasts (probably necessary to implement some pagination there)
  • Query podcasts by term: GET /api/1.0/podcasts?q=[term]
  • Query podcasts by feedId (assuming this feed id is a unique id specific to your index): GET /api/1.0/podcasts/[feedId]
  • Query podcasts by iTunes ID: GET /api/1.0/podcasts?itunesid=[itunesid]
  • Add a podcast: POST /api/1.0/podcasts?url=[feed url] (or pass the feed url as a JSON or form-encoded body)
  • Get all episodes of a specific podcast for which we know the feed ID (again assuming that this is THE unique identifier for podcasts in your index): GET /api/1.0/podcasts/[feed id]/episodes
  • Get all episodes of a podcast for which you only have the feed url or the iTunes ID (this one is a tricky one because there are several ways to approach it depending on the use case): GET /api/1.0/podcasts/episodes?itunesid=[iTunes ID] or GET /api/1.0/episodes?itunesid=[iTunes ID]
  • Query podcasts recently updated (stick with the generic endpoint structure and play with query parameters): GET /api/1.0/podcasts?sort=lastUpdateTime&order=desc&offset=0&max=10 (sort, order, offset and max are pretty standard pagination query parameters that let you define how many results you want from what starting point, sorted by which field and in what order)

These are just some examples that would need to be expanded on if you are willing to do so. Designing APIs is part of what I do for a living so I can help. Another part of what I do is develop mobile and web apps and I wanted to dive into that, but I really think an important first step is to redesign the API if you really want to maximize adoption and evolutivity.

Just my 2 cents.

@Morgma
Copy link

Morgma commented Sep 9, 2020

I agree that establishing RESTful conventions early on is important - proper use of HTTP verbs is key. I'm a fan of structuring complex queries against OData v4 protocol (v3 support is probably advisable also), rather than having a custom convention for query structure. Many clients will consume OData v4 readily to provide filterable grids, sort, count, pagination, etc. Complex queries can optionally be passed via the HTTP body content as well, as to avoid busting the URI length for GET requests or running into encoding problems.

Make the API self-documenting, featuring an Open API 3.0 (Swagger) metadata endpoint to facilitate automatic client code generation. A web-based, interactive API browser is always a nice touch when trying to attract new developers.

The URI needs to be a short as possible while still being easily legible - for example, "api" is already in the domain, so I believe that could be removed from the stub.

The API version could either an optional query parameter or HTTP header (defaulting to the latest). I imagine the write-end of this API could face some significant breaking changes, especially early on, however, the read-end should strive to be very forward compatible - accessing beta features or pinning code to a specific release becomes a consumer option, but not a requirement.

Combined with making use of pluralization in the semantics, the API can be pretty intuitive:

GET api.podcastindex.org/podcasts
GET api.podcastindex.org/podcast/1/episodes?ver='0.1.0.254-beta'
GET api.podcastindex.org/podcast/3/episode/1

...and to scratch the query itch with something more complex, collections can be handled via OData:

GET api.podcastindex.org/podcasts?$filter=contains(name, 'Some Agenda')&$expand=episodes($filter=lastUpdateTime gt '2020-01-01')

Following on with RESTful conventions, we can really expand into quality of life improvements for developers, like enriching the response body with navigational properties to downstream entity queries - e.g. HATEOAS (Hypermedia as the Engine of Application State) - this could really help simplify client SDK development, because you can recurse through the entity definition even if the link refs have to change later on.

@daveajones
Copy link
Contributor

I know we need to be more RESTful. No doubt about that. What's in place now is basically minimum viable product to get people started. All of these comments are great. I'll start a v1.1 API layout that we can all add to. OpenAPI is laid out with YAML if I remember correctly. I think Postman has support for it.

Having a v1.1 that conforms to OpenAPI, and then leaving the current v1.0 active seems like a good balance for those that just want quick hits without full REST, and more robust platform folks.

@normand1
Copy link
Contributor

normand1 commented Sep 9, 2020

@daveajones +1 for Open API spec. I've found this tool really helpful for building out OpenAPI specs btw: https://stoplight.io/

@sarbogast
Copy link
Author

sarbogast commented Sep 9, 2020 via email

@Morgma
Copy link

Morgma commented Sep 10, 2020

@daveajones Is the server-side API code available in another repo?

@podcastindex
Copy link
Collaborator

@daveajones Is the server-side API code available in another repo?

Not yet. It's a custom framework, so let me figure out the best way to split it up and I'll put something up.

@realsircodesalot
Copy link

This looks like an interesting tool to use that could take the doctrine code comments and generate the OpenAPI/Swagger json file from our own code documentation: http://zircote.github.io/swagger-php/.

@daveajones
Copy link
Contributor

That is an interesting tool. I need to start testing that. Thank you for passing along.

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

No branches or pull requests

6 participants