From 899f6364038721b72feb4174cb912748c8c5d1e6 Mon Sep 17 00:00:00 2001 From: Johnny Steenbergen Date: Fri, 19 Jan 2024 05:10:32 -0600 Subject: [PATCH] chore(allsrv): add deprecation headers to the v1 endpoints This is simple enough to add and may go largely unnoticed, but if you control the SDK/client, then you are capable of throwing warning/errors based on the deprecation headers in the response. If it's a while before the deprecation deadline, then warn the user, if it's past due... start throwing some error logs if the endpoints continue to work. There is no guarantee the endpoint will remain available. This is a really hard problem. In an ideal world, you own the sdk your consumers use to interact with your API. This is an excellent place to be because you can add the glue necessary to transition APIs. Please decorate your SDKs with useful origin and user agent headers so you're able to target your deprecation efforts. Here's a look at an example log that gives us useful `Origin` and `User-Agent` our SDK would add to help us transition external teams utilizing the SDK: ```json { "level": "INFO", "trace_id": "$TRACE_ID", "user_id": "$USER_ID", "name": "allsrvd.svc", "foo_id": "$FOO_ID", "origin": "$OTHER_TEAM_SERVICE_NAME", "user-agent": "allsrvc (github.com/jsteenb2/allsrvc) / v0.4.0", "msg": "foo deleted successfully" } ``` Knowing who you are serving and what versions of your SDK are being used is insanely helpful. They only have to approve and merge it once if their tests pass. With the log above, you can use your logging infrastructure to visualize what teams are doing with your service and how dated their integrations might be by utilizing the `User-Agent`. The origin helps you track what services are hitting you as well `:chef_kiss:`. You can simplify the work for your internal teams by updating their code to the newest version and cutting them a PR. That's how to be considerate of your fellow teams while improving your own situation! We'll go over an example of how to decorate your SDKs with the information above in a latercommmit. If you're relying on an OpenAPI spec, just be warned, if your clients have to generate from that OpenAPI spec... and you have multiple similar endpoints defined in that OpenAPI spec... your users may be scratching their heads with which one to use. Some due diligence and a mountain of patience goes a long way. Now that we've established our upcoming deprecations, let's take aim at improving our database story. Say we want to create a SQL DB or some new integration. Where do we start? Take a moment to work through the next steps. We'll then move onto adopting a sqlite db implementation. This should cause zero changes to the server, and should be 100% dependency injected into the servers same as the in-mem db is being done now. --- allsrv/server.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/allsrv/server.go b/allsrv/server.go index a64f7f6..15580ca 100644 --- a/allsrv/server.go +++ b/allsrv/server.go @@ -123,13 +123,13 @@ func NewServer(db DB, opts ...func(*serverOpts)) *Server { } func (s *Server) routes() { - authMW := s.authFn // 2) + mw := applyMW(s.authFn, deprecationHeaders) // 2) // 4) 7) 9) 10) - s.mux.Handle("POST /foo", authMW(http.HandlerFunc(s.createFoo))) - s.mux.Handle("GET /foo", authMW(http.HandlerFunc(s.readFoo))) - s.mux.Handle("PUT /foo", authMW(http.HandlerFunc(s.updateFoo))) - s.mux.Handle("DELETE /foo", authMW(http.HandlerFunc(s.delFoo))) + s.mux.Handle("POST /foo", mw(http.HandlerFunc(s.createFoo))) + s.mux.Handle("GET /foo", mw(http.HandlerFunc(s.readFoo))) + s.mux.Handle("PUT /foo", mw(http.HandlerFunc(s.updateFoo))) + s.mux.Handle("DELETE /foo", mw(http.HandlerFunc(s.delFoo))) } func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -211,3 +211,10 @@ func basicAuth(expectedUser, expectedPass string) func(http.Handler) http.Handle }) } } + +func deprecationHeaders(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Deprecation", "Fri, 26 July 2024 23:59:59 GMT") + next.ServeHTTP(w, r) + }) +}