diff --git a/services/crates/crates-base.js b/services/crates/crates-base.js
index 28c1af3e7eee5c26a2731e4214880152b36554d9..079f519de54826d9aa80a93d1cfeede537822519 100644
--- a/services/crates/crates-base.js
+++ b/services/crates/crates-base.js
@@ -1,36 +1,27 @@
 import Joi from 'joi'
 import { nonNegativeInteger } from '../validators.js'
-import { BaseJsonService } from '../index.js'
+import { BaseJsonService, InvalidResponse } from '../index.js'
 
-const crateSchema = Joi.object({
+const versionSchema = Joi.object({
+  downloads: nonNegativeInteger,
+  num: Joi.string().required(),
+  license: Joi.string().required().allow(null),
+  rust_version: Joi.string().allow(null),
+})
+
+const crateResponseSchema = Joi.object({
   crate: Joi.object({
     downloads: nonNegativeInteger,
     recent_downloads: nonNegativeInteger.allow(null),
     max_version: Joi.string().required(),
   }).required(),
-  versions: Joi.array()
-    .items(
-      Joi.object({
-        downloads: nonNegativeInteger,
-        license: Joi.string().required().allow(null),
-        rust_version: Joi.string().allow(null),
-      }),
-    )
-    .min(1)
-    .required(),
+  versions: Joi.array().items(versionSchema).min(1).required(),
 }).required()
 
-const versionSchema = Joi.object({
-  version: Joi.object({
-    downloads: nonNegativeInteger,
-    num: Joi.string().required(),
-    license: Joi.string().required().allow(null),
-    rust_version: Joi.string().allow(null),
-  }).required(),
+const versionResponseSchema = Joi.object({
+  version: versionSchema.required(),
 }).required()
 
-const schema = Joi.alternatives(crateSchema, versionSchema)
-
 class BaseCratesService extends BaseJsonService {
   static defaultBadgeData = { label: 'crates.io' }
 
@@ -38,8 +29,27 @@ class BaseCratesService extends BaseJsonService {
     const url = version
       ? `https://crates.io/api/v1/crates/${crate}/${version}`
       : `https://crates.io/api/v1/crates/${crate}?include=versions,downloads`
+    const schema = version ? versionResponseSchema : crateResponseSchema
     return this._requestJson({ schema, url })
   }
+
+  static getLatestVersion(response) {
+    return response.crate.max_stable_version
+      ? response.crate.max_stable_version
+      : response.crate.max_version
+  }
+
+  static getVersionObj(response) {
+    if (response.crate) {
+      const version = this.getLatestVersion(response)
+      const versionObj = response.versions.find(v => v.num === version)
+      if (versionObj === undefined) {
+        throw new InvalidResponse({ prettyMessage: 'version not found' })
+      }
+      return versionObj
+    }
+    return response.version
+  }
 }
 
 const description =
diff --git a/services/crates/crates-base.spec.js b/services/crates/crates-base.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..a68990acb132d24e6d812c65d63b9bd2ba58c746
--- /dev/null
+++ b/services/crates/crates-base.spec.js
@@ -0,0 +1,47 @@
+import { expect } from 'chai'
+import { test, given } from 'sazerac'
+import { BaseCratesService } from './crates-base.js'
+
+describe('BaseCratesService', function () {
+  describe('getLatestVersion', function () {
+    test(BaseCratesService.getLatestVersion, () => {
+      given({ crate: { max_version: '1.1.0' } }).expect('1.1.0')
+      given({
+        crate: { max_stable_version: '1.1.0', max_version: '1.9.0-alpha' },
+      }).expect('1.1.0')
+    })
+  })
+
+  describe('getVersionObj', function () {
+    const versions = [
+      /*
+      These versions are more recent, but we're going to ignore them
+      That might be because they were yanked, or because they're pre-releases.
+      */
+      { num: '1.3.0-beta' },
+      { num: '1.2.0' },
+      // this is the one we will select
+      { num: '1.1.0' },
+    ]
+
+    it('ignores more recent versions than max_stable_version', function () {
+      const response = {
+        crate: {
+          max_stable_version: '1.1.0',
+        },
+        versions,
+      }
+      expect(BaseCratesService.getVersionObj(response).num).to.equal('1.1.0')
+    })
+
+    it('ignores more recent versions than max_version', function () {
+      const response = {
+        crate: {
+          max_version: '1.1.0',
+        },
+        versions,
+      }
+      expect(BaseCratesService.getVersionObj(response).num).to.equal('1.1.0')
+    })
+  })
+})
diff --git a/services/crates/crates-downloads.service.js b/services/crates/crates-downloads.service.js
index f5435dbc904042d1e39a1bf0c24a1ccdf995dc2c..ab5c0af5d9bd21ce9d276a00db35095fba21ac97 100644
--- a/services/crates/crates-downloads.service.js
+++ b/services/crates/crates-downloads.service.js
@@ -73,7 +73,7 @@ export default class CratesDownloads extends BaseCratesService {
   transform({ variant, json }) {
     switch (variant) {
       case 'dv':
-        return json.crate ? json.versions[0].downloads : json.version.downloads
+        return this.constructor.getVersionObj(json).downloads
       case 'dr':
         return json.crate.recent_downloads || 0
       default:
diff --git a/services/crates/crates-downloads.tester.js b/services/crates/crates-downloads.tester.js
index 24e7d1ca7d3a6d2d7d28fc68d4650744650149d7..8bc169570e5fbbb1daa87c754a0ed2b6d75303c8 100644
--- a/services/crates/crates-downloads.tester.js
+++ b/services/crates/crates-downloads.tester.js
@@ -41,7 +41,9 @@ t.create('recent downloads (null)')
           recent_downloads: null,
           max_version: '0.2.71',
         },
-        versions: [{ downloads: 42, license: 'MIT OR Apache-2.0' }],
+        versions: [
+          { downloads: 42, license: 'MIT OR Apache-2.0', num: '0.2.71' },
+        ],
       }),
   )
   .expectBadge({ label: 'recent downloads', message: '0' })
diff --git a/services/crates/crates-license.service.js b/services/crates/crates-license.service.js
index 42bffc2b170c9a87edc0974aa429912e9f375648..9dc52e7ac022bab6445b3bc0bfbc090b931878cf 100644
--- a/services/crates/crates-license.service.js
+++ b/services/crates/crates-license.service.js
@@ -36,8 +36,8 @@ export default class CratesLicense extends BaseCratesService {
 
   static defaultBadgeData = { label: 'license', color: 'blue' }
 
-  static transform({ version, versions }) {
-    const license = version ? version.license : versions[0].license
+  static transform(response) {
+    const license = this.getVersionObj(response).license
     if (!license) {
       throw new InvalidResponse({ prettyMessage: 'invalid null license' })
     }
diff --git a/services/crates/crates-license.spec.js b/services/crates/crates-license.spec.js
index 0e9db1858d1882d6f54fab7e836801fd8dc58516..19424ab1d9615e3aa8fd048adfc06c6db49d3626 100644
--- a/services/crates/crates-license.spec.js
+++ b/services/crates/crates-license.spec.js
@@ -1,17 +1,21 @@
 import { expect } from 'chai'
-import { test, given } from 'sazerac'
 import { InvalidResponse } from '../index.js'
 import CratesLicense from './crates-license.service.js'
 
 describe('CratesLicense', function () {
-  test(CratesLicense.transform, () => {
-    given({
-      version: { num: '1.0.0', license: 'MIT' },
-      versions: [{ license: 'MIT/Apache 2.0' }],
-    }).expect({ license: 'MIT' })
-    given({
-      versions: [{ license: 'MIT/Apache 2.0' }],
-    }).expect({ license: 'MIT/Apache 2.0' })
+  it('extracts expected license given valid inputs', function () {
+    expect(
+      CratesLicense.transform({
+        version: { num: '1.0.0', license: 'MIT' },
+      }),
+    ).to.deep.equal({ license: 'MIT' })
+
+    expect(
+      CratesLicense.transform({
+        crate: { max_stable_version: '1.2.3' },
+        versions: [{ num: '1.2.3', license: 'MIT/Apache 2.0' }],
+      }),
+    ).to.deep.equal({ license: 'MIT/Apache 2.0' })
   })
 
   it('throws InvalidResponse on null license with specific version', function () {
@@ -23,7 +27,12 @@ describe('CratesLicense', function () {
   })
 
   it('throws InvalidResponse on null license with latest version', function () {
-    expect(() => CratesLicense.transform({ versions: [{ license: null }] }))
+    expect(() =>
+      CratesLicense.transform({
+        crate: { max_stable_version: '1.2.3' },
+        versions: [{ num: '1.2.3', license: null }],
+      }),
+    )
       .to.throw(InvalidResponse)
       .with.property('prettyMessage', 'invalid null license')
   })
diff --git a/services/crates/crates-msrv.service.js b/services/crates/crates-msrv.service.js
index 569745e55770a190ec2386554e7743192d6a83bd..415770f1974d9660eff83b387fd20fa1d6017774 100644
--- a/services/crates/crates-msrv.service.js
+++ b/services/crates/crates-msrv.service.js
@@ -51,8 +51,8 @@ export default class CratesMSRV extends BaseCratesService {
 
   static defaultBadgeData = { label: 'msrv', color: 'blue' }
 
-  static transform({ version, versions }) {
-    const msrv = version ? version.rust_version : versions[0].rust_version
+  static transform(response) {
+    const msrv = this.getVersionObj(response).rust_version
     if (!msrv) {
       throw new NotFound({ prettyMessage: 'unknown' })
     }
diff --git a/services/crates/crates-version.service.js b/services/crates/crates-version.service.js
index fd85174d987467aa199f2bf30f2865493503bfae..a618404f04dd44afb616bd61149fe413996b40d7 100644
--- a/services/crates/crates-version.service.js
+++ b/services/crates/crates-version.service.js
@@ -19,15 +19,9 @@ export default class CratesVersion extends BaseCratesService {
     },
   }
 
-  transform(json) {
-    return json.crate.max_stable_version
-      ? json.crate.max_stable_version
-      : json.crate.max_version
-  }
-
   async handle({ crate }) {
     const json = await this.fetch({ crate })
-    const version = this.transform(json)
+    const version = this.constructor.getLatestVersion(json)
     return renderVersionBadge({ version })
   }
 }
diff --git a/services/crates/crates-version.spec.js b/services/crates/crates-version.spec.js
deleted file mode 100644
index f4d00f2d3dad9744f18fb68ae7f2830c817f91bd..0000000000000000000000000000000000000000
--- a/services/crates/crates-version.spec.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { test, given } from 'sazerac'
-import CratesVersion from './crates-version.service.js'
-
-describe('CratesVersion', function () {
-  test(CratesVersion.prototype.transform, () => {
-    given({ crate: { max_version: '1.1.0' } }).expect('1.1.0')
-    given({
-      crate: { max_stable_version: '1.1.0', max_version: '1.9.0-alpha' },
-    }).expect('1.1.0')
-  })
-})