15 Prompts for Code Migration: Python 2→3, JS→TS, REST→GraphQL

15 Prompts for Code Migration: Python 2→3, JS→TS, REST→GraphQL

Migrating code between language versions or API paradigms is one of the most delicate tasks in software engineering. A single overlooked edge case can break production. To reduce risk and speed up the process, many teams now use AI-assisted prompts. This article presents 15 curated prompts for three common migration scenarios: Python 2 to Python 3, JavaScript to TypeScript, and REST to GraphQL.

Each prompt is a complete, copy-paste-ready instruction you can give to a code-generation AI (like GPT-4 or Claude). I include a real-world example, the AI's output, and a short explanation of why it works.

Python 2 → 3 Migration (Prompts 1–5)

1. Migrate print statement to print function

Task: Convert all print statements to print() function calls.

Prompt: "Refactor this Python 2 script to Python 3. Replace all print statements with print() function calls. Keep the output behavior identical. Here is the code:

print "Hello, world"
print "The answer is", 42
```"

**Example result:**
```python
print("Hello, world")
print("The answer is", 42)

Why it works: Python 3 made print a function. The AI preserves the comma-separated arguments and adds parentheses, maintaining the same spacing and multiple-value output.

2. Update exception handling syntax

Task: Change except Exception, e to except Exception as e.

Prompt: "Update this Python 2 exception handling block to Python 3 syntax. Use as instead of comma. Code:

try:
    result = 1 / 0
except ZeroDivisionError, e:
    print "Error:", e
```"

**Example result:**
```python
try:
    result = 1 / 0
except ZeroDivisionError as e:
    print("Error:", e)

Why it works: Python 3 removed the comma syntax; as is the only valid form. The AI also converts the print statement as a bonus.

3. Replace xrange with range

Task: Replace xrange with range (which in Python 3 behaves like xrange).

Prompt: "Convert this Python 2 code to Python 3. Replace xrange with range. Also ensure that any list conversions are explicit if needed. Code:

for i in xrange(10):
    print i
```"

**Example result:**
```python
for i in range(10):
    print(i)

Why it works: range in Python 3 is lazy (like xrange in Python 2). No extra changes needed unless you explicitly need a list, in which case you'd use list(range(...)).

4. Fix integer division

Task: Change floor division to true division where appropriate.

Prompt: "Migrate this Python 2 code to Python 3. Change integer division to true division (/) and use // for floor division explicitly. Code:

a = 5 / 2
print a
```"

**Example result:**
```python
a = 5 / 2
print(a)  # 2.5 in Python 3

Why it works: Python 2's / does floor division on integers; Python 3 returns a float. The prompt tells the AI to keep // for floor, avoiding silent data changes.

5. Migrate unicode handling

Task: Remove u prefix from strings and use str instead of unicode.

Prompt: "Convert this Python 2 code to Python 3. Remove u prefixes from string literals. Replace unicode() with str(). Code:

s = u"hello"
print type(s)
```"

**Example result:**
```python
s = "hello"
print(type(s))  # <class 'str'>

Why it works: Python 3 strings are Unicode by default. The u prefix is ignored but kept for clarity; the AI removes it here for clean code.

JavaScript → TypeScript Migration (Prompts 6–10)

6. Add type annotations to function parameters

Task: Infer and add TypeScript types to function parameters.

Prompt: "Convert this JavaScript function to TypeScript. Add type annotations for all parameters and return type. Infer types from usage. Code:

function add(a, b) {
    return a + b;
}
```"

**Example result:**
```typescript
function add(a: number, b: number): number {
    return a + b;
}

Why it works: The AI assumes numeric addition. If the function used concatenation, it might infer string. Always review inferred types.

7. Define interfaces for objects

Task: Create TypeScript interfaces from JavaScript object patterns.

Prompt: "Given this JavaScript object, create a TypeScript interface and use it. Code:

const user = {
    name: "Alice",
    age: 30,
    email: "alice@example.com"
};
```"

**Example result:**
```typescript
interface User {
    name: string;
    age: number;
    email: string;
}

const user: User = {
    name: "Alice",
    age: 30,
    email: "alice@example.com"
};

Why it works: The AI infers the property types from the values. This catches typos and missing fields at compile time.

8. Convert class with JSDoc to TypeScript

Task: Migrate a JSDoc-annotated class to TypeScript with proper types.

Prompt: "Convert this JavaScript class with JSDoc to TypeScript. Replace JSDoc with TypeScript syntax. Code:

/** @param {string} name */
class Person {
    constructor(name) {
        this.name = name;
    }
    greet() {
        return "Hello, " + this.name;
    }
}
```"

**Example result:**
```typescript
class Person {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
    greet(): string {
        return "Hello, " + this.name;
    }
}

Why it works: JSDoc types are often incomplete; TypeScript enforces stricter checks. The AI converts the doc comment into actual syntax.

9. Add strict null checks

Task: Use null and undefined types explicitly.

Prompt: "Refactor this JavaScript to TypeScript with strict null checks enabled. Add `

| nullor| undefined` where needed. Code:

function getLength(str) {
    if (str == null) {
        return -1;
    }
    return str.length;
}
```"

**Example result:**
```typescript
function getLength(str: string | null): number {
    if (str == null) {
        return -1;
    }
    return str.length;
}

Why it works: Without strictNullChecks, null is assignable to any type. The prompt forces explicit union types.

10. Convert async/await to typed promises

Task: Add TypeScript types to async functions and Promises.

Prompt: "Convert this JavaScript async function to TypeScript. Add return type and resolve type. Code:

async function fetchData(url) {
    const response = await fetch(url);
    return response.json();
}
```"

**Example result:**
```typescript
async function fetchData(url: string): Promise<any> {
    const response = await fetch(url);
    return response.json();
}

Why it works: The AI adds Promise<any> as a generic return. For production, you'd replace any with a specific interface.

REST → GraphQL Migration (Prompts 11–15)

11. Define a GraphQL schema from REST endpoints

Task: Generate a GraphQL schema based on a REST API response.

Prompt: "Given this REST API response, create a GraphQL schema with types and a query. Response:

{
    "id": 1,
    "title": "Hello",
    "body": "World"
}
```"

**Example result:**
```graphql
type Post {
  id: ID!
  title: String!
  body: String!
}

type Query {
  post(id: ID!): Post
}

Why it works: The AI maps JSON fields to GraphQL scalar types. ! marks non-null fields.

12. Create a resolver that calls a REST API

Task: Write a GraphQL resolver that fetches data from an existing REST endpoint.

Prompt: "Write a GraphQL resolver for the post query that calls a REST API at https://jsonplaceholder.typicode.com/posts/:id. Use fetch."

Example result:

const resolvers = {
  Query: {
    post: async (_, { id }) => {
      const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
      return response.json();
    },
  },
};

Why it works: The resolver acts as a thin wrapper over the REST API. This pattern is common in incremental migrations.

13. Batch multiple REST calls into one GraphQL query

Task: Combine several REST endpoints into a single GraphQL query.

Prompt: "Create a GraphQL schema and resolver that returns a user and their posts in one query. REST endpoints: /users/:id returns {id, name} and /users/:id/posts returns [{id, title}]."

Example result:

type User {
  id: ID!
  name: String!
  posts: [Post]
}

type Post {
  id: ID!
  title: String!
}

type Query {
  user(id: ID!): User
}

Why it works: GraphQL allows nested queries, reducing multiple REST round trips to one.

14. Handle errors in GraphQL resolvers

Task: Add error handling and custom error types.

Prompt: "Extend this resolver to throw a GraphQL error if the REST call fails. Use GraphQLError."

Example result:

import { GraphQLError } from 'graphql';

const resolvers = {
  Query: {
    post: async (_, { id }) => {
      const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
      if (!response.ok) {
        throw new GraphQLError('Post not found', { extensions: { code: 'NOT_FOUND' } });
      }
      return response.json();
    },
  },
};

Why it works: Proper error handling in GraphQL uses structured error objects, not HTTP status codes.

15. Add pagination to a GraphQL query

Task: Implement pagination for a list query.

Prompt: "Convert this REST endpoint /posts?_page=1&_limit=10 into a GraphQL query with pagination arguments page and limit. Return total count."

Example result:

type Post {
  id: ID!
  title: String!
}

type PostConnection {
  posts: [Post]
  total: Int!
}

type Query {
  posts(page: Int = 1, limit: Int = 10): PostConnection
}

Why it works: The AI adds default values and a connection type for metadata like total.

Conclusion

These 15 prompts cover the core patterns for migrating Python 2→3, JavaScript→TypeScript, and REST→GraphQL. Each prompt is designed to be a starting point — you'll need to adjust for your specific codebase, especially for edge cases and custom types. The key is to verify AI output manually: automated migration tools (like 2to3 for Python or ts-migrate for TypeScript) handle bulk changes, but AI prompts excel at context-aware transformations.

Try these prompts on your own code, and always run your test suite after migration. Happy refactoring!

← All posts

Comments