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!
Comments