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

Introduction

Code migration is one of the most tedious yet critical tasks in software engineering. Whether you're upgrading from Python 2 to 3, converting JavaScript to TypeScript, or shifting from REST to GraphQL, the process is error-prone and time-consuming. Large language models (LLMs) like GPT-4, Claude, and specialized coding assistants can dramatically reduce this effort—if you prompt them correctly. This guide provides 18 battle-tested prompts for three major migration scenarios, each with explanations and real-world examples. Based on official documentation from Python.org, TypeScript handbook, and GraphQL Foundation, these prompts are designed to produce safe, idiomatic, and maintainable code.

Section 1: Python 2 to Python 3 Migration

Python 2 officially reached end-of-life on January 1, 2020 (source: python.org/dev/peps/pep-0373/). Yet many legacy systems still run Python 2. The following prompts target common pain points.

Prompt 1: Fix Unicode Handling

Task: Convert Python 2 unicode and str types to Python 3 str/bytes.

Prompt:
"""
You are a Python migration expert. Migrate the following Python 2 code to Python 3. Focus on fixing Unicode/bytes handling: replace unicode() with str(), str() with bytes() where appropriate, and update isinstance checks. Provide the migrated code and a short explanation of changes.

Python 2 code:

def process(data):
    if isinstance(data, unicode):
        return data.encode('utf-8')
    elif isinstance(data, str):
        return unicode(data, 'utf-8')

"""

Example output:

def process(data):
    if isinstance(data, str):
        return data.encode('utf-8')
    elif isinstance(data, bytes):
        return data.decode('utf-8')

Explanation: unicode becomes str, str becomes bytes, encode/decode swapped accordingly.

Prompt 2: Replace print Statement with Function

Task: Convert Python 2 print statements to Python 3 print function.

Prompt:
"""
Migrate this Python 2 code to Python 3. Replace all print statements with print() function calls. Preserve file handles, >> redirections, and trailing commas.

Python 2 code:

print "Hello"
print >> sys.stderr, "Error"
print "Item",

"""

Example output:

print("Hello")
print("Error", file=sys.stderr)
print("Item", end='')

Prompt 3: Update xrange to range

Task: Replace xrange with range and handle large iterables.

Prompt:
"""
Migrate this Python 2 code to Python 3. Replace xrange with range. If the result is used as a list, wrap it with list(). Add a comment about memory implications.

Python 2 code:

for i in xrange(1000000):
    process(i)

"""

Example output:

for i in range(1000000):  # range is lazy in Python 3
    process(i)

Prompt 4: Fix Integer Division

Task: Update / division to return float when needed.

Prompt:
"""
Migrate this Python 2 code to Python 3. Ensure integer division uses // and float division uses /. Use from __future__ import division if necessary.

Python 2 code:

def average(a, b):
    return a / b

"""

Example output:

def average(a, b):
    return a / b  # returns float in Python 3

Prompt 5: Update dict.iteritems()

Task: Replace dict.iteritems(), dict.iterkeys(), dict.itervalues().

Prompt:
"""
Migrate this Python 2 code to Python 3. Replace iteritems() with items(), iterkeys() with keys(), itervalues() with values(). For large dictionaries, suggest using six.iteritems() as a compatibility layer.

Python 2 code:

for k, v in mydict.iteritems():
    print k, v

"""

Example output:

for k, v in mydict.items():
    print(k, v)

Prompt 6: Migrate urllib

Task: Update urllib2 and urllib to urllib.request, urllib.parse.

Prompt:
"""
Migrate this Python 2 code to Python 3. Replace urllib2.urlopen with urllib.request.urlopen, urllib.urlencode with urllib.parse.urlencode.

Python 2 code:

import urllib2
response = urllib2.urlopen('http://example.com')

"""

Example output:

import urllib.request
response = urllib.request.urlopen('http://example.com')

Section 2: JavaScript to TypeScript Migration

TypeScript adoption grew by 33% among professional developers in 2025 (source: Stack Overflow Developer Survey 2025). These prompts help convert JS to typed, safe TS.

Prompt 7: Add Type Annotations to Functions

Task: Infer and add parameter and return types.

Prompt:
"""
Convert this JavaScript function to TypeScript. Add type annotations for all parameters and return type. Use interfaces or types for complex objects. Assume strict mode.

JavaScript code:

function greet(name, age) {
    return `Hello, ${name}. You are ${age} years old.`;
}

"""

Example output:

function greet(name: string, age: number): string {
    return `Hello, ${name}. You are ${age} years old.`;
}

Prompt 8: Convert Object to Interface

Task: Extract shape from object literal into interface.

Prompt:
"""
Convert this JavaScript object usage to TypeScript. Define an interface for the user object. Use optional properties where appropriate.

JavaScript code:

function createUser(name, email) {
    return { name: name, email: email, isAdmin: false };
}

"""

Example output:

interface User {
    name: string;
    email: string;
    isAdmin?: boolean;
}

function createUser(name: string, email: string): User {
    return { name, email, isAdmin: false };
}

Prompt 9: Handle any to Proper Types

Task: Replace any with union types or generics.

Prompt:
"""
Convert this TypeScript code that uses any to use proper types. Use union types or generics where appropriate.

TypeScript code:

function getLength(input: any): number {
    return input.length;
}

"""

Example output:

function getLength(input: string | any[]): number {
    return input.length;
}

Prompt 10: Add Null Checks

Task: Use strict null checks with ? and !.

Prompt:
"""
Convert this JavaScript code to TypeScript with strict null checks enabled. Use optional chaining (?.) and non-null assertion (!) where appropriate.

JavaScript code:

function getFirstName(user) {
    return user.profile.name.first;
}

"""

Example output:

interface User {
    profile?: {
        name?: { first?: string };
    };
}

function getFirstName(user: User): string | undefined {
    return user?.profile?.name?.first;
}

Prompt 11: Convert Class with Inheritance

Task: Migrate ES6 class to TypeScript with access modifiers.

Prompt:
"""
Convert this JavaScript class to TypeScript. Add public, private, protected modifiers. Use parameter properties.

JavaScript code:

class Animal {
    constructor(name) {
        this.name = name;
    }
    speak() {
        console.log(this.name + ' makes a noise.');
    }
}

"""

Example output:

class Animal {
    constructor(public name: string) {}
    speak(): void {
        console.log(`${this.name} makes a noise.`);
    }
}

Prompt 12: Migrate Callbacks to Promises with Types

Task: Convert callback pattern to typed async/await.

Prompt:
"""
Convert this JavaScript callback-based function to TypeScript with async/await. Define a proper Promise return type.

JavaScript code:

function fetchData(callback) {
    setTimeout(() => {
        callback(null, { id: 1, name: 'Item' });
    }, 1000);
}

"""

Example output:

interface Data {
    id: number;
    name: string;
}

function fetchData(): Promise<Data> {
    return new Promise((resolve) => {
        setTimeout(() => resolve({ id: 1, name: 'Item' }), 1000);
    });
}

Section 3: REST to GraphQL Migration

GraphQL is used by 47% of developers in production (source: State of JS 2025). Moving from REST requires rethinking data fetching.

Prompt 13: Convert REST Endpoint to GraphQL Query

Task: Transform a REST GET endpoint into a GraphQL query.

Prompt:
"""
Convert this REST endpoint to a GraphQL query. Define the schema type, query resolver, and a sample query. Use Apollo Server style.

REST endpoint:

GET /api/users/:id
Response: { "id": 1, "name": "Alice", "email": "alice@example.com" }

"""

Example output:

type User {
    id: ID!
    name: String!
    email: String!
}

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

Prompt 14: Merge Multiple REST Calls into One GraphQL Query

Task: Combine two REST endpoints into a single query.

Prompt:
"""
Create a GraphQL schema and resolver that combines these two REST endpoints into one query. Use DataLoader for batching.

REST endpoints:

GET /api/users/:id → { id, name, email }
GET /api/users/:id/posts → [ { id, title } ]

"""

Example output:

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

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

type Query {
    userWithPosts(id: ID!): UserWithPosts
}

Prompt 15: Add Mutations for POST/PUT/DELETE

Task: Convert REST write operations to GraphQL mutations.

Prompt:
"""
Convert these REST write endpoints into GraphQL mutations. Include input types and return types.

REST endpoints:

POST /api/users body: { name, email } → 201 { id, name, email }
DELETE /api/users/:id → 204

"""

Example output:

input CreateUserInput {
    name: String!
    email: String!
}

type Mutation {
    createUser(input: CreateUserInput!): User!
    deleteUser(id: ID!): Boolean!
}

Prompt 16: Handle Pagination (REST offset/limit to GraphQL connection)

Task: Convert REST pagination to Relay-style connection.

Prompt:
"""
Convert this REST paginated endpoint to a GraphQL connection type following Relay spec. Include edges, pageInfo, and totalCount.

REST endpoint:

GET /api/users?offset=0&limit=10 → { items: [...], total: 100 }

"""

Example output:

type UserConnection {
    edges: [UserEdge!]!
    pageInfo: PageInfo!
    totalCount: Int!
}

type UserEdge {
    node: User!
    cursor: String!
}

type PageInfo {
    hasNextPage: Boolean!
    hasPreviousPage: Boolean!
}

Prompt 17: Add Error Handling (REST status codes to GraphQL errors)

Task: Map REST errors to GraphQL error types.

Prompt:
"""
Create a GraphQL schema that handles errors like REST status codes. Use a union type or custom error type. Include resolver logic for common statuses (400, 404, 500).

REST errors:

404  UserNotFound
400  ValidationError
500  InternalError

"""

Example output:

type UserNotFound implements Error {
    message: String!
    userId: ID!
}

type ValidationError implements Error {
    message: String!
    field: String!
}

union UserResult = User

| UserNotFound | ValidationError

Prompt 18: Migrate Authentication from REST Headers to GraphQL Context

Task: Move token-based auth from REST headers to GraphQL context.

Prompt:
"""
Convert this REST authentication pattern to GraphQL using context. Show how to extract the token from the Authorization header in Apollo Server's context function.

REST pattern:

Authorization: Bearer <token>
Middleware extracts user from token and attaches to request.

"""

Example output:

const server = new ApolloServer({
    context: ({ req }) => {
        const token = req.headers.authorization?.split(' ')[1];
        const user = token ? verifyToken(token) : null;
        return { user };
    },
    resolvers: {
        Query: {
            me: (_, __, { user }) => {
                if (!user) throw new AuthenticationError('Not authenticated');
                return user;
            },
        },
    },
});

Conclusion

Code migration doesn't have to be a nightmare. With the right prompts, you can automate the bulk of the work—from fixing Python 2's Unicode mess to adding TypeScript types or crafting GraphQL schemas. The 18 prompts above are ready to copy-paste into your favorite LLM tool. Start with one migration scenario, test the output, and iterate. For complex projects, always review the generated code manually and use linters (like pylint for Python 3, tsc --strict for TypeScript). Migrate smart, not hard.

← All posts

Comments